Java JNA编写win32 API的自定义COM接口(interface)

标签 java jna

我需要编写 win32 API 的自定义 IShellFolder 接口(interface)。但我在调用方法 ParseDisplayName 时遇到问题。 jna 的原始版本有一个 bug,该方法的 pszDisplayName 参数是 String,但 win32 api 的参数是 wstring。

这是我的代码

String file = "c:\\Users\\Duchon\\Downloads\\Baumüller Brno, s.r.o.PS43668.prpkg";
PointerByReference psfDesktopPTR = new PointerByReference();
WinNT.HRESULT hResult = Shell32.INSTANCE.SHGetDesktopFolder(psfDesktopPTR);
   if (COMUtils.SUCCEEDED(hResult)) {
      IntByReference pcheaten = new IntByReference();
      PointerByReference ppidl = new PointerByReference();
      IntByReference pdwAttributes = new IntByReference();
      IShellFolder psfDesktop = IShellFolder.Converter.PointerToIShellFolder(psfDesktopPTR);
      hResult = psfDesktop.ParseDisplayName(null, null, new WString(file), pcheaten, ppidl, pdwAttributes);
      if (COMUtils.SUCCEEDED(hResult)) {
      }
}

这是我的 IShellFolder 界面:

public interface IShellFolder {
   WinNT.HRESULT ParseDisplayName(WinDef.HWND hwnd, Pointer pbc, WString pszDisplayName, IntByReference pchEaten, PointerByReference ppidl, IntByReference pdwAttributes);

   public static class Converter {
      public static IShellFolder PointerToIShellFolder(final PointerByReference ptr) {
         final Pointer interfacePointer = ptr.getValue();
        final Pointer vTablePointer = interfacePointer.getPointer(0);
        final Pointer[] vTable = new Pointer[1];
        vTablePointer.read(0, vTable, 0, 1);
        return new IShellFolder() {
            @Override
            public WinNT.HRESULT ParseDisplayName(WinDef.HWND hwnd, Pointer pbc, WString pszDisplayName, IntByReference pchEaten, PointerByReference ppidl, IntByReference pdwAttributes) {
                Function f = Function.getFunction(vTable[0], Function.ALT_CONVENTION);
                return new WinNT.HRESULT(f.invokeInt(new Object[] {interfacePointer, hwnd, pbc, pszDisplayName, pchEaten, ppidl, pdwAttributes }));
            }
        };
      }
   }
}

并调用ParseDisplay方法抛出异常java.lang.Error:无效的内存访问。

当我遇到错误时你能帮助我吗?

非常感谢。

最佳答案

你就快到了。一般来说,定制现有 JNA 接口(interface)的方法是定义自己的接口(interface)并扩展它,然后编写自己的方法。对于单个方法,您基本上已完成,但 Converter 类会生成一个匿名类,您需要完全复制该类。这应该可行。

public interface MyIShellFolder extends com.sun.jna.platform.win32.COM.IShellFolder {

    // Define your own function invocation.
    // Since your argument signature includes a WString
    // it will be an overloaded version selected when you use the
    // WString argument.
    WinNT.HRESULT ParseDisplayName(WinDef.HWND hwnd, Pointer pbc, WString pszDisplayName, IntByReference pchEaten,
            PointerByReference ppidl, IntByReference pdwAttributes);

    // Do the same extending the inner class
    public static class Converter extends com.sun.jna.platform.win32.COM.IShellFolder.Converter {
        // You are overriding the superclass version of this so you have
        // to define the entire method
        public static MyIShellFolder PointerToIShellFolder(final PointerByReference ptr) {
            final Pointer interfacePointer = ptr.getValue();
            final Pointer vTablePointer = interfacePointer.getPointer(0);
            final Pointer[] vTable = new Pointer[13];
            vTablePointer.read(0, vTable, 0, 13);
            return new MyIShellFolder() {

                @Override
                public WinNT.HRESULT QueryInterface(REFIID byValue, PointerByReference pointerByReference) {
                    Function f = Function.getFunction(vTable[0], Function.ALT_CONVENTION);
                    return new WinNT.HRESULT(
                            f.invokeInt(new Object[] { interfacePointer, byValue, pointerByReference }));
                }

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

                @Override
                public WinNT.HRESULT ParseDisplayName(WinDef.HWND hwnd, Pointer pbc, WString pszDisplayName,
                        IntByReference pchEaten, PointerByReference ppidl, IntByReference pdwAttributes) {
                    Function f = Function.getFunction(vTable[3], Function.ALT_CONVENTION);
                    return new WinNT.HRESULT(f.invokeInt(new Object[] { interfacePointer, hwnd, pbc, pszDisplayName,
                            pchEaten, ppidl, pdwAttributes }));
                }

                @Override
                public WinNT.HRESULT EnumObjects(WinDef.HWND hwnd, int grfFlags, PointerByReference ppenumIDList) {
                    Function f = Function.getFunction(vTable[4], Function.ALT_CONVENTION);
                    return new WinNT.HRESULT(
                            f.invokeInt(new Object[] { interfacePointer, hwnd, grfFlags, ppenumIDList }));
                }

                public WinNT.HRESULT BindToObject(Pointer pidl, Pointer pbc, REFIID riid, PointerByReference ppv) {
                    Function f = Function.getFunction(vTable[5], Function.ALT_CONVENTION);
                    return new WinNT.HRESULT(f.invokeInt(new Object[] { interfacePointer, pidl, pbc, riid, ppv }));
                }

                @Override
                public HRESULT BindToStorage(Pointer pidl, Pointer pbc, REFIID riid, PointerByReference ppv) {
                    Function f = Function.getFunction(vTable[6], Function.ALT_CONVENTION);
                    return new WinNT.HRESULT(f.invokeInt(new Object[] { interfacePointer, pidl, pbc, riid, ppv }));
                }

                @Override
                public HRESULT CompareIDs(WinDef.LPARAM lParam, Pointer pidl1, Pointer pidl2) {
                    Function f = Function.getFunction(vTable[7], Function.ALT_CONVENTION);
                    return new WinNT.HRESULT(f.invokeInt(new Object[] { interfacePointer, lParam, pidl1, pidl2 }));
                }

                @Override
                public HRESULT CreateViewObject(WinDef.HWND hwndOwner, REFIID riid, PointerByReference ppv) {
                    Function f = Function.getFunction(vTable[8], Function.ALT_CONVENTION);
                    return new WinNT.HRESULT(f.invokeInt(new Object[] { interfacePointer, hwndOwner, riid, ppv }));
                }

                @Override
                public HRESULT GetAttributesOf(int cidl, Pointer apidl, IntByReference rgfInOut) {
                    Function f = Function.getFunction(vTable[9], Function.ALT_CONVENTION);
                    return new WinNT.HRESULT(f.invokeInt(new Object[] { interfacePointer, cidl, apidl, rgfInOut }));
                }

                @Override
                public HRESULT GetUIObjectOf(WinDef.HWND hwndOwner, int cidl, Pointer apidl, REFIID riid,
                        IntByReference rgfReserved, PointerByReference ppv) {
                    Function f = Function.getFunction(vTable[10], Function.ALT_CONVENTION);
                    return new WinNT.HRESULT(f.invokeInt(
                            new Object[] { interfacePointer, hwndOwner, cidl, apidl, riid, rgfReserved, ppv }));
                }

                public WinNT.HRESULT GetDisplayNameOf(Pointer pidl, int flags, STRRET pName) {
                    Function f = Function.getFunction(vTable[11], Function.ALT_CONVENTION);
                    return new WinNT.HRESULT(f.invokeInt(new Object[] { interfacePointer, pidl, flags, pName }));
                }

                @Override
                public HRESULT SetNameOf(WinDef.HWND hwnd, Pointer pidl, String pszName, int uFlags,
                        PointerByReference ppidlOut) {
                    Function f = Function.getFunction(vTable[12], Function.ALT_CONVENTION);
                    return new WinNT.HRESULT(
                            f.invokeInt(new Object[] { interfacePointer, hwnd, pidl, pszName, uFlags, ppidlOut }));
                }

                // OLD VERSION THAT YOU WANT TO IGNORE BUT MUST DECLARE
                @Override
                public HRESULT ParseDisplayName(HWND hwnd, Pointer pbc, String pszDisplayName, IntByReference pchEaten,
                        PointerByReference ppidl, IntByReference pdwAttributes) {
                    return null;
                }
            };
        }
    }
}

关于Java JNA编写win32 API的自定义COM接口(interface),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57493294/

相关文章:

java - Log4J fileappender 无法在 Websphere 7 上滚动

java - 将包含数据的 HTML 导出到 MS Word

java - JAVA 和 Delphi 中的数学函数给出不同的结果

java - 配置 Jetty 6 以使用 commons.dbcp 数据源

java - 如何使用JNA 查找某个进程?

java - 反转链表队列时遇到问题

java - 使用 JNA 调用 CreateFile 给出 UnsatisfiedLinkError : Error looking up function 'CreateFile' : The specified procedure could not be found

java - 使用Java + JNA调用WinInet函数

java - 返回数组的第一个结构体为空

java - JNA GetExitCodeProcess() 工作异常