Die Unsitte Windows interne Nachrichten zu versenden

Neulich im http://www.c-plusplus.de/forum/ fand sich folgende Empfehlung:

XYZ schrieb:
Schreibe knapp vor der MAIN MESSAGE LOOP:
C/C++ Code:

PostMessage(DeinHandle,WM_CREATE,NULL,NULL); //oder so ähnlich vielleicht noch mit Instanz
while //MAIN MESSAGE LOOP

Ich staunte nicht schlecht. Grund für diesen Holzhammer war, dass „angeblich“ die Nachricht WM_CREATE, von Windows nicht verschickt wird. Also helfen wir einfach etwas nach und versenden diese selber.
Das sich dieser Code verbietet ist klar und ich will hier gar nicht weiter darauf eingehen warum.

Aber es bringt mich zum Thema:
Es ist eine beliebte Unsitte Windows Nachrichten, die nur für das interne Zusammenspiel der Komponenten und als „Benachrichtigungen“ dienen, selber zu versenden.
Favoriten hier sind oft WM_SETFOCUS, WM_PAINT, WM_SIZE, WM_KEYDOWN und manche andere.

Und Windows macht es dem Programmierer nicht einfach. In den Anfangszeiten von Windows wurde zu wenig bei der Namensgebung darauf geachtet, welche Nachrichten mehr oder weniger Aktionen auslösen und Eigenschaften setzen (z.B. WM_SETFONT) und welche Nachrichten als Notifications des OS dienen einem Programm mitzuteilen, dass etwas passiert ist, oder geschehen soll (z.B. WM_CREATE, WM_PAINT, WM_SETFOCUS, WM_SIZE, WM_ACTIVATE etc.).
Vieles wäre einfacher, wenn man Anhand des Nachrichtenamens erkennen würde, dass diese Nachricht vom OS versendet wird und damit nicht für den Eigenbedarf bestimmt ist.
Die letzte Gruppe der Nachrichten steht hier oft in einem direkten Zusammenhang mit einer API-Funktion (CreateWindow, UpdateWindow, SetFocus, SetWindowPos, SetActivteWindow etc.). Mit in diese Kategorie fällt, der Versuch mit WM_KEY… Nachrichten Tastatureingaben zu simulieren was auch nur in Ausnahmefällen korrekt funktioniert.

Mit der Einführung der neuen Common Controls, wurde hier nachgebessert. Sicherlich auch weil WM_COMMAND als Benachrichtigungs Medium etwas schmalbrüstig ist. WM_NOTIFY wurde eingeführt
Dieser Schritt war gut.  Interessanter Weise habe ich noch niemals den Versuch gesehen solche Notifications zu simulieren. Obwohl dies hier auch kein Problem wäre, denn es gibt hier keine API Funktionen, die Konfliktpotential anbieten würden.

Häufigster Grund solch einer Versuchung nachzugeben eine Nachricht selbst zu versenden, ist oft einfach Unwissen über die Windows-API. Und Eingangs erwähnte ich es schon: Die Dokumentation ist oft genug nicht eindeutig und macht zu selten auch Hinweise auf die entsprechenden verbundenen API Funktionen, siehe Doku zu WM_SETFOCUS in der wir nichts zu SetFocus lesen, außer in der Fußnote für See also. Erst die Doku der SetFocus API-Funktion gibt Aufschluss, dass diese Nachricht durch SetFocus versendet wirdund damit in gewisser Weise intern ist. Windows führt Buch welches Fenster den Fokus hat, aber dieser wird eben durch SetFocus gesetzt und nicht durch WM_SETFOCUS!

Fazit: Verurteilen kann man diese Unsitte schwer, außer mit dem Hinweis: „Es wurde nicht korrekt in der Doku gelesen, RTFM (Read the fine MSDN)“. Allerdings ist für Anfänger die MSDN oft genug einfach nur mehr erschlagend als informativ.
Dennoch kommt man nicht umhin sorgfältig auf die Zusammenhänge von Nachrichten und API-Funktionen zu studieren. Das bedeutet in diesem Zusammenhang, gerade die Dokumentationen der Funktionen, Nachrichten und Methoden zu lesen, die in der Fußnote unter See also aufgeführt werden. Oft genug findet man auf diesem Weg die Zusammenhänge (oft etwas mühsam) heraus.

Anmerkung: Die Dokumentation der MFC mach das Ganze leider noch schlimmer, denn hier werden nur kurze Auszüge der Windows-API wiedergegeben, die leider oft genug nicht detailliert genug sind. Hier ist immer angeraten, hinter einer virtuellen On… Funktion einen Windows Nachrichten Handler zu vermuten und in der Windows API noch einmal genauer nachzulesen. Allerdings macht sie auch einiges wiederklarer, denn sie kapselt die WM_… Nachrichten, die als Methoden/Getter/Setter funktionieren direkt in eigenständigen Memberfunktionen. Aber auch hier empfiehlt es sich nachzusehen was unter See also steht.

9 Gedanken zu „Die Unsitte Windows interne Nachrichten zu versenden“

  1. Hallo Martin,
    Sie beklagen den „..Versuch mit WM_KEY… Nachrichten Tastatureingaben zu simulieren ..“. Können Sie mir dann sagen wie man solche Eingaben an andere Anwendungen lehrbuchmässig macht?

  2. Es gibt nur einen einzigen Weg und der heißt SendKeys.
    Wenn die Applikation z.B. intern GetKeyState verwendet, dann wird nur durch Senden der WM_KEY… Nachricht der Tastenstatus nicht korrekt gesetzt.

    Gleichfalls würden keine Accelerator ausgelöst etc. etc. etc.

  3. SendKeys verlangt, dass die Zielanwendung im Vordergrund ist und ist daher kein realistischer Ersatz für die WM_ Methode. Die von Ihnen gescholtenen WM_ Methode hat offenbar doch eine Existenzberechtigung 😉

  4. Leider schaffe ich es selbst mit AttachThreadInput nur dann einer anderen Anwendung Tastendrucke zukommen zu lassen, wenn man diese zusätzlich mit SetFocus in den Vordergrund holt. Wie jedoch sendet man Tasten in ein minimiertes Fenster?

  5. Das ist doch klar! Nur eine Anwendung, die den Fokus hat, bekommt auch Tastatureingaben… Oder! Das ist doch der Sinn von Fokus haben und nicht haben!
    Eine minimierte Anwendung kannst Du doch wieder mit ShowWindow restaurieren. Eine minimierte Anwendung kann keine Tastatureingaben bekommen, weil sie keinen Fokus bekommen kann.

    Ich sehe schon ich muss dazu noch mal einen Blog Artikel scheiben 🙂

    Ansonsten wende dich an nntp://microsoft.public.de.vc oder an http://www.c-plusplus.de/forum

  6. Nun ja, es geht hier um mehrere Dinge.
    Jeder CreateWindow() sendet ein WM_CREATE an seine Fensterprozedur,
    und erst wenn diese Nachricht fertig bearbeitet ist, kehrt auch
    CreateWindow() zurueck und ist dann erst seinerseits fertig.
    WM_PAINT sollte man nicht senden, das erledigen InvalidateRect()
    (und seine Invalidatexxx-Brueder), auch wenn es mehr ein Formalismus
    zur Uebersicht und zum Verstaendis des Programmes ist.
    Das gilt auch fuer den zu bevorzugenden SetFocus() gegenuber
    WM_SETFOCUS .
    WM_COMMAND brauchts fuer die „klassischen“ (also seit Windows 3.0
    vorhandenen) Common Controls. Die senden kein WM_NOTIFY , was
    erstmalig mit Windows 95 (Explorer statt Programm-/Dateimanager)
    erschien.
    Ich persoenlich programmiere seit 25 Jahren unter DOS und Windows.
    Aber bis heute kann ich mit MFC nichts anfangen. Ich will nicht
    unterstellen, dass ich mit dieser Behauptung repraesentativ bin.
    Nach meiner Wahrnehmung bietet MFC keine auf irgendeine Weise
    vereinfachte „Schnittstelle“. Es kommt mir vor, als dass ich
    zuaetzlich zur mir bekannten klassischen Windows-Programmierung ein
    zusaetzliches und noch kompliziertes MFC begreifen muesste,
    was das Programmieren nicht einfacher macht (und womit sich der Sinn
    von MFC fuer mich in Frage stellt)
    Auch die Dokumentation von MFC kommt nach meiner Wahrnehmung
    qualitativ und quantitativ nicht an die des Win32-API (MSDN, Internet,
    Buecher, sonstwo) heran.

    1. Ich verstehe Deinen Kommentar nicht.
      Von WM_COMMAND habe ich nicht geredet auch nicht von WM_NOTIFY… ich habe diese nur erwähnt weil diese eben die klassischen Notifications sind.

      Bzgl. MFC wie auch anderer Technikenmag jeder seine Meinung haben.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.

This site uses Akismet to reduce spam. Learn how your comment data is processed.