JLI Spieleprogrammierung Foren-Übersicht JLI Spieleprogrammierung

 
 FAQFAQ   SuchenSuchen   MitgliederlisteMitgliederliste   BenutzergruppenBenutzergruppen 
 medals.php?sid=7d3eb2b5a1605d57a4eb3788320ae5cfMedaillen   RegistrierenRegistrieren   ProfilProfil   Einloggen, um private Nachrichten zu lesenEinloggen, um private Nachrichten zu lesen   LoginLogin 

Kapitel 12 - Programm hängt sich auf

 
Neues Thema eröffnen   Neue Antwort erstellen    JLI Spieleprogrammierung Foren-Übersicht -> Fragen, Antworten und Kritik
Vorheriges Thema anzeigen :: Nächstes Thema anzeigen  
Autor Nachricht
MarC++
Mini JLI'ler



Anmeldedatum: 02.03.2004
Beiträge: 3

Medaillen: Keine

BeitragVerfasst am: 08.11.2004, 15:10    Titel: Kapitel 12 - Programm hängt sich auf Antworten mit Zitat

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! Sad

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
Benutzer-Profile anzeigen Private Nachricht senden
The Lord of Programming
Living Legend


Alter: 37
Anmeldedatum: 14.03.2003
Beiträge: 3122

Medaillen: Keine

BeitragVerfasst am: 08.11.2004, 21:25    Titel: Antworten mit Zitat

Am besten, du postest mal den Code von der Schleife und den Code zum Beenden Wink
_________________
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
Benutzer-Profile anzeigen Private Nachricht senden Website dieses Benutzers besuchen
MarC++
Mini JLI'ler



Anmeldedatum: 02.03.2004
Beiträge: 3

Medaillen: Keine

BeitragVerfasst am: 09.11.2004, 05:20    Titel: Antworten mit Zitat

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
Benutzer-Profile anzeigen Private Nachricht senden
KI
JLI Master


Alter: 39
Anmeldedatum: 04.07.2003
Beiträge: 965
Wohnort: Aachen
Medaillen: Keine

BeitragVerfasst am: 09.11.2004, 08:45    Titel: Antworten mit Zitat

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
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden
The Lord of Programming
Living Legend


Alter: 37
Anmeldedatum: 14.03.2003
Beiträge: 3122

Medaillen: Keine

BeitragVerfasst am: 09.11.2004, 12:10    Titel: Antworten mit Zitat

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
Benutzer-Profile anzeigen Private Nachricht senden Website dieses Benutzers besuchen
MarC++
Mini JLI'ler



Anmeldedatum: 02.03.2004
Beiträge: 3

Medaillen: Keine

BeitragVerfasst am: 09.11.2004, 14:08    Titel: Antworten mit Zitat

@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
Benutzer-Profile anzeigen Private Nachricht senden
KI
JLI Master


Alter: 39
Anmeldedatum: 04.07.2003
Beiträge: 965
Wohnort: Aachen
Medaillen: Keine

BeitragVerfasst am: 09.11.2004, 18:35    Titel: Antworten mit Zitat

@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
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden
KI
JLI Master


Alter: 39
Anmeldedatum: 04.07.2003
Beiträge: 965
Wohnort: Aachen
Medaillen: Keine

BeitragVerfasst am: 09.11.2004, 19:18    Titel: Antworten mit Zitat

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
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden
KI
JLI Master


Alter: 39
Anmeldedatum: 04.07.2003
Beiträge: 965
Wohnort: Aachen
Medaillen: Keine

BeitragVerfasst am: 10.11.2004, 18:17    Titel: Antworten mit Zitat

(oh tripple post. Rolling Eyes - 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. Wink

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. Wink
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden
Beiträge der letzten Zeit anzeigen:   
Neues Thema eröffnen   Neue Antwort erstellen    JLI Spieleprogrammierung Foren-Übersicht -> Fragen, Antworten und Kritik Alle Zeiten sind GMT
Seite 1 von 1

 
Gehe zu:  
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

Impressum