使用JNA实现IContextMenu COM接口

问题描述

我需要Windows资源管理器命令行管理程序中的所有项目。我正在用jna实现IShellFolder COM对象接口。但是现在我在实现用于查询上下文菜单的接口IContextMenu时遇到问题。当我调用QueryContextMenu函数时,HResult的结果像真实的一样为0,但是当我调用函数GetMenuItemCount时,HMenu为空,结果为0。

那么你能告诉我我哪里有错误。非常感谢。

这是我的IContextMenu代码

public interface IContextMenu {
Guid.IID IID_IContextMenu = new Guid.IID("{000214E4-0000-0000-C000-000000000046}");

WinNT.HRESULT QueryContextMenu(WinDef.HMENU hMenu,int indexMenu,int idCmdFirst,int idCmdLast,int uFlags);
WinNT.HRESULT InvokeCommand(Pointer pici);
WinNT.HRESULT GetCommandString(IntByReference idCmd,int uType,IntByReference pReserved,WTypes.LPSTR pszName,int cchMax);

public static class Converter {
    public Converter() {
    }

    public static IContextMenu PointerToIContextMenu(PointerByReference ptr) {
        final Pointer interfacePointer = ptr.getValue();
        final Pointer vTablePointer = interfacePointer.getPointer(0);
        final Pointer[] vTable = new Pointer[3];
        vTablePointer.read(0,vTable,3);

        return new IContextMenu() {
            @Override
            public WinNT.HRESULT QueryContextMenu(WinDef.HMENU hMenu,int uFlags) {
                Function f = Function.getFunction(vTable[2],Function.ALT_CONVENTION);
                return new WinNT.HRESULT(f.invokeInt(new Object[] { interfacePointer,hMenu.getPointer(),indexMenu,idCmdFirst,idCmdLast,uFlags }));
            }

            @Override
            public WinNT.HRESULT InvokeCommand(Pointer pici) {
                Function f = Function.getFunction(vTable[1],Function.ALT_CONVENTION);
                return new WinNT.HRESULT(f.invokeInt(new Object[]{ interfacePointer,pici }));
            }

            @Override
            public WinNT.HRESULT GetCommandString(IntByReference idCmd,int cchMax) {
                Function f = Function.getFunction(vTable[0],idCmd,uType,pReserved,pszName,cchMax }));
            }
        };
    }
}

}

这是我调用QueryContextMenu的代码

IContextMenu contextMenu = null;
PointerByReference contextMenuPtr = new PointerByReference();
Pointer ppidlsPointer = new Memory(Native.POINTER_SIZE * ppidls.length);
ppidlsPointer.setPointer(0,ppidls[0].getValue());
hResult = psfParentFolder.GetUIObjectOf(null,1,ppidls[0].getPointer(),new Guid.REFIID(IContextMenu.IID_IContextMenu),new IntByReference(0),contextMenuPtr);
if (!COMUtils.SUCCEEDED(hResult))
   return false;

/* End Section */

/* Begin Get Context Menu Section */

contextMenu = IContextMenu.Converter.PointerToIContextMenu(contextMenuPtr);
WinDef.HMENU hMenu = User32Ex.INSTANCE.CreatePopupMenu();
hResult = contextMenu.QueryContextMenu(hMenu,30,0x00000004);
if (!COMUtils.SUCCEEDED(hResult)) {
   int error = Native.getLastError();
   return false;
}

int count = User32Ex.INSTANCE.GetMenuItemCount(hMenu.getPointer());
if (count > 0) {
}

/* End Section */

解决方法

您可能没有从IContextMenuVtbl中读取您的想法。此代码表明您仅收集3个函数指针:

final Pointer[] vTable = new Pointer[3];
vTablePointer.read(0,vTable,3);

但是,此接口(与大多数COM接口一样)扩展了IUnknown,因此自动在索引0处获取方法QueryInterface,在索引1处获取方法AddRef,在索引1处获取方法Release索引2。这就是您似乎正在调用的三个方法,尽管参数错误。

the header file开始,指针索引继续:

  • 3:QueryContextMenu
  • 4:InvokeCommand
  • 5:GetCommandString

您可以全部读入6个函数指针并引用最后3个指针,或者尝试使用现有编号(以相反的顺序)以3个指针的偏移量进行读取

我相信您还应该在界面定义中添加extends IUnknown