我可以通过 JNA 从 Java 使用 COM 吗?

发布于 2024-10-31 19:03:40 字数 2139 浏览 1 评论 0原文

也许我疯了,但我开始对这个想法感兴趣,即使它只是为了学习体验:我尝试通过 JNA。根据 COM 规范,COM 接口指针只是一个指向函数指针数组的指针。我想既然 JNA 允许调用函数指针,如果我可以获得 VMT(函数指针数组),我应该能够调用 COM 接口方法。

这是我的 IUnknown 接口:

@IId("00000000-0000-0000-C000-000000000046")
public interface IUnknown {
    int QueryInterface(Guid riid, PointerByReference ppvObject);
    int AddRef();
    int Release();
}

这里有一些在给定 CLSID 的情况下创建 IUnkown 接口的代码:

public static IUnknown createInstance(Guid clsId) {
    IId iidA = IUnknown.class.getAnnotation(IId.class);
    if (iidA == null)
        throw new IllegalArgumentException("Interface needs to be annotated with an IId");
    Guid iId = new Guid(iidA.value());
    Ole32 ole32 = WindowsJna.OLE32.get();
    PointerByReference p = new PointerByReference();
    int res = ole32.CoCreateInstance(clsId, null, Ole32.CLSCTX_INPROC, iId, p);
    if (res != Ole32.S_OK)
        throw new WinApiException(res);
    final Pointer interfacePointer = p.getValue();
    final Pointer vTablePointer = interfacePointer.getPointer(0);
    final Pointer[] vTable = new Pointer[3];
    vTablePointer.read(0, vTable, 0, 3);
    return new IUnknown() {
        public int QueryInterface(Guid riid, PointerByReference ppvObject) {
            Function f = Function.getFunction(vTable[0], Function.ALT_CONVENTION);
            return f.invokeInt(new Object[] { interfacePointer, riid, ppvObject });
        }
        public int AddRef() {
            Function f = Function.getFunction(vTable[1], Function.ALT_CONVENTION);
            return f.invokeInt(new Object[] { interfacePointer });
        }
        public int Release() {
            Function f = Function.getFunction(vTable[2], Function.ALT_CONVENTION);
            return f.invokeInt(new Object[] { interfacePointer });
        }
    };
}

我对 JNA 仍然有点陌生,所以我想知道代码是否有意义?还无法让它工作,因为在调用此代码之前我陷入了其他一些愚蠢的错误。

这种执行 COM 的方法是否会太慢,或者它实际上会成为一种从 Java 执行此操作的可行方法,特别是如果将一些 Java 动态代理与 COM 的 IDispatch 一起投入使用的话?

我了解 JACOB 和 Java 中的其他 COM 库,并且我已经使用过它们。就像我提到的,只是尝试一些新的东西来获得学习体验。

Perhaps I'm crazy, but I'm starting to have fun with this idea even if it is just for the learning experience: I'm trying to use COM from Java by calling the Ole32.dll functions via JNA. According to the COM spec a COM interface pointer is just a pointer to a pointer that points to an array of function pointers. I thought since JNA allows to call function pointers I should be able to call COM interface methods if I can get the VMT (the array of function pointers).

Here is my IUnknown interface:

@IId("00000000-0000-0000-C000-000000000046")
public interface IUnknown {
    int QueryInterface(Guid riid, PointerByReference ppvObject);
    int AddRef();
    int Release();
}

And here is a bit of code to create an IUnkown interface, given a CLSID:

public static IUnknown createInstance(Guid clsId) {
    IId iidA = IUnknown.class.getAnnotation(IId.class);
    if (iidA == null)
        throw new IllegalArgumentException("Interface needs to be annotated with an IId");
    Guid iId = new Guid(iidA.value());
    Ole32 ole32 = WindowsJna.OLE32.get();
    PointerByReference p = new PointerByReference();
    int res = ole32.CoCreateInstance(clsId, null, Ole32.CLSCTX_INPROC, iId, p);
    if (res != Ole32.S_OK)
        throw new WinApiException(res);
    final Pointer interfacePointer = p.getValue();
    final Pointer vTablePointer = interfacePointer.getPointer(0);
    final Pointer[] vTable = new Pointer[3];
    vTablePointer.read(0, vTable, 0, 3);
    return new IUnknown() {
        public int QueryInterface(Guid riid, PointerByReference ppvObject) {
            Function f = Function.getFunction(vTable[0], Function.ALT_CONVENTION);
            return f.invokeInt(new Object[] { interfacePointer, riid, ppvObject });
        }
        public int AddRef() {
            Function f = Function.getFunction(vTable[1], Function.ALT_CONVENTION);
            return f.invokeInt(new Object[] { interfacePointer });
        }
        public int Release() {
            Function f = Function.getFunction(vTable[2], Function.ALT_CONVENTION);
            return f.invokeInt(new Object[] { interfacePointer });
        }
    };
}

I'm still a bit new to JNA, so I would like to know if the code makes sense? Couln't get it to work yet cause I'm stuck at a some other silly error before this code gets invoked.

Will this way of doing COM be too slow or could it actually become a feasible way of doing it from Java, especially if one throw in some Java Dynamic Proxies along with COM's IDispatch?

I know about JACOB and the other COM libraries from Java and I've used them. Just trying something new for, like I mentioned, the learning experience.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

疧_╮線 2024-11-07 19:03:40

鉴于本机 COM 全部基于 C(而不是 C++)构建,因此如果本机代码使用 C 或 stdcall 调用约定,这在技术上将起作用。 JNA 为您提供了使用本机内存并为函数调用设置堆栈所需的所有工具。

但最终,您希望得到一些可以解析类型库并生成您实际需要的接口的东西,我相信这就是 JACOB 和 com4j 所做的。

编辑

JNA 现在提供相当全面的 COM 支持,包括类型库的读取和事件回调。

Given that native COM is all built on C (not C++), this will technically work if the native code is using either C or stdcall calling conventions. JNA gives you all the tools you need to futz with the native memory and set up the stack for a function call.

Ultimately, though, you'd want to wind up with something that can parse a typelib and generate the interfaces you'll actually need, which I believe is what JACOB and com4j do.

EDIT

JNA now provides fairly comprehensive COM support, including reading of type libraries and event callbacks.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文