Seite 1 von 1

[C++] WinApi: ClassName (?)

Verfasst: 28.09.2016, 13:32
von joggel
Hallo,

ich stand vor kurzem vor einem Problem.
Ich habe ein Programm geschrieben, welches bei ankommenden Netzwerksignalen (Das war diese Frage) eine "selbst-gemalte" MessageBox anzeigt. Ist im Prinzip ein Fenster ohne Rahmen und ein kleiner Haken drinnen.
Ich habe dieses Fenster mittels CreateWindowEx kreiert. Das klappte auch soweit ganz gut.
ABER: es klappte nur ein einziges mal!!! Beim 2ten Aufruf von CreateWindowEx mit GENAU DENSELBEN Parametern wurde das Programm einfach beendet.
Ich bekam irgendwann heraus, dass ich niemals das Fenster gleich nennen durfte. Also habe ich die Parameter lpClassName und lpWindowName bei jedem Aufruf verändert, sowie auch der Parameter lpszClassName der Struktur WNDCLASSW die ja bei der Funktion RegisterClass verwendet wird.

Jetzt ist meine Frage: WIESO?
Ich habe ja auch nach jedem Aufruf der MessageBox ordentlich UnregisterClass aufgerufen... :?:

Ich meine, es funktioniert jetzt, aber es scheint mir keine sauberen Lösung zu sein.

Ich wollte nur mal wissen, was ich da falsch gemacht habe...

Re: [C++] WinApi: ClassName (?)

Verfasst: 28.09.2016, 14:06
von Krishty
Ich weiß nicht, was da schief läuft, aber ich glaube auch nicht, dass das Programm „einfach beendet“ wurde. Die WinAPI ruft niemals TerminateProcess() auf, wenn was nicht klappt, sondern löst immer irgendeine Exception aus, und falls die nicht gefangen wird, wird das Programm der Fehlerberichterstattung übergeben. Gab es keine Debug-Ausgaben? Keine Haltepunkte? Keinen Crash Dump?

Das mit der Fensterklasse stinkt mir aber. Die solltest du keinesfalls direkt um die Message Box bauen.

Fensterklassen sind da, damit fremde UI deine Fenster benutzen kann. Beispiel: Alle Edit-Controls, Combo-Boxen usw. in Windows liegen in der Bibliothek CommCtrl32.dll.
  • jedes Windows-Programm, das eine Combo-Box nutzt, lädt CommCtrl32.dll
  • CommCtrl32.dll registriert die Combo-Box-Klasse unter dem Namen COMBOBOX
  • das Programm ruft CreateWindow() mit COMBOBOX auf
  • jetzt hat es eine Combo-Box und musste dazu nichts wissen außer dem Namen
  • wenn das Programm beendet, zerstört es die Combo-Box
  • CommCtrl32.dll wird entladen
  • dabei zieht es die Klassenregistrierung zurück
Wenn du jetzt eine Fensterklasse joggelMessageBox registrierst, solltest du das vor der ersten Verwendung tun. UnregisterClass() erst bei Programmende, nicht nach jeder Box! Falls das Programm nämlich nicht exakt Modal abläuft (will man bei Netzwerkkram eigentlich nicht), oder das Fenster nicht richtig schließt, zerschießt du dein Fenster.

Re: [C++] WinApi: ClassName (?)

Verfasst: 28.09.2016, 14:14
von joggel
Es gab keine Exception, keine Debugausgabe, kein Crash dump, garnix. Ich habe den Haltepunkt auf der Zeile von CreateWindowEx(...) gesetzt, programm hielt dort, beim Ausführen dieser Zeile beendete sich der Debugger einfach...

Aber okay, das hatte ich garnicht mehr auf den Schirm, dass man CreateWindow zB auch mit COMBOBOX aufrufen kann.
Kann ich ja mal probieren.

Aber wie gesagt: komisch ist das Verhalten schon...

Re: [C++] WinApi: ClassName (?)

Verfasst: 28.09.2016, 14:26
von Krishty
Clowns sind komisch; das Verhalten ist sonderbar :)

Dann beendet nicht CreateWindowEx() das Programm, sondern deine Fensterprozedur (die wird innerhalb CreateWindowEx() ja mit WM_CREATE usw. aufgerufen).

Benutzt du assert()? Das löst eine Message Box aus, falls irgendwo was fehlschlägt. Die Message Box kann aber nicht erzeugt werden, während CreateWindowEx() läuft, oder verhakt sich da gern in Endlosschleifen. Dann ruft assert() std::unexpected() oder irgend so einen Scheiß auf.

Setz vor dem Aufruf von CreateWindowEx() einen Haltepunkt in deiner Fensterprozedur und schau, ob der angesprungen wird, bevor sich das Programm beendet! Die Art der Nachricht kannst du im Debugger anzeigen, indem du die entsprechende Variable ins Watch-Fenster einträgst und ,wm anhängst.

Re: [C++] WinApi: ClassName (?)

Verfasst: 28.09.2016, 15:11
von joggel
Also...ich verwende kein assert oder so.

Das Verhalten ist jetzt ein anderes.... :|
Jetzt schlägt der Aufruf RegisterClass fehl wenn ich zwei mal den gleichen Klassenname übergebe.

Auch egal...

Re: [C++] WinApi: ClassName (?)

Verfasst: 28.09.2016, 16:27
von gdsWizard
Ich hätte auch auf ein assert() getippt. Vielleicht hast du irgendwo vergessen (wo es notwendig ist) die DefWindowProc() aufzurufen. Manchmal wird darin rekursiv wieder eine Methode an den Callback weitergegeben oder irgendwas mit den Rückgabewerten ist nicht korrekt. Am schlüssigsten wäre aber wirklich assert(), aber da du es nicht benutzt....

Edit: Das Fehlschlagen des 2.Erzeugens mit dem selben Namen deutet darauf hin das UnRegisterClass fehl schlägt. Es ist aber keine gute Lösung Register und UnRegister öfter für die selbe Klasse zu machen.

Re: [C++] WinApi: ClassName (?)

Verfasst: 29.09.2016, 19:15
von Krishty
joggel hat geschrieben:Also...ich verwende kein assert oder so.
Verwendest du die STL? Die verwendet nämlich assert()s. Wenn du falsch auf einen std::vector zugreifst oder so, passiert das genauso.

Aktivier doch mal den Application Verifier für deine Anwendung, dann solltest du eine recht aussagekräftige Fehlermeldung bekommen …

Re: [C++] WinApi: ClassName (?)

Verfasst: 30.09.2016, 09:24
von joggel
ja, ich verwende die STL. Aber ich bin mir zu 100% sicher, dass in dem Moment nichts bei der Verwendung schief geht...

Und wie aktiviere ich diesen "Application Verifier"?

Re: [C++] WinApi: ClassName (?)

Verfasst: 30.09.2016, 12:40
von Krishty
Debug-Version deines Programms kompilieren

StartProgrammeApplication Verifier (falls dein Programm 32-bittig ist) oder Application Verifier (x64) (falls es 64-bittig ist) → Application Verifier

Im Fenster dann FileAdd Application

zur Debug-Version deines Programms navigieren und die auswählen

Häkchen bei
  • Basics
  • MiscDirty Stacks
  • Networking (da dein Programm ja offensichtlich Netzwerkfunktionalität nutzt)
dann Save

nun dein Programm im Debugger laufen lassen

im Output-Fenster sollte eine der ersten Meldungen (zwischen Dutzenden foo.dll loaded) sowas sein wie AV Debug Heap enabled; daran siehst du, dass der Verifier mitläuft
  • für dein Programm werden Allokationen nun so geändert, dass out-of-bounds-Zugriffe sofort im Debugger landen
  • uninitialisierte Variablen kriegen jetzt hässliche Default-Werte, damit sie schnell auffallen
  • viele WinAPI-Aufrufe werden auf Konsistenz überprüft
  • falls du Multi-Threading nutzt, kannst du Cuzz aktivieren, was dein Programm sehr viel langsamer macht, aber das Timing der Threads möglichst stark stört damit mögliche Race Conditions und Deadlocks zu Tage treten
Debugger hält an und zeigt Diagnostik, falls irgendwo was nicht stimmt – wenn wir eine exakte Fehlermeldung haben, sehen wir weiter

Re: [C++] WinApi: ClassName (?)

Verfasst: 30.09.2016, 12:48
von joggel
Okay, werd ich bei gelegenheit mal ausprobieren. Danke...