Implementierung der IContextMenu COM-Schnittstelle mit JNA

Aug 25 2020

Ich benötige alle Elemente aus dem Windows Explorer-Shell-Menü. Ich implementiere mit jna die IShellFolder COM-Objektschnittstelle. Aber jetzt habe ich ein Problem mit der Implementierung der Schnittstelle IContextMenu zum Abfragen des Kontextmenüs. Wenn ich die QueryContextMenu-Funktion aufrufe, ist das Ergebnis von HResult 0 wie true, aber das HMenu war leer, wenn ich die Funktion GetMenuItemCount aufrufe, und das Ergebnis ist 0.

Kannst du mir also sagen, wo ich einen Fehler habe? Vielen Dank.

Dies ist mein Code für 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 }));
            }
        };
    }
}

}}

Und dies ist mein Code zum Aufrufen des 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 */

Antworten

DanielWiddis Aug 25 2020 at 03:18

Möglicherweise lesen Sie nicht, was Sie von der denken IContextMenuVtbl. Dieser Code zeigt an, dass Sie nur 3 Funktionszeiger sammeln:

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

Diese Schnittstelle (wie die meisten COM-Schnittstellen) wird jedoch erweitert IUnknown, sodass die Methoden automatisch QueryInterfacebei Index 0, AddRefIndex 1 und ReleaseIndex 2 abgerufen werden. Dies sind also die drei Methoden, die Sie anscheinend aufrufen, obwohl sie die falschen Argumente haben.

In der Header-Datei werden die Zeigerindizes fortgesetzt:

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

Sie können entweder alle 6 Funktionszeiger einlesen und auf die letzten 3 verweisen oder versuchen, mit einem Versatz von 3 Zeigern unter Verwendung Ihrer vorhandenen Nummerierung zu lesen (jedoch in umgekehrter Reihenfolge!).

Ich glaube, Sie sollten auch eine extends IUnknownzu Ihrer Schnittstellendefinition hinzufügen .