|
JLI Spieleprogrammierung
|
Vorheriges Thema anzeigen :: Nächstes Thema anzeigen |
Autor |
Nachricht |
MarC++ Mini JLI'ler
Anmeldedatum: 02.03.2004 Beiträge: 3
Medaillen: Keine
|
Verfasst am: 08.11.2004, 15:10 Titel: Kapitel 12 - Programm hängt sich auf |
|
|
Hi,
hatte ein kleines Problem welches ich zwar lösen konnte, aber trotzdem gerne wissen würde warum es aufgetreten ist. (Hab über die Suchfunktion keine AW gefunden)
In Kap 12 geht es ja um Nachrichten und in den Beispielen wird auf die Nachricht WM_DESTROY reagiert und PostQuitMessage(0) gesendet.
Wenn ich das so mache und das Fenster schliesse dann liefert GetMessage() als Rückgabewert -1 und das Programm hängt in der Nachrichtenschleife fest!
Ersetze ich WM_DESTROY durch WM_CLOSE, dann läuft alles wie es soll, d.h. GetMessage liefert 0 und die Schleife wird beendet!
Also, warum gehts mit WM_DESTROY nicht dafür aber mit WM_CLOSE (die Beispiele von CD funzen mit WM_DESTROY)
wenn die Beschreibung nicht reichen sollte kann ich noch den Quelltext posten
thx&cu
MarC++ _________________ MfG
MarC++ |
|
Nach oben |
|
|
The Lord of Programming Living Legend
Alter: 37 Anmeldedatum: 14.03.2003 Beiträge: 3122
Medaillen: Keine
|
Verfasst am: 08.11.2004, 21:25 Titel: |
|
|
Am besten, du postest mal den Code von der Schleife und den Code zum Beenden _________________ www.visualgamesentertainment.net
Current projects: RDTDC(1), JLI-Vor-Projekt, Tetris(-Tutorial), JLI-Format
(1) Realtime Developer Testing and Debugging Console
Anschlag, Anleitung zum Atombombenbau, Sprengkörper...
Hilf Schäuble! Damit er auch was findet... |
|
Nach oben |
|
|
MarC++ Mini JLI'ler
Anmeldedatum: 02.03.2004 Beiträge: 3
Medaillen: Keine
|
Verfasst am: 09.11.2004, 05:20 Titel: |
|
|
Code: |
#include "CreateWnd.h"
HWND hWnd = 0;
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow)
{
// Fenster erzeugen und Handle speichern
hWnd = CreateMainWindow(hInstance);
if(hWnd == 0)
{
MessageBox(NULL, "Fenster konnte nicht erzeugt werden", "Fehler", MB_ICONSTOP |MB_OK);
return 0;
}
MSG msg;
while(GetMessage(&msg, hWnd, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
LRESULT CALLBACK MessageHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_CLOSE: <----- WM_DESTROY klappt ned
PostQuitMessage(0);
return 0;
break;
}
return (DefWindowProc(hWnd, msg, wParam, lParam));
} |
_________________ MfG
MarC++ |
|
Nach oben |
|
|
KI JLI Master
Alter: 39 Anmeldedatum: 04.07.2003 Beiträge: 965 Wohnort: Aachen Medaillen: Keine
|
Verfasst am: 09.11.2004, 08:45 Titel: |
|
|
Hallo,
wo ist der Code von CreateMainWindow? Vielleicht hast Du da einen Fehler gemacht? Ist es echt ein Hauptfenster oder ein Dialog? Die brauchen nämlich unterschiedliche Message-Handler. Außerdem ist Deine Nachrichtenschleife inkorrekt. Damit sich das Programm nicht aufhängt, muss -1 auch behandelt werden, obwohl die Funktion GetMessage ein BOOL zurückgibt. Siehe MSDN.
Auszug: Code: |
BOOL bRet;
while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)
{
if (bRet == -1)
{
// handle the error and possibly exit
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
|
|
|
Nach oben |
|
|
The Lord of Programming Living Legend
Alter: 37 Anmeldedatum: 14.03.2003 Beiträge: 3122
Medaillen: Keine
|
Verfasst am: 09.11.2004, 12:10 Titel: |
|
|
MarC++ hat Folgendes geschrieben: | Code: | case WM_CLOSE: <----- WM_DESTROY klappt ned
PostQuitMessage(0);
return 0;
break;
} |
|
Musste man da nicht irgendwo auch noch DestroyWindow mit dem jeweiligen Fensterhandle aufrufen?
Versuch mal, obs funzt, wenn du im WM_DESTROY-Zweig noch zusätzlich diese Funktion aufrufst. _________________ www.visualgamesentertainment.net
Current projects: RDTDC(1), JLI-Vor-Projekt, Tetris(-Tutorial), JLI-Format
(1) Realtime Developer Testing and Debugging Console
Anschlag, Anleitung zum Atombombenbau, Sprengkörper...
Hilf Schäuble! Damit er auch was findet... |
|
Nach oben |
|
|
MarC++ Mini JLI'ler
Anmeldedatum: 02.03.2004 Beiträge: 3
Medaillen: Keine
|
Verfasst am: 09.11.2004, 14:08 Titel: |
|
|
@KI:
Hatte es in der MSDN gelesen das man -1 auch abfangen sollte, dachte aber es muss auch ohne gehen, da -1 imho nur im Fehlerfalle zurückgegeben wird, und Fehler mach ich ja keine! LOL
Das Fenster erstellen an sich sollte korrekt sein, da 1 zu 1 übernommen.
Trotzdem auch davon noch en Codeschnippes:
Code: | #include "CreateWnd.h"
HWND CreateMainWindow(HINSTANCE hInstance)
{
WNDCLASSEX wndClass =
{
sizeof(WNDCLASSEX), //Groesse angeben
CS_DBLCLKS | CS_OWNDC | //Standardstile
CS_HREDRAW | CS_VREDRAW,
MessageHandler, //Callback-Funktion
0, //Zusätzliche Angaben
0, //nicht benötigt
hInstance, //Anwendungsinstanz
LoadIcon(NULL, IDI_WINLOGO), //Windows-Logo
LoadCursor(NULL, IDC_ARROW), //Normaler Cursor
(HBRUSH)GetStockObject(WHITE_BRUSH), //Weisser Pinsel
NULL, //kein menü
"WindowClass", //Der Name der Klasse
LoadIcon(NULL, IDI_WINLOGO) //Windows-Logo
};
//Fensterklasse registrieren, damit sie von CreateWindowEx()
//verwendet werden kann
RegisterClassEx(&wndClass);
//Der Rückgabewert von CreateWindowEx() ist auch der Rückgabewert
//der Funktion
return CreateWindowEx(
NULL, // Ohne erweiterte Stile
"WindowClass", //Klassenname
"HelloWin", //fenstertitel
WS_OVERLAPPEDWINDOW | WS_VISIBLE, //fenster-Eigenschaften
100, //oben Links
100, //oben Links
300, //Breite
400, //Hoehe
NULL, //Elternfenster
NULL, //Menü
hInstance, //Anwendungsinstanz
NULL); //nicht benötigt
} |
@The Lord:
Hab mal wieder nach WM_DESTROY umbenannt und DestroyWindow(hWnd) dort eingefügt -> keine Änderung, soll heissen beim beenden liefert GetMessage -1 statt 0. _________________ MfG
MarC++ |
|
Nach oben |
|
|
KI JLI Master
Alter: 39 Anmeldedatum: 04.07.2003 Beiträge: 965 Wohnort: Aachen Medaillen: Keine
|
Verfasst am: 09.11.2004, 18:35 Titel: |
|
|
@MarC++
Ich hab den Code mal nachgeschrieben und bei mir funktioniert es ohne Fehler.
Mir ist aufgefallen, dass du in deinem ersten Codeschnippsel HWND hWnd = 0; global deklarierst.
Das musst du garnicht. Zudem wird im MessageHandler HWND hWnd nochmal deklariert...
Also.. Damit du dein Projekt mal mit meinem vergeleichen kannst. Es besteht aus 3 Dateien.
Einer Quelldatei
--> WinMain.cpp
Zwei Header-Dateien
--> WinMain.h
--> StdInc.h
Diese kannst du einfach in ein leeres Win32 Projekt einfügen und kompilieren.
Der Code ist im Prinzip identsich mit dem, den du hier gepostet hast.
Macht dein Programm noch mehr, außer ein Fenster erstellen... vielleicht liegt der Fehler ja doch woanders.
WinMain.cpp
Code: | //////////////////////////////
// Hauptfenster
//////////////////////////////
#include "StdInc.h"
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wndClass =
{
sizeof(WNDCLASSEX), //Groesse angeben
CS_DBLCLKS | CS_OWNDC | //Standardstile
CS_HREDRAW | CS_VREDRAW,
MessageHandler, //Callback-Funktion
0, //Zusätzliche Angaben
0, //nicht benötigt
hInstance, //Anwendungsinstanz
LoadIcon(NULL, IDI_WINLOGO), //Windows-Logo
LoadCursor(NULL, IDC_ARROW), //Normaler Cursor
(HBRUSH)GetStockObject(WHITE_BRUSH),//Weisser Pinsel
NULL, //Kein Menü
"WindowClass", //Der Name der Klasse
LoadIcon(NULL, IDI_WINLOGO) //Windows-Logo
};
//Fensterklasse registrieren, damit sie von CreateWindowEx()
//verwendet werden kann
RegisterClassEx(&wndClass);
HWND hWnd = CreateWindowEx(
NULL, //Ohne erweiterte Stile
"WindowClass", //Klassenname
"HelloWin", //Fenstertitel
WS_OVERLAPPEDWINDOW | WS_VISIBLE, //Fenster-Eigenschaften
100, //Oben Links
100, //Oben Links
300, //Breite
400, //Höhe
NULL, //Elternfenster
NULL, //Menü
hInstance, //Anwendungsinstanz
NULL); //nicht benötigt
if(hWnd == 0)
{
MessageBox(NULL, "Fenster konnte nicht erzeugt werden", "Fehler", MB_ICONSTOP |MB_OK);
return 0;
}
MSG msg;
BOOL bRet;
while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)
{
if (bRet == -1)
{
// handle the error and possibly exit
MessageBox(NULL, "Fehler beim Verlassen des Programms", "Fehler", MB_ICONSTOP |MB_OK);
return 0;
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return 0;
}
LRESULT CALLBACK MessageHandler(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam)
{
switch(uMessage)
{
case WM_DESTROY: // <----- WM_DESTROY klappt doch
PostQuitMessage(0);
return 0;
break;
}
return (DefWindowProc(hWnd, uMessage, wParam, lParam));
}
|
WinMain.h
Code: |
//////////////////////////////
// Hauptfenster
//////////////////////////////
#ifndef ___TEST__WINMAIN_H__INCLUDED
#define ___TEST__WINMAIN_H__INCLUDED
// Nachrichten-Prozedur
LRESULT CALLBACK MessageHandler(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam);
#endif // !___TEST__WINMAIN_H__INCLUDED
|
StdInc.h
Code: |
//////////////////////////////
// Master-Include-Datei
//////////////////////////////
// System-Header
#include <windows.h>
// Lokale Header
#include "WinMain.h" // Hauptfenster
|
|
|
Nach oben |
|
|
KI JLI Master
Alter: 39 Anmeldedatum: 04.07.2003 Beiträge: 965 Wohnort: Aachen Medaillen: Keine
|
Verfasst am: 09.11.2004, 19:18 Titel: |
|
|
KI hat Folgendes geschrieben: | Mir ist aufgefallen, dass du in deinem ersten Codeschnippsel HWND hWnd = 0; global deklarierst.
Das musst du garnicht. Zudem wird im MessageHandler HWND hWnd nochmal deklariert...
|
Nochmal dazu. Der MessageHandler benutzt natürlich sein eigenes hWnd. (welches in der Parameterliste deklariert wird)
Das hWnd global zu deklarieren ist übrigens garnicht so schlecht, wenn du es noch in anderen Funktionen brauchst.
und zum Fehler
Wenn man bei GetMessage als zweiten Parameter hWnd übergibt, gibt die Funktion nach der WindowMessage WM_DESTROY -1 zurück.
Wie in meinen anderen Posts und bei MSDN zu sehen kann mal dort auch NULL übergeben. Dann funktioniert wundersamerweise alles problemlos. |
|
Nach oben |
|
|
KI JLI Master
Alter: 39 Anmeldedatum: 04.07.2003 Beiträge: 965 Wohnort: Aachen Medaillen: Keine
|
Verfasst am: 10.11.2004, 18:17 Titel: |
|
|
(oh tripple post. - naja muss sein)
Das Problem liegt in der Funktion GetMessage.
Man sollte am besten immer NULL als zweiten Parameter übergeben.
Das ist nämlich einfach formuliert: viel praktischer.
Und da du ja so wissensdurstig bist, versuch ich mal zu erklären warum.
Bei NULL empfängt GetMessage Nachrichten für jedes Fenster, dass zum "calling thread" gehört. Außerdem werden Threadnachrichten empfangen. Wie z.B WM_QUIT ...
Und das ist auch schon der Knackpunkt. Wenn man nämlich einen hWnd an die GetMessage-Funktion übergibt, verliert jener nach DestroyWindow seine Gültigkeit und Getmessage gibt logischerweise -1 zurück.
Die Schleife müsste man demnach so umbauen ->
Code: |
do
{
// Nachricht für das Fenster holen
bRet = GetMessage(&msg, hWnd, 0, 0);
switch(bRet)
{
case -1:
// Im Fehlerfall gibt es keine Nachrichten mehr
// Nun muss überprüft werden, ob WM_QUIT da ist...
if(!GetMessage(&msg, NULL, 0, 0))
{
// Ja, ist da
MessageBox(NULL, "Quit", "", 0);
}
else
{
// Noch andere Thread-Messages da...
}
break;
default:
// Sonst Standard-Verhalten
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
while(msg.message != WM_QUIT);
return 0;
}
|
Ich bevorzuge ja diese Methode:
KI hat Folgendes geschrieben: | Hallo,
...
Auszug: Code: |
BOOL bRet;
while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)
{
if (bRet == -1)
{
// handle the error and possibly exit
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
|
|
Den einzigen Vorteil, den der hWnd Parameter bringt, ist der, dass man nur Messages von einem explizitem Fenster bekommt.
Was einem das bringt ist mir auch nicht klar.. da müsste man wohl mal die Entwicker von Windows fragen. |
|
Nach oben |
|
|
|
|
Du kannst keine Beiträge in dieses Forum schreiben. Du kannst auf Beiträge in diesem Forum nicht antworten. Du kannst deine Beiträge in diesem Forum nicht bearbeiten. Du kannst deine Beiträge in diesem Forum nicht löschen. Du kannst an Umfragen in diesem Forum nicht mitmachen.
|
Powered by phpBB © 2001, 2005 phpBB Group Deutsche Übersetzung von phpBB.de
|