英文:
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论