使用JNA访问COM接口

使用JNA访问COM接口

本文介绍了使用JNA访问COM接口的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试访问与JNA的接口,但我碰壁了。

I'm trying to access the IDesktopWallpaper interface with JNA, but I've hit a wall.

我经历了 ShOljIdl_core.idl (来自Windows 10 SDK),并发现了界面的GUID,如下所示

I went through ShOljIdl_core.idl (from Windows 10 SDK) and discovered the GUID of the interface as follows

// IDesktopWallpaper
[
    uuid(B92B56A9-8B55-4E14-9A89-0199BBB6F93B),
    object
]

以及实现该接口的具体类的GUID

and the GUID of the concrete class that implements the interface

// CLSID_DesktopWallpaper
[uuid(C2CF3110-460E-4fc1-B9D0-8A1C0C9CC4BD)] coclass DesktopWallpaper { interface IDesktopWallpaper; }

因此,我遵循了JDA github中的官方示例并编写了以下内容

So I followed the official example in the JDA github and wrote the following

@ComObject(clsId="{C2CF3110-460E-4fc1-B9D0-8A1C0C9CC4BD}")
public interface DesktopWallpaper extends IUnknown{


}

Main code>

Ole32.INSTANCE.CoInitializeEx(Pointer.NULL, Ole32.COINIT_MULTITHREADED);
try {
    Factory factory = new Factory();
    try {
        DesktopWallpaper dw = factory.createObject(DesktopWallpaper.class);
    } finally {
        factory.disposeAll();
        factory.getComThread().terminate(1 * 1000);
    }

} finally {
    Ole32.INSTANCE.CoUninitialize();
}

但是 factory.createObject(DesktopWallpaper.class) 抛出不支持这样的接口(HRESULT:80004002)(puArgErr =)我不知道如何解决这个问题或它为什么会发生。

But the factory.createObject(DesktopWallpaper.class) throws No such interface supported(HRESULT: 80004002) (puArgErr=)and I don't know how to get around this or why it is happening.

任何专家都可以启发我发生了什么事吗? (我是一个完全菜鸟),我将提供所有必要的进一步信息。 JNA可以实现我想要的功能还是必须使用Com4j等其他功能?

Can any experts enlighten me on what's happening? (I am a complete noob) I will provide any further info that's necessary. Can JNA achieve what I want or do I have to use something else like Com4j?

推荐答案

经过大量的搜索后,我终于可以使用它了。问题(至少就我目前的理解而言)是,当前的JNA帮助器只能与从 IDispatch 继承的接口一起使用。因此,如果所讨论的接口(例如 IDesktopWallpaper )没有继承自 IDispatch ,则应该使用vtable进行函数调用。我从 很棒的Google论坛帖子,其中的张贴者还提供了使我入门的代码示例。

After a lot of googling, I finally got it to work. The problem (at least to my current understanding) is that the current JNA helpers only work with interfaces that inherit from IDispatch. So if the interface in question such as IDesktopWallpaper does not inherit from IDispatch, then one should use vtable for function calls. I got this information from this amazing Google forum post in which the poster also provided a code sample that got me started.

以下是 SetWallpaper()函数的一些工作代码:

Here is some working code for the SetWallpaper() function:

public class DesktopWallpaperHandler extends Unknown{
    private static final GUID CLSID_DesktopWallpaper = new GUID("{C2CF3110-460E-4fc1-B9D0-8A1C0C9CC4BD}");
    private static final GUID IID_IDesktopWallpaper = new GUID("{B92B56A9-8B55-4E14-9A89-0199BBB6F93B}");

    private DesktopWallpaperHandler(Pointer pvInstance) {
        super(pvInstance);
    }

    public static DesktopWallpaperHandler create(){
        PointerByReference p = new PointerByReference();

        WinNT.HRESULT hr = Ole32.INSTANCE.CoCreateInstance(CLSID_DesktopWallpaper, null, WTypes.CLSCTX_SERVER, IID_IDesktopWallpaper, p);
        COMUtils.checkRC(hr);

        DesktopWallpaperHandler handler = new DesktopWallpaperHandler(p.getValue());

        return handler;
    }

    public void SetWallpaper(WTypes.LPWSTR monitor, WTypes.LPWSTR wallpaper){
        int result = this._invokeNativeInt(3, new Object[]{this.getPointer(), monitor, wallpaper});
        COMUtils.checkRC(new HRESULT(result));
    }
}

然后在 Main

Ole32.INSTANCE.CoInitializeEx(Pointer.NULL, Ole32.COINIT_MULTITHREADED);
try {
    WTypes.LPWSTR path = new LPWSTR("C:\\Users\\Harry\\Desktop\\1.jpg");
    DesktopWallpaperHandler handler = DesktopWallpaperHandler.create();
    handler.SetWallpaper(null, path);
} finally {
    Ole32.INSTANCE.CoUninitialize();
}

使用 IDesktopWallpaper 可以访问渐变效果,现在可以通过添加以下内容来实现:

The original motive to use IDesktopWallpaper was to access the fade in transition effect, and now that can be done by adding the following:

User32.INSTANCE.SendMessageTimeout(User32.INSTANCE.FindWindow("Progman", null), 0x52c, 0, 0, 0, 500, null);

这篇关于使用JNA访问COM接口的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-24 03:04