Auf TreeView-Events einer anderen Anwendung reagieren



  • Hallo zusammen,

    ich habe seit längerem ein kleines Problem, das ich bisher noch nicht lösen konnte. Vielleicht könnt Ihr mir ja etwas auf die Sprünge helfen ...

    Hintergrund:
    Ich habe zwar genügend Programmiererfahrung, leider hatte ich bisher noch nie den Anlass mich eingehender mit der Win32-Programmierung auseinander zu setzen. Für ein kleines Programmierprojekt ist es jetzt allerdings nötig und ich freue mich eigentlich, damit mal in die Gelegenheit zu kommen dazu zu lernen. Warum schreibe ich das? Damit ihr mir nicht erklären müsst was ein struct ist, mir aber Win32-API-technische Dinge etwas behutsamer erklären solltet.

    Problem:
    Ich möchte aus einer von mir geschriebenen Anwendung gewisse Details eines Windows einer anderen Anwendung auslesen. Konkret geht es um ein TreeView und ein RichEdit Control, aber bleiben wir zunächst mal beim TreeView ... Ich würde gern auf (ich nenn es mal) OnChange-Events reagieren, soll heißen, wenn sich ein Item im Tree ändert, ein neues hinzukommt, ein bestehendes gelöscht wird, etc. möchte ich über ein Callback (oder wie auch immer) gewisse Aktionen ausführen.

    Im Internet und im MSDN hab ich bereits genügend recherchiert, aber leider noch keine vernünftige Lösung finden können. Ich bin momentan so weit, dass ich weiß, dass ein TreeView Control WM_NOTIFY Messages an sein ParentWindow schickt, wenn Events wie oben genannt auftreten. Also ist das nächste Problem ja, an diese Messages zu kommen.
    Dazu hätte ich gedacht einen WindowsHook in einer DLL zu installieren, der die Messages dieses Windows abfängt und ein entsprechendes Callback aufruft. Per Spy++ habe ich schon überprüft, dass diese WM_NOTIFY Messages definitiv gesendet werden, allerdings bekomme ich mit meinem Hook sämtliche Mouse- und Keyboardevents, Paint-Messages und so weiter, aber keine einzige WM_NOTIFY Message.

    Hier mal der grobe Rahmen meines Codes:

    HWND window = FindWindow("TMainForm", "Fenstername");
    
    // Dann durchlaufe ich die Childwindows um das TreeView zu finden per
    // EnumChildWindows(...); Im folgenden nehmen wir an, das TreeView Control
    // liegt in HWND treeViewCtrlWindow
    
    HWND treeViewParent = GetParent(treeViewCtrlWindow);
    HMODULE hookCallbackLibrary = LoadLibrary("DLLName.dll");
    FARPROC hookCallback = GetProcAddress(hookCallbackLibrary, "_wasauchimmer@12");
    HHOOK hook = SetWindowsHookEx(WH_CALLWNDPROC,
                                  (HOOKPROC)hookCallback,
                                  hookCallbackLibrary,
                                  GetWindowThreadProcessId(treeViewParent, processID));
    

    Ich habe als Hooktyp schon WH_CALLWNDPROC und WH_GETMESSAGE probiert, andere scheinen mir nicht sinnvoll zu sein. Mein HookCallback sieht vereinfacht wie folgt aus:

    DLL_EXPORT LRESULT CALLBACK wasauchimmer(int nCode, WPARAM wParam, LPARAM lParam)
    {
        MSG* message = (MSG*)lParam;
    
        switch (message->message)
        {
            case WM_PAINT:
                logMessage(message, "WM_PAINT");
                break;
    
            case WM_MOUSEMOVE:
                logMessage(message, "WM_MOUSEMOVE");
                break;
    
            case WM_NOTIFY:
                logMessage(message, "WM_NOTIFY");
                break;
    
            // ... usw. ...
    
            default:
                logMessage(message, "Unknown");
                break;
        }
    
        return CallNextHookEx(myHook, nCode, wParam, lParam);
    }
    

    Das logMessage() schreibt einfach nen paar Infos über die Message in ein Textfile. Wenn ich mir das dann nachher anschaue, wurden halt sämtliche Messages abgefangen, aber keine WM_NOTIFY Messages. Die sollten doch aber vom TreeView für alle möglichen Events an das ParentWindow verschickt werden, glaubt man zumindest der MSDN Referenz (und dem Spy++).

    Deswegen die Bitte an Euch:
    Habt ihr für mich Win32-N00B vielleicht einen Tipp? Wichtig ist mir dabei, definitiv kein Polling zu verwenden, also wirklich auf Events zu reagieren. Desweiteren möchte ich es vermeiden auf die MFC zurückgreifen zu müssen! Also reine Win32-API Funktionen.
    Sollte es vielleicht sogar eine bessere Methode geben als über Hooks daran zu kommen, bin ich natürlich gern für Vorschläge offen (aus Java bin ich z.B. sowas wie MessageHandler gewohnt). Wenn nicht, für welche TreadID (also welches Window) registriere ich dann den Hook und welchen HookTypen (WH_CALLWNDPROC, WH_GETMESSAGE, ...)? Sollte doch aber in meinem Code schon alles korrekt sein wenn ich mich nicht total irre.

    Schon mal vielen Dank im Voraus,
    liebe Grüße,
    Timo


  • Mod

    Dein Irrtum ist es, dass das Tree-Control selbst die WM_NOTIFY Nachrichten erhält. Das ist aber nicht so.
    Die WM_NOTIFY Nachrichten gehen an das Parent ⚠
    Wenn Du also WM_NOTIFY Nachrichten willst musst Du das Parent subclassen!



  • Hi Martin,

    also das war mir schon klar, siehe ->

    Ich bin momentan so weit, dass ich weiß, dass ein TreeView Control WM_NOTIFY Messages an sein ParentWindow schickt, wenn Events wie oben genannt auftreten. Also ist das nächste Problem ja, an diese Messages zu kommen.

    HWND treeViewParent = GetParent(treeViewCtrlWindow);
    // ...
    HHOOK hook = SetWindowsHookEx(WH_CALLWNDPROC,
                                  (HOOKPROC)hookCallback,
                                  hookCallbackLibrary,
                                  GetWindowThreadProcessId(treeViewParent,
                                                           processID));
    

    ... wurden halt sämtliche Messages abgefangen, aber keine WM_NOTIFY Messages. Die sollten doch aber vom TreeView für alle möglichen Events an das ParentWindow verschickt werden, glaubt man zumindest ...

    Das kann es also nicht sein, das habe ich ja schon berücksichtigt. Ist denn überhaupt die generelle Vorgehensweise korrekt? Oder würde man das nicht über Hooks lösen? Und wenn doch, hast Du/hat noch einer noch eine Idee?

    Danke für die Mühe,
    Timo


  • Mod

    WH_CALLWNDPROC müsste IMHO gehen. WH_GETMESSAGE nicht, denn WM_NOTIFY Nachricten werden direkt über SendMessage ausgeliefert und landen nicht in der Queue!


Anmelden zum Antworten