Implementación de la interfaz COM IContextMenu usando JNA
Necesito todos los elementos del Menú Shell del Explorador de Windows. Estoy implementando con jna la interfaz de objetos COM IShellFolder. Pero ahora tengo un problema con la implementación de la interfaz IContextMenu para consultar el menú contextual. Cuando invoco la función QueryContextMenu, el resultado de HResult es 0 como verdadero, pero HMenu ha estado vacío cuando invoco la función GetMenuItemCount y el resultado es 0.
Entonces, ¿puedes decirme dónde tengo un error? Muchísimas gracias.
Este es mi código para 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 }));
}
};
}
}
}
Y este es mi código para invocar 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 */
Respuestas
Es posible que no estés leyendo lo que piensas del IContextMenuVtbl. Este código indica que solo está recopilando 3 punteros de función:
final Pointer[] vTable = new Pointer[3];
vTablePointer.read(0, vTable, 0, 3);
Sin embargo, esta interfaz (como la mayoría de las interfaces COM) se extiende IUnknown, por lo que obtiene automáticamente los métodos QueryInterfaceen el índice 0, AddRefen el índice 1 y Releaseen el índice 2. Esos son los tres métodos a los que parece estar llamando, aunque con los argumentos incorrectos.
Desde el archivo de encabezado , los índices de puntero continúan:
- 3:
QueryContextMenu - 4:
InvokeCommand - 5:
GetCommandString
Puede leer los 6 punteros de función y hacer referencia a los últimos 3, o intentar leer en un desplazamiento de 3 punteros utilizando su numeración existente (¡pero en orden inverso!)
Creo que también debería agregar an extends IUnknowna la definición de su interfaz.