JNA 调用 Win32 API 方法 IShellFolder::GetUIObjectOf

JNA call Win32 API method IShellFolder::GetUIObjectOf

我在调用此方法时遇到问题 IShellFolder::GetUIObject 我不知道如何创建指向指针数组的指针作为此函数的第三个参数。在文档中这个函数的 header 是:

HRESULT GetUIObjectOf(
  HWND                  hwndOwner,
  UINT                  cidl,
  PCUITEMID_CHILD_ARRAY apidl,
  REFIID                riid,
  UINT                  *rgfReserved,
  void                  **ppv
);

这是我的代码:

String directory = "c:\Users";
String file = "c:\Users\Duchon\Downloads\Baumüller Brno, s.r.o.PS43668.prpkg";
try {
   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();
      MyIShellFolder psfDesktop = MyIShellFolder.Converter.PointerToIShellFolder(psfDesktopPTR);
      hResult = psfDesktop.ParseDisplayName(null, null, new WString(file), pcheaten, ppidl, pdwAttributes);
      PointerByReference iContextMenuPtr = new PointerByReference();
      if (COMUtils.SUCCEEDED(hResult)) {
         Pointer[] ppidls = new Pointer[1];
         ppidls[0] = ppidl.getValue();
         hResult = psfDesktop.GetUIObjectOf(null, 1, ppidl.getValue(), new Guid.REFIID(IContextMenu.IID_IContextMenu), new IntByReference(), iContextMenuPtr);
         if (COMUtils.SUCCEEDED(hResult)) {
             // QueryIContextMenu ...
         }
      }
   }
}
catch (Exception e) {
   e.printStackTrace(System.err);
}

但是我得到无效内存访问异常。我需要一个文件数组的解决方案,而不仅仅是一个文件。非常感谢。

当您收到无效内存访问错误时,这表明您需要正确分配本机内存。您上面的代码只声明了一个 Java 端指针数组。

C 中的数组使用连续内存。这意味着您必须为数组分配一个足够大的本地内存块;收集一堆单独的分配是不够的(这就是在 Java 中声明单个 Pointer 变量所做的)。

分配本机内存块有两个主要选项:

选项 1. 使用 JNA 的 Memory class 显式分配您需要的内存大小。如果您分配一个指针数组,您将像这样分配: Memory m = new Memory(numberOfElements * Native.POINTER_SIZE); 当您将返回值放入该内存中时,您将使用偏移量从数组中提取适当的指针,例如,对于索引为 0 的 [=第 16=] 个指针,执行 Pointer p = m.getPointer(i * Native.POINTER_SIZE);

选项 2. 创建适当大小的 Structure(在本例中,包含一个指针元素)并使用 Structure.toArray() 分配结构数组。所以你可以定义:

    @FieldOrder ({"childId"})
    class PCUITEMID_CHILD extends Structure {
      public Pointer childId;
    }

然后分配数组

PCUITEM_CHILD[] pcuItemIdArray = new PCUITEMID_CHILD().toArray(numberOfElements);

然后你可以传递这个数组变量,并使用传统的数组语法访问它的结果。

Pointer p = pcuItemIdArray[0].childId;