Register for your free account! | Forgot your password?

Go Back   elitepvpers > Coders Den > C/C++
You last visited: Today at 16:01

  • Please register to post and access all features, it's quick, easy and FREE!

Advertisement



WinApi - Wofür GetMessage-Loop?

Discussion on WinApi - Wofür GetMessage-Loop? within the C/C++ forum part of the Coders Den category.

Reply
 
Old   #1
 
Shadow992's Avatar
 
elite*gold: 77
Join Date: May 2008
Posts: 5,430
Received Thanks: 5,878
WinApi - Wofür GetMessage-Loop?

Hallo liebe Community,

ich versuche gerade herauszufinden, was genau bei der WinApi-GUI-Programmierung dieses Grundgerüst macht:

Code:
#include <windows.h>

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

LPCSTR lpszAppName = "AppName";
LPCSTR lpszTitle   = "Meine erste Applikation";

int APIENTRY WinMain(HINSTANCE hInstance,
           HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{

   HWND       hWnd;
   MSG        msg;
   WNDCLASSEX   wc;

   wc.cbSize        =  sizeof(WNDCLASSEX);
   wc.style         =  CS_HREDRAW | CS_VREDRAW;
   wc.lpfnWndProc   =  WndProc;
   wc.cbClsExtra    =  0;
   wc.cbWndExtra    =  0;
   wc.hInstance     =  hInstance;
   wc.hCursor       =  LoadCursor(NULL,IDC_ARROW);
   wc.hIcon         =  LoadIcon(NULL, IDI_APPLICATION);
   wc.hbrBackground =  (HBRUSH)GetStockObject(WHITE_BRUSH);
   wc.lpszClassName =  lpszAppName;
   wc.lpszMenuName  =  lpszAppName;
   wc.hIconSm       =  LoadIcon(NULL, IDI_APPLICATION);

   if( RegisterClassEx(&wc) == 0)
      return 0;

   hWnd = CreateWindowEx(NULL,
                         lpszAppName,
                         lpszTitle,
                         WS_OVERLAPPEDWINDOW,
                         0,
                         0,
                         CW_USEDEFAULT,
                         CW_USEDEFAULT,
                         NULL,
                         NULL,
                         hInstance,
                         NULL);

   if( hWnd == NULL)
      return 0;

   ShowWindow(hWnd, iCmdShow);
   UpdateWindow(hWnd);

   while (GetMessage(&msg, NULL, 0, 0) > 0)
   {
      TranslateMessage(&msg);
      DispatchMessage(&msg);
   }
   return msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT umsg, WPARAM wParam, LPARAM lParam)
{
   switch (umsg)
   {
   case WM_DESTROY:
      {
         PostQuitMessage(0);
         return 0;
      }
   }
   return DefWindowProc(hWnd, umsg, wParam, lParam);
}
Dabei ist das ganze C/C++ spezifische Zeugs durchaus klar (ich programmiere ja nicht erst seit gestern).
Viel mehr geht es mir um die Windows-Besonderheiten, die mich ein klein wenig verwirren.

Ich habe jetzt ein bisschen nachgelesen und msdn benutzt, aber mir ist sowohl das Gefundene zu ungenau als auch msdn.

Ich geh mal der Reihe nach den Code (ganz grob) durch, damit hier nicht jedes Stück erklärt wird und ihr seht was ich falsch verstanden habe/was nicht.

Quote:
LRESULT CALLBACK WndProc(HWND hWnd, UINT umsg, WPARAM wParam, LPARAM lParam)
So viel ich verstanden habe wird diese Funktion aufgerufen sobald mein Fenster eine Windows-Nachricht bekommt. Ich stelle mir das wie eine Art "Soft-Interrupt" vor. Das heißt in meinem Kopf sieht das so aus:

Fenster bekommt Message gesendet (z.B. über Maus, SendMessage, o.ä.) --> Fenster (bzw. genauer gesagt Windows) ruft für jede ankommende Nachricht automatisch die CALLBACK Funktion auf --> in der Funktion wird dann auf die Message reagiert (oder auch nicht)

Läuft das wirklich so ab? Fehlen da Schritte dazwischen? Oder kann man das grob zusammengefasst so sagen?

Dann gehts weiter mit der main, die ist soweit ja auch klar, bissel Structs füllen und Pointer/Objekte/etc. holen.
Bis zu der Stelle der While-Schleife ist mir alles klar.


Code:
   while (GetMessage(&msg, NULL, 0, 0) > 0)
   {
      TranslateMessage(&msg);
      DispatchMessage(&msg);
   }
Was das macht habe ich noch nicht ganz verstanden, laut msdn soll ich mir ungefähr folgendes drunter vorstellen:

Zuerst wird per GetMessage die aktuelle message aus der Warteliste des Prozesses/Threads geholt (von dem angegebenen Fenster).
Anschließend wandle ich ich die Message in irgendeine Art von "virtual key" um (was auch immer das genau ist). Für mich klingt das einfach nur nach eine Art Mapping bzw. casting.
Anschließend wird die message versandt, aber wohin?

DispatchMessage hat keinerlei Handle-Angabe, die message scheint also nicht an mein Fenster verschickt zu werden, sondern "irgendwohin"?!

Worauf das alles hinausläuft ist unter anderem auf diese Frage:
Kann ich die While-Schleife auch weglassen (bzw. zumindest leeren) ohne, dass ich Einschränkungen in der Message-Verarbeitung habe? Dass man dies Messages dann irgendwo anders holen/verwerfen/etc. muss ist mir klar, aber warum dann nicht direkt in der Callback-Funktion am Anfang/Ende?
Shadow992 is offline  
Old 12/16/2015, 21:03   #2


 
Jeoni's Avatar
 
elite*gold: 966
Join Date: Apr 2010
Posts: 1,105
Received Thanks: 681
Das Design dieses Teils der WinAPI ist zu Teilen meiner Meinung nach ziemlich misslungen, da will man sich nicht wirklich mit beschäftigen. Daher auch alle Informationen von mir unter Vorbehalt sehen. Habe damit lange nichts mehr gemacht und vieles selbst nur gehört.
Du brauchst die while-Schleife an einer Stelle deines Programmes. Erst durch diese findet die Messageverarbeitung statt. Irgendwo durch DispatchMessage wird afaik deine Callback-Funktion aufgerufen. Theoretisch könntest du die Callback-Funktion weglassen und die Verarbeitung direkt in der while-Loop machen.
Die Angabe eines Handles für DispatchMessage ist nicht nötig bzw. nicht wirklich möglich, weil du durch den Loop Messages für jedes mit dem Thread assoziierte Fenster bekommst (oder für den Thread generell). Das entsprechende Handle zum betroffenen Fenster befindet sich schon in der .
Nettes Projekt mit der Sprache im Übrigen. Rein vom lehr- bzw. lernwert (dort aber umso mehr), denn generell halte ich den Markt der Sprachen für durchaus gesättigt.
Mit freundlichen Grüßen
Jeoni

P.S.: Die oberen beiden Links ("About ..." und "Using ...") von könnten vielleicht noch etwas zum Verständnis beitragen.
Jeoni is offline  
Thanks
1 User
Old 12/16/2015, 21:44   #3
 
Shadow992's Avatar
 
elite*gold: 77
Join Date: May 2008
Posts: 5,430
Received Thanks: 5,878
Quote:
Originally Posted by Jeoni View Post
Das Design dieses Teils der WinAPI ist zu Teilen meiner Meinung nach ziemlich misslungen, da will man sich nicht wirklich mit beschäftigen. Daher auch alle Informationen von mir unter Vorbehalt sehen. Habe damit lange nichts mehr gemacht und vieles selbst nur gehört.
Du brauchst die while-Schleife an einer Stelle deines Programmes. Erst durch diese findet die Messageverarbeitung statt. Irgendwo durch DispatchMessage wird afaik deine Callback-Funktion aufgerufen. Theoretisch könntest du die Callback-Funktion weglassen und die Verarbeitung direkt in der while-Loop machen.
Die Angabe eines Handles für DispatchMessage ist nicht nötig bzw. nicht wirklich möglich, weil du durch den Loop Messages für jedes mit dem Thread assoziierte Fenster bekommst (oder für den Thread generell). Das entsprechende Handle zum betroffenen Fenster befindet sich schon in der .
Nettes Projekt mit der Sprache im Übrigen. Rein vom lehr- bzw. lernwert (dort aber umso mehr), denn generell halte ich den Markt der Sprachen für durchaus gesättigt.
Mit freundlichen Grüßen
Jeoni

P.S.: Die oberen beiden Links ("About ..." und "Using ...") von könnten vielleicht noch etwas zum Verständnis beitragen.
Vor allem der About-Link hat mir jetzt die erhoffte "Einsicht" gebracht.
Um es noch einmal kurz zusammen zu fassen, was wirklich passiert, wenn ein Prozess eine Message bekommt (für eventuelle Googler):

1. Die Message wird in die Message-Warteschlange des Threads eingereiht nach dem FIFO-Prinzip. Es wird keinerlei Message/Callback oder ähnliches aufgerufen.
2. Die Message muss "per Hand" aus der Warteschlange entfernt werden, dafür benutzt man GetMessage.
3. TranslateMessage ist dafür da, um Keyboard-Eingaben richtig zu verarbeiten (also scheinbar in den Basis-Fällen ala "isButtonClicked", etc. überflüssig).
4. Sobald DispatchMessage aufgerufen wird, wird asynchron (?) die festgelegte Prozedur aufgerufen und die Message entsprechend übergeben.

Der Clou an der ganzen Sache (vor allem am DispatchMessage) ist, dass das WindowHandle auch in der Message-Struct selbst gespeichert wird:

Quote:
The DispatchMessage function sends a message to the window procedure associated with the window handle specified in the MSG structure.

Quelle:
Zusammengefasst heißt das also:
Das Weglassen der Schleife (bzw. der DispatchMessage-Methode) heißt gleichzeitig, dass das Fenster auf keinerlei Eingaben/Messages mehr reagiert.
Shadow992 is offline  
Old 12/17/2015, 08:24   #4
 
Terrat's Avatar
 
elite*gold: 130
Join Date: Apr 2012
Posts: 1,173
Received Thanks: 670
Ja das ist richtig.
Falls du jetzt in richtung multi Window gehst musst du darauf achten das 1 Schleife mehrere Fenster handelt.
Terrat is offline  
Thanks
1 User
Old 12/17/2015, 10:49   #5


 
MrSm!th's Avatar
 
elite*gold: 7110
Join Date: Jun 2009
Posts: 28,902
Received Thanks: 25,407
Kleine Ergänzungen:

Quote:
3. TranslateMessage ist dafür da, um Keyboard-Eingaben richtig zu verarbeiten (also scheinbar in den Basis-Fällen ala "isButtonClicked", etc. überflüssig).
Das mag vielleicht aktuell so sein (kann mir gut vorstellen, dass da auch mal andere Mappings hinzukommen könnten), ich wüsste aber nicht, welchen Vorteil es einem bringen würde, den Aufruf wegzulassen. Falls es dir um Performance geht: Die Internals der Message Loop bzw. das Holen, Vorverarbeiten und Dispatchen dürften nun wirklich die letzten Aspekte sein, an denen man Performance rausholen kann. Immerhin geht es hier um ein GUI, etwas Interaktives - da ist sowieso der Mensch das Bottleneck.
Quote:
4. Sobald DispatchMessage aufgerufen wird, wird asynchron (?) die festgelegte Prozedur aufgerufen und die Message entsprechend übergeben.
Nein, das geschieht nicht asynchron, es geschieht ganz normal als Funktionsaufruf irgendwo innerhalb von DispatchMessage bzw. einer davon aufgerufenen Funktion. Deshalb ist es ja auch so wichtig, keine blockierenden I/O-Aufrufe oder allgemein zeitintensive Aufgaben in der WndProc durchzuführen. Wenn du dort blockierst, blockierst du die Message Loop und somit die gesamte Reaktionsfähigkeit des Programms. Das zieht sich durch alle Layer, die auf der Win32 API aufbauen und trifft auch z.B. bei .NET Programmen zu, die die eigentliche Message Loop abstrahieren (aber eben nicht umgehen).

Und deswegen könntest du die Loop auch nicht weglassen. Nicht nur, dass dein Programm dann keine Nachrichten verarbeiten würde, es würde de facto sofort beendet werden. Das Verweilen in der Message Loop ist schließlich das einzige in deinem Code, das den Main Thread davon abhält, direkt wieder aus der WinMain zu returnen und somit den Prozess zu beenden.

Quote:
Der Clou an der ganzen Sache (vor allem am DispatchMessage) ist, dass das WindowHandle auch in der Message-Struct selbst gespeichert wird:
Jo, die Message Loop verarbeitet alle Messages, die in die Queue des Threads gesteckt werden, sprich für alle Fenster, die zu dem Thread gehören, in dem GetMessage() aufgerufen wird. Die Zuweisung an die jeweiligen Fenster ist für dich als Aufrufer von GetMessage() nicht direkt relevant, das ist sogesehen eine Eigenschaft der Message selbst und erst innerhalb von DispatchMessage() von Bedeutung.
MrSm!th is offline  
Thanks
1 User
Old 12/17/2015, 14:10   #6
 
Shadow992's Avatar
 
elite*gold: 77
Join Date: May 2008
Posts: 5,430
Received Thanks: 5,878
Quote:
Originally Posted by MrSm!th View Post
Kleine Ergänzungen:
Falls es dir um Performance geht: Die Internals der Message Loop bzw. das Holen, Vorverarbeiten und Dispatchen dürften nun wirklich die letzten Aspekte sein, an denen man Performance rausholen kann. Immerhin geht es hier um ein GUI, etwas Interaktives - da ist sowieso der Mensch das Bottleneck.
Nö darum gings mir eigentlich nicht, war mehr ein "wenn das was ich schreibe falsch ist, wird jetzt jemand aufspringen und sich beschweren".

Danke dir für die Ergänzungen, gut zu wissen, dass das als "simpler" Funktionsaufruf implementiert ist. Und ich dachte Windows ist was Besonderes.
Shadow992 is offline  
Reply


Similar Threads Similar Threads
[C++] WinAPI GUI Wrapper
12/31/2013 - Coding Snippets - 0 Replies
Mal wieder was kleines von mir. Momentan versuche ich mich ein wenig an der Win32 API & das C-Zeugs hat mich irgendwann genervt, also habe ich angefangen, Wrapper für die GUI-Elemente zu schreiben. Momentan sind 2 Controls fertig, Button und Window. Bis auf WM_COMMAND und WM_DESTROY wird bisher keine Nachricht verarbeitet. nd::Window kann mit dem += Operator neue Controls hinzufügen (wie z.B. den Button) und mit dem -= Operator können diese wieder entfernt werden. nd::Button kann mit...
[Help] Winapi/C++
07/08/2011 - C/C++ - 2 Replies
Hallo leute also ich habe mir in letzter zeit oder schon etwas länger c++ Beigebracht. Ich weis nicht ob meine kenntnisse schon ausreichen aber naja ich hab mich mal an Winapi versucht und jetzt mein problem ... kann mir jemand vll erklären was n Handle ist und wenn nicht das gibt es dan vieleicht irgendwelche aufgaben womit ich mir meine c++ kenntnisse verbessern/festigen kann also ich hoffe ihr könnt mir helfen da ich echt ziehmlich interressiert in der Programmierung(Coding) bin. Ich würd...
Agbot loop dosnt loop
10/18/2008 - Silkroad Online - 1 Replies
my agbot after i tele will go through the 20 sec wait then says in bot concle feature not available yet feature not available yet idk whats wrong
WinAPI use in C#
06/09/2008 - .NET Languages - 15 Replies
Hi, in Anlehnung an die Topics hier habe ich mich dazu aufgerafft, nen Annotrainer zu schreiben (siehe Attachment). In der Listview werden halt aktive Annoprozesse angezeigt, die man dann anwählen kann um dann mit dem Cheat button Geld zu cheaten. Jedes item in der Listview hat im item.Tag das jeweilige Prozessobject, somit auch die ID. Allerdings komme ich mit den eigentlichen Funktionen OpenProcess, ReadProcessMemory und WirteProcessMemory in C# noch nicht klar. Zwar bekomme ich das...
WinAPI use in C#
05/19/2008 - .NET Languages - 0 Replies
Hi, in Anlehnung an die Topics hier habe ich mich dazu aufgerafft, nen Annotrainer zu schreiben (siehe Attachment). In der Listview werden halt aktive Annoprozesse angezeigt, die man dann anwählen kann um dann mit dem Cheat button Geld zu cheaten. Jedes item in der Listview hat im item.Tag das jeweilige Prozessobject, somit auch die ID. Allerdings komme ich mit den eigentlichen Funktionen OpenProcess, ReadProcessMemory und WirteProcessMemory in C# noch nicht klar. Zwar bekomme ich das...



All times are GMT +1. The time now is 16:01.


Powered by vBulletin®
Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
SEO by vBSEO ©2011, Crawlability, Inc.
This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

Support | Contact Us | FAQ | Advertising | Privacy Policy | Terms of Service | Abuse
Copyright ©2025 elitepvpers All Rights Reserved.