GetMenuItemInfo liefert String von Items nicht



  • Walter Z schrieb:

    Um mii.wID auszulesen, muss auch das Flag MIIM_ID gesetzt werden, also:

    mii.fMask = MIIM_STRING | MIIM_ID;

    ach, das hatte ich testweise rausgenommen, danke für die Info ^^

    Walter Z schrieb:

    Nebenbei: Um Probleme mit GetMenuItemInfo() ("unerklärliches" Versagen, bisweilen sogar Access Violation) zu vermeiden, emfiehlt es sich, alle sonstigen mii-Strukturmitglieder stets auf 0 zu setzen, am besten in jedem Schleifendurchlauf.

    Denn beim Abarbeiten von mii überschreibt GetMenuItemInfo() intern unter Umständen einige der Strukturmitglieder - und versagt dann im nächsten Schleifendurchlauf, obwohl die Anwendung von sich aus eigentlich nichts an den Werten geändert hat. Zudem unterscheidet sich dieses schwierig vorhersagbare Verhalten auch noch zwischen den 9x- und den NT-basierten Windows-Versionen.

    Habe nun mit memset alles auf 0 initialisiert, aber leider funktioniert es dennoch nicht 😞



  • Bei mir funktioniert der Code, sofern:

    a) die Abbruchbedingung mii.wID < 60000 || mii.wID > 69999 so wirklich stimmt,
    b) die Größe von cBuffer1 richtig initialisiert bzw. definiert wurde.

    Allerdings habe ich den Code nur in einer Nicht-Unicode-Anwendung (mit UCHAR statt WCHAR) getestet.

    Versagt denn GetMenuString() ebenfalls?

    Walter Zorn



  • Walter Z schrieb:

    Bei mir funktioniert der Code, sofern:

    a) die Abbruchbedingung mii.wID < 60000 || mii.wID > 69999 so wirklich stimmt,
    b) die Größe von cBuffer1 richtig initialisiert bzw. definiert wurde.

    Allerdings habe ich den Code nur in einer Nicht-Unicode-Anwendung (mit UCHAR statt WCHAR) getestet.

    Versagt denn GetMenuString() ebenfalls?

    Walter Zorn

    a) hat mit dem Problem ja nichts zu tun.
    b) selbst wenn ich dwTypeData und cch auf 0 setze funktioniert es nicht wie es soll

    GetMenuString() funktioniert ebenfalls nicht.

    Hast du das mit einem (am besten dynamisch erzeugten) Menü eines anderen Programms getestet?



  • Hast du das mit einem (am besten dynamisch erzeugten) Menü eines anderen Programms getestet?

    Ja, mit einem dynamisch erzeugten Menu in einem anderen Programm (nicht einer anderen Instanz des selben Programms).

    Allerdings liefert MN_GETHMENU bei mir auch auf XP NULL zurück, weshalb ich auf GetMenu() zurückgegriffen habe.

    Hier sicherheitshalber nochmal der getestete Code. (AlertMain (Wrapper für MessageBox) und GetLastErrorString sind anwendungseigene Funktionen.)

    #ifndef MN_GETHMENU
        #define MN_GETHMENU 0x01E1
    #endif
        HWND hWnd2;
        HMENU hMenu;
    
        hWnd2 = FindWindow("MDIMAINWZMdi0.1.0.0", NULL);
        if(hWnd2 == NULL)
            AlertMain("hWnd2 ist NULL");
    
        else
        {
            //hMenu = (HMENU)SendMessage (hWnd2, MN_GETHMENU, 0, 0); // hWnd2 stimmt, hMenu stimmt
            hMenu = GetMenu (hWnd2); // hWnd2 stimmt, hMenu stimmt
    
            if(hMenu == NULL)
                AlertMain("hMenu ist NULL");
    
            else if(!IsMenu(hMenu))
                AlertMain("hMenu kein Menu");
    
            else
            {
                UCHAR cBuffer1[4096];
                UINT iCount, i;
                MENUITEMINFO mii;
    
                iCount = GetMenuItemCount (hMenu);
    
                for (i = 0; i < iCount; i++)
                {
                    memset(&mii, 0, sizeof(mii));
                    mii.cbSize = sizeof(mii);
                    mii.fMask = MIIM_STRING | MIIM_ID;
                    mii.dwTypeData = cBuffer1;  // TCHAR cBuffer1[4096]
                    mii.cch = sizeof(cBuffer1) / sizeof(UCHAR);
    
                    if (!GetMenuItemInfo (hMenu, i, TRUE, &mii))
                    {
                        if(GetLastErrorString(cBuffer1, sizeof(cBuffer1)-1))
                            AlertMain(cBuffer1);
                        else
                            AlertMain("GetMenuItemInfo() und GetLastErrorString() fehlgeschlagen");
                        continue;
                    }
    
                    // GetLastError() ist hier 0 - kein Fehler also
                    // Problem: mii.cch ist 0 und cBuffer1 wurde nicht geändert
    
                    if (mii.fType & MF_SEPARATOR || !mii.cch
                    /* || mii.wID < 60000 || mii.wID > 69999 */
                     )
                        continue;
    
                    MessageBox (0, cBuffer1, 0, 0); // nie erreicht
                }
            }
        }
    

    Walter Zorn



  • Hast du zufällig ICQ und könntest es damit probieren? Vielleicht haben die die MFC-Menüklasse überladen und die Strings sind wirklich leer?
    Dann müsste ich mich ja von meinem Prozess in den ICQ-Prozess hacken und aus dem Speicher lesen, was ich suche 😞

    GetMenu() funktioniert beim ICQ-Fenster gar nicht. Liegt vielleicht daran, dass es ein Popup-Menü ist?



  • Soweit ich weiß, kommt man sowohl mit GetMenu als auch mit MN_GETHMENU nur an Menus heran, die explizit dem Fenster (per SetMenu) bzw. der Fensterklasse zugewiesen wurden.

    Bei Popup-Menus ist das normalerweise nicht der Fall, sie haben lediglich ein bestimmtes Fenster als Parent, an das sie zwar die Menu-Kommandos senden, mit dem sie aber, soweit ich weiß, nicht direkt assoziiert sind (per Zeiger in der windowsinternen Datenstruktur für jedes Fenster).

    Ob man mit EnumChildWindows() an Popupmenus eines Fensters herankommt, habe ich nicht ausprobiert, glaube aber eher nicht, dass das funktioniert. Der Name der Menu-Fensterklasse ist übrigens "#32768", vielleicht hilft das irgendwie weiter - oder das Abfangen von WM_INITMENUPOPUP per Hooking...

    Walter Zorn



  • Walter Z schrieb:

    Der Name der Menu-Fensterklasse ist übrigens "#32768", vielleicht hilft das irgendwie weiter - oder das Abfangen von WM_INITMENUPOPUP per Hooking...

    Über die Fensterklasse komme ich bereits an das Fenster des Popup-Menüs, an das ich MN_GETHMENU sende, um den HMENU zu erhalten. Die anderen Daten, die GetMenuItemInfo liefert, sind ja auch korrekt, nur die Strings eben falsch bzw. leer 😞



  • Kann es sein, dass es sich um ein Ownerdraw-Menu handelt? Dann sollten die Flags
    MIIM_DATA | MIIM_STATE | MIIM_TYPE
    für mii.fMask
    und die Verwendung von mii.dwItemData statt mii.dwTypeData weiterhelfen.

    Problematisch wird's halt nur, wenn dwItemData auf eine Struktur mit Unterelementen statt direkt auf einen String zeigt...

    Walter Zorn



  • dwItemData wollte ich zuerst verwenden. Allerdings zeigt der Pointer ja auf einen Speicherbereich von ICQ.

    Ich muss mir mal anschauen was OwnerDraw-Menüs sind und wie ich auf den Speicher fremder Programme direkt zugreife.
    Danke so weit für deine Hilfe. Falls dir noch etwas einfällt - immer her damit 🙂



  • Allerdings zeigt der Pointer ja auf einen Speicherbereich von ICQ.

    Ups, stimmt eigentlich.

    und wie ich auf den Speicher fremder Programme direkt zugreife

    GetWindowThreadProcessId(),
    OpenProcess(),
    ReadProcessMemory()

    und dann den geschriebenen Puffer auf einen plausiblen Menustring validieren 🙂

    Walter Zorn



  • Yeah, per dwItemData und ReadProcessMemory komme ich an die IDs, die ich brauche 🙂

    Danke vielmals für deine Hilfe!


Anmelden zum Antworten