Problem mit SetMouseHook



  • @Martin-Richter

    Also schreibt Windows die Messages der Reihe nach in den VRAM des Prozesses wo der Thread ist der Messages verwendet, an eine Stelle wo grade Platz ist?

    Das ist ja dann so wie der Stack und Windows muss wissen wo genug Luft nach oben ist?

    Die Antwort auf meine Frage bzgl. ab wie vielen Messages der Queue "voll" ist sehe ich leider nicht? Was wenn schon 100.000 Messages warten und die schon komplett fragmentiert vorliegen im VRAM oder schon auf die Festplatte ausgelagert werden (theoretisch)?

    Was ist dann bei den nicht Queued Nachrichten? Da wird dann der Prozess bzw. alle Threads angehalten und sofort die WndProc gecalled?



  • @CUser1 sagte in Problem mit SetMouseHook:

    @Martin-Richter

    Also schreibt Windows die Messages der Reihe nach in den VRAM des Prozesses wo der Thread ist der Messages verwendet, an eine Stelle wo grade Platz ist?

    Nein. Wie genau es implementiert ist, ist aber auch gar nicht wichtig. Wichtig ist dass jeder Thread eine Message-Queue hat, und Nachrichten die an Fenster gehen, werden in die Queue des Threads eingefügt der für dieses Fenster zusändig ist.

    Das ist ja dann so wie der Stack und Windows muss wissen wo genug Luft nach oben ist?

    Nein, das funktioniert deutlich anders als ein Stack.

    Die Antwort auf meine Frage bzgl. ab wie vielen Messages der Queue "voll" ist sehe ich leider nicht?

    Siehe https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-postmessagea :

    There is a limit of 10,000 posted messages per message queue. This limit should be sufficiently large. If your application exceeds the limit, it should be redesigned to avoid consuming so many system resources. To adjust this limit, modify the following registry key.

    HKEY_LOCAL_MACHINE
       SOFTWARE
          Microsoft
             Windows NT
                CurrentVersion
                   Windows
                      USERPostMessageLimit
    

    The minimum acceptable value is 4000.


    Was wenn schon 100.000 Messages warten und die schon komplett fragmentiert vorliegen im VRAM oder schon auf die Festplatte ausgelagert werden (theoretisch)?

    Wenn das Limit erreicht ist werden neue Messages einfach verworfen.

    Was ist dann bei den nicht Queued Nachrichten? Da wird dann der Prozess bzw. alle Threads angehalten und sofort die WndProc gecalled?

    Nein, es werden gar keine Threads angehalten.

    Für "SendMessage": Wenn die Nachricht für den aktuellen Thread bestimmt ist, dann wird sie direkt bearbeitet ohne sie in die Message-Queue einzufügen. Und wenn die Nachricht für einen anderen Thread ist, dann wird sie zur "sofortigen" Ausführung vorgemerkt und die SendMessage funktion wartet dann so lange bis der andere Thread die Nachricht auch wirklich ausgeführt hat.

    Weiters gibt es dann noch Nachrichten die nie in der Queue gespeichert werden wie z.B. WM_PAINT. Statt diese in die Queue einzufügen wird bei GetMessage/PeekMessage geprüft ob die Nachricht gerade "nötig" ist, und wenn ja, wird sie einfach zurückgegeben.


    ps: Die Abkürzung VRAM wird üblicherweise für Video-RAM verwendet. Wenn du virtuellen Speicher meinst, schreib einfach "virtueller Speicher".



  • @hustbaer Was heißt dann direkt bearbeiten? Das wie du sagst bei WM_PAINT Windows das Window einfach redrawed, ohne das der Thread bzw. dessen WndProc des Fensters überhaupt etwas mitbekommt?



  • Nein, es wird direkt deine WndProc aufgerufen, ohne den Umweg über die Message Queue.



  • @Mechanics sagte in Problem mit SetMouseHook:

    Nein, es wird direkt deine WndProc aufgerufen, ohne den Umweg über die Message Queue.

    Nein 🙂
    EDIT: Bzw. "ja", da du es denke ich auf den SendMessage Teil bezogen hast. War etwas verwirrt weil @CUser1 schon falsch verstanden hat wie WM_PAINT funktioniert.

    @CUser1 sagte in Problem mit SetMouseHook:

    @hustbaer Was heißt dann direkt bearbeiten? Das wie du sagst bei WM_PAINT Windows das Window einfach redrawed, ohne das der Thread bzw. dessen WndProc des Fensters überhaupt etwas mitbekommt?

    Ebenfalls nein 🙂

    WM_PAINT wird niemals in die Queue gestellt aber es wird auch nicht direkt die WndProc aufgerufen. GetMessage tut nur einfach so als wäre ganz hinten in der Queue ein WM_PAINT gewesen wenn die Paint-Region nicht leer ist.

    Also das läuft (grob skizziert, sinngemäss) eher so:

    BOOL GetMessage(LPMSG lpMsg, HWND  hWnd, UINT  wMsgFilterMin, UINT  wMsgFilterMax) {
    start:
        if (checkMessageQueue(hWnd, wMsgFilterMin, wMsgFilterMax)) {
            // ... "Echte" Message aus der Queue holen, lpMsg befüllen etc. ...
            if (lpMsg->msg == WM_QUIT)
                return FALSE;
            else
                return TRUE;
        }
    
        if (WM_PAINT >= wMsgFilterMin && WM_PAINT <= wMsgFilterMax) {
            if (!isPaintRegionEmpty(hWnd)) {
                // Wir tun einfach so als wäre in der Queue noch eine WM_PAINT Nachricht gewesen
                lpMsg->msg = WM_PAINT;
                // ...
                return TRUE;
            }
        }
    
        // ...
    
        // Keine Message da => warten
        waitForNewMessageOrTimerOrPaintRegionChange(hWnd);
        goto start;
    }
    


  • ps: Das erklärt auch warum WM_PAINT Messages immer und immer wieder reported werden, bis man endlich BeginPaint/EndPaint aufruft.

    Die MS Doku sagt dazu

    GetMessage does not remove WM_PAINT messages from the queue. The messages remain in the queue until processed.

    Stimmt bloss nicht. Es sieht bloss so aus als ob sie nicht entfernt würden, weil sie in Wirklichkeit gar nie reinkommen sondern bei Bedarf einfach aus dem Nichts erzeugt werden.



  • @CUser1 Und zu dem Teil:

    Für "SendMessage": Wenn die Nachricht für den aktuellen Thread bestimmt ist, dann wird sie direkt bearbeitet ohne sie in die Message-Queue einzufügen.

    Damit meine ich das was @Mechanics beschrieben hat: in dem Fall wird die WndProc direkt aufgerufen.



  • @hustbaer Wenn ich es richtig verstehe dann "erzeugt" GetMessage die WM_PAINT oder WM_TIMER nicht aus dem Messagequeue sondern durch die Abfrage anderer Bedingungen, was MartinRichter mit direkt gemeint hat, weil dass nicht über den Queue läuft.

    Aber trotzdem muss man PeekMessage oder GetMessage callen weil sonst bleibt das WM_PAINT trotzdem aus.



  • @hustbaer Ja dann meint direkt aber bloß, dass sie anderen Messages "vorgezogen" wird? Und nicht wie ein Treiber der die CPU schlagartig unterbricht?



  • @CUser1 sagte in Problem mit SetMouseHook:

    @hustbaer Wenn ich es richtig verstehe dann "erzeugt" GetMessage die WM_PAINT oder WM_TIMER nicht aus dem Messagequeue sondern durch die Abfrage anderer Bedingungen, was MartinRichter mit direkt gemeint hat, weil dass nicht über den Queue läuft.

    Aber trotzdem muss man PeekMessage oder GetMessage callen weil sonst bleibt das WM_PAINT trotzdem aus.

    Ja, das hast du richtig verstanden.

    Bei SendMessage an ein Fenster des eigenen Threads läuft das aber anders. Weil warten bis der eigene Thread (der ja gerade in SendMessage hängt) irgendwann mal PeekMessage/GetMessage aufruft -- da könnte man lange warten. In dem Fall muss Windows also die WndProc direkt aufrufen.

    Und nicht wie ein Treiber der die CPU schlagartig unterbricht?

    Schlagartig unterbrochen wird dabei aber auch nichts. Dein Thread hat ja SendMessage(eigenesFenster) aufgerufen. Und in dem Fall ruft SendMessage dann einfach direkt die WndProc auf.



  • @hustbaer Wenn man SendMessage an einen anderen Thread sendet und Windows dann die WndProc aufruft dann bräuchte man ja Critical Section damit nicht Windows und der eigene Thread ggf. zugleich Werte verändern?



  • @CUser1 sagte in Problem mit SetMouseHook:

    @hustbaer Wenn man SendMessage an einen anderen Thread sendet und Windows dann die WndProc aufruft dann bräuchte man ja Critical Section damit nicht Windows und der eigene Thread ggf. zugleich Werte verändern?

    Wenn du SendMessage an ein Fenster eines anderen Threads machst, dann geht das ganz normal über die Queue. Also "fast ganz normal". Solche Messages werden bevorzugt behandelt, und ich bin mir nicht sicher ob in dem Fall nicht auch GetMessage/PeekMessage im "Ziel-Thread" direkt die WndProc aufruft. Aber der "Ziel-Thread" muss auf jeden Fall erstmal eine "Message-Processing" Funktion aufrufen (also GetMessage, PeekMessage und noch ein paar andere).



  • @hustbaer Ja es ergibt eh alles Sinn wenn man mit den Begriffen "schlagartig unterbrechen" oder "direkt" konform umgeht.


  • Mod

    @CUser1 sagte in Problem mit SetMouseHook:

    @hustbaer Wenn man SendMessage an einen anderen Thread sendet und Windows dann die WndProc aufruft dann bräuchte man ja Critical Section damit nicht Windows und der eigene Thread ggf. zugleich Werte verändern?

    Nein. Da es der eigene Thread ist, würde das sowieso nichts nutzen.
    Also:

    Wenn Du SendMessage aufrufst und ein anderer Thread ist involviert, dann blockiert Dein Thread so lange bis SendMessage zurück kommt. Punkt.

    Ein Thread wird eine Nachricht von einem anderen Thread nur entgegen nehmen, wenn Peek-,GetMessage aufgerufen wird. Und nur wenn der Thead mit return aus der WindowProc zurückkehr, läuft der sendende Thread weiter.

    Bei COM wird es spaßiger. Da kann ein externer Aufruf von einem STA Aufruf tatsächlich reentrant sein und ein eingehender COM Aufruf oder eine Nachricht kann wären einem simplen Aufruf in der eigenen Anwendung etwas verändern...



  • @Martin-Richter Das mit COM habe ich nicht verstanden?

    Bei COM erstellt man ja einen Pointer und die COM Funktion erzeugt ein Objekt und der Pointer zeigt dann dorthin oder?

    Ist das nicht wie bei FILE * f = fopen(...); da wird diese struct auch wo anders erstellt durch die mrsvc80.dll oder so?

    Verwenden die da malloc um solche aobjekte zu erzeugen?

    Oder wo werden die COM Objekte erzeugt?

    Und wo ist der Messagequeue? Hustbär sagte der ist nicht im virtuellen Speicher des Prozesses wo der Thread ist?



  • @CUser1 sagte in Problem mit SetMouseHook:

    Und wo ist der Messagequeue? Hustbär sagte der ist nicht im virtuellen Speicher des Prozesses wo der Thread ist?

    Nein, das hab ich nicht gesagt. Ich habe gesagt (geschrieben) dass diese Beschreibung falsch ist:

    Also schreibt Windows die Messages der Reihe nach in den VRAM des Prozesses wo der Thread ist der Messages verwendet, an eine Stelle wo grade Platz ist?



  • @hustbaer Und wie ist es dann?



  • @CUser1 Die genauen Details sind soweit ich weiss nicht dokumentiert.
    Ist aber auch egal, das Verhalten der Queue ist ausreichend gut dokumentiert dass man damit arbeiten kann.


Anmelden zum Antworten