Accessing COM Interface with JNA

[亡魂溺海] 提交于 2020-05-15 08:01:26

问题


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

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
]

and the GUID of the concrete class that implements the interface

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

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{


}

and in Main

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();
}

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.

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?


回答1:


TL;DR

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.

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));
    }
}

And then in 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();
}

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);


来源:https://stackoverflow.com/questions/44016328/accessing-com-interface-with-jna

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!