使用JNA实现IContextMenu COM接口

huangapple go评论79阅读模式
英文:

Implementation of IContextMenu COM interface using JNA

问题

I need all items from Windows Explorer Shell Menu. I am implementing with jna the IShellFolder COM object interface. But now I have a problem with implementation the interface IContextMenu for query the context menu. When I invoke the QueryContextMenu function the result of HResult is 0 like true, but the HMenu has been empty when I invoke function GetMenuItemCount and the result is 0.

So can you tell me where I have a bug. Thank you very much.

This is my code for 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, 0, 3);

        return new IContextMenu() {
            @Override
            public WinNT.HRESULT QueryContextMenu(WinDef.HMENU hMenu, int indexMenu, int idCmdFirst, int idCmdLast, 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 uType, IntByReference pReserved, WTypes.LPSTR pszName, int cchMax) {
                Function f = Function.getFunction(vTable[0], Function.ALT_CONVENTION);
                return new WinNT.HRESULT(f.invokeInt(new Object[] { interfacePointer, idCmd, uType, pReserved, pszName, cchMax }));
            }
        };
    }
}
}

And this is my code to invoke the 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, 0, 1, 30, 0x00000004);
if (!COMUtils.SUCCEEDED(hResult)) {
   int error = Native.getLastError();
   return false;
}

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

/* End Section */
英文:

I need all items from Windows Explorer Shell Menu. I am implementing with jna the IShellFolder COM object interface. But now I have a problem with implementation the interface IContextMenu for query the context menu. When I invoke the QueryContextMenu function the result of HResult is 0 like true, but the HMenu has been empty when I invoke function GetMenuItemCount and the result is 0.

So can you tell me where I have a bug. Thank you very much.

This is my code for 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, 0, 3);
return new IContextMenu() {
@Override
public WinNT.HRESULT QueryContextMenu(WinDef.HMENU hMenu, int indexMenu, int idCmdFirst, int idCmdLast, 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 uType, IntByReference pReserved, WTypes.LPSTR pszName, int cchMax) {
Function f = Function.getFunction(vTable[0], Function.ALT_CONVENTION);
return new WinNT.HRESULT(f.invokeInt(new Object[] { interfacePointer, idCmd, uType, pReserved, pszName, cchMax }));
}
};
}
}

}

And this is my code to invoke the 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, 0, 1, 30, 0x00000004);
if (!COMUtils.SUCCEEDED(hResult)) {
int error = Native.getLastError();
return false;
}
int count = User32Ex.INSTANCE.GetMenuItemCount(hMenu.getPointer());
if (count > 0) {
}
/* End Section */

答案1

得分: 1

你可能没有从IContextMenuVtbl中读取你认为的内容。此代码表明您只收集了3个函数指针:

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

然而,这个接口(和大多数COM接口一样)继承自IUnknown,因此自动获取了方法:索引0处的QueryInterface,索引1处的AddRef,以及索引2处的Release。所以这似乎是你要调用的三个方法,尽管参数不正确。

头文件中可以看出,指针索引继续如下:

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

您可以选择读取所有6个函数指针并引用最后3个,或者尝试在偏移3个指针的位置使用您现有的编号(但顺序相反!)

我认为您还应该在接口定义中添加extends IUnknown

英文:

You may not be reading what you think from the IContextMenuVtbl. This code indicates you're only collecting 3 function pointers:

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

However, this interface (as most COM interfaces) extends IUnknown, so automatically gets the methods QueryInterface at index 0, AddRef at index 1, and Release at index 2. So those are the three methods you appear to be calling, although with the wrong arguments.

From the header file, the pointer indices continue:

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

You can either read in all 6 function pointers and reference the last 3, or attempt to read at an offset of 3 pointers using your existing numbering (but in reverse order!)

I believe you should also add an extends IUnknown to your interface definition.

huangapple
  • 本文由 发表于 2020年8月25日 03:53:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/63567872.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定