使用JNA实现IContextMenu COM接口
Implementation of IContextMenu COM interface using JNA
我需要 Windows 资源管理器 Shell 菜单中的所有项目。我正在使用 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, 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 }));
}
};
}
}
}
这是我调用 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 */
您可能没有阅读您对 IContextMenuVtbl
的看法。此代码表示您仅收集 3 个函数指针:
final Pointer[] vTable = new Pointer[3];
vTablePointer.read(0, vTable, 0, 3);
但是,此接口(与大多数 COM 接口一样)扩展了 IUnknown
,因此自动获取索引 0 处的方法 QueryInterface
、索引 1 处的 AddRef
和 Release
在索引 2 处。所以这些是您似乎正在调用的三个方法,尽管参数错误。
从the header file开始,指针索引继续:
- 3:
QueryContextMenu
- 4:
InvokeCommand
- 5:
GetCommandString
您可以读入所有 6 个函数指针并引用最后 3 个,或者尝试使用现有编号在 3 个指针的偏移处读取(但顺序相反!)
我认为您还应该在接口定义中添加一个 extends IUnknown
。
我需要 Windows 资源管理器 Shell 菜单中的所有项目。我正在使用 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, 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 }));
}
};
}
}
}
这是我调用 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 */
您可能没有阅读您对 IContextMenuVtbl
的看法。此代码表示您仅收集 3 个函数指针:
final Pointer[] vTable = new Pointer[3];
vTablePointer.read(0, vTable, 0, 3);
但是,此接口(与大多数 COM 接口一样)扩展了 IUnknown
,因此自动获取索引 0 处的方法 QueryInterface
、索引 1 处的 AddRef
和 Release
在索引 2 处。所以这些是您似乎正在调用的三个方法,尽管参数错误。
从the header file开始,指针索引继续:
- 3:
QueryContextMenu
- 4:
InvokeCommand
- 5:
GetCommandString
您可以读入所有 6 个函数指针并引用最后 3 个,或者尝试使用现有编号在 3 个指针的偏移处读取(但顺序相反!)
我认为您还应该在接口定义中添加一个 extends IUnknown
。