Problem mit SetMouseHook
-
@CUser1 sagte in Problem mit SetMouseHook:
CallNextHookEx
@CUser1 Lerne englisch!
Siehe https://docs.microsoft.com/en-us/windows/win32/winmsg/messages-and-message-queuesDie MessageQueue ist nur so voll wie Nachrichten "nicht" abgeholt werden.
Wenn eine Nachricht abgeholt wird, wird Sie aus der Queue entfernt. Eine Messagequeue ist vergleichsweise klein.Die MessageQueue liegt im aktuellen Prozess. Jeder Thread kann eine eigene haben. Wird aber GetMessafe/PeekMessage nicht verwendet und kein Fenster erzeugt gibt es auch keine MessaageQueue.
Die meisten Nachrichten werden auch nicht in der MessageQueue abgelegt. Die mneisten Nachrichten werden direkt ausgeführt/gesendet per SendMessage.
In der MessageQueue landen typischerweise rohe Tastatur- und Mausnachrichten.
Nachrichten aus anderen Threads. etc. Und natürlich Nachrichten die mit PostMessage abgesendet werden. Bestimmte Nachrichten sind nie in der Messagequeue (WM_TIMER, WM_PAINT) werden aber durch Nutzung der Queue erzeugt.
-
@Martin-Richter sagte in Problem mit SetMouseHook:
@CUser1 sagte in Problem mit SetMouseHook:
CallNextHookEx
@CUser1 Lerne englisch!
Ruf die nächste Ex von cpt. Hook an
-
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:
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 endlichBeginPaint
/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 inSendMessage
hängt) irgendwann malPeekMessage
/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 ruftSendMessage
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 auchGetMessage
/PeekMessage
im "Ziel-Thread" direkt die WndProc aufruft. Aber der "Ziel-Thread" muss auf jeden Fall erstmal eine "Message-Processing" Funktion aufrufen (alsoGetMessage
,PeekMessage
und noch ein paar andere).
-
@hustbaer Ja es ergibt eh alles Sinn wenn man mit den Begriffen "schlagartig unterbrechen" oder "direkt" konform umgeht.
-
@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.