Stratos: Punto de Encuentro de Desarrolladores

¡Bienvenido a Stratos!

Acceder

Foros





Ayuda Programa Básico en Windows

Iniciado por SrDurden, 09 de Junio de 2003, 10:52:55 PM

« anterior - próximo »

SrDurden

                                Hola!

He empezado a leerme el Game Programming Genesis, e intentando crear el esqueleto básico de un programa en windows tengo un pequeño error. He tratado de solucionarlo comparandolo con el codigo que se incluye en el tercer capítulo (uno que pone estrellitas por pantalla utilizando la GDI de windows), pero no encuentro el problema.

El programa se ejecuta bien, se enciende, aparece una pantalla con el fondo de color negro por pantalla, con su barra, con su titulo, con los botones de maximizar, minimizar, etc..

El problema resulta al cerrar el programa: Aunque ya no se está ejecutando, si hago un control+alt+sup aparece el nombre del fichero activo, como si se siguiera ejecutandose. Que le pasa?

Os adjunto el código del programa, es muy sencillo, un winmain que no hace nada (simplemente crea la ventana y se queda a la escucha de mensajes que le puedan llegar) y una callback function, que le llamo WinProc. Por favooooooooor, estoy desesperao, no encuentro el error por ninguna parte, y no conozco a nadie que sepa algo de programación en windows!!

Si sirve de algo utilizo Visual C++ 6.0.

Aquí el código:

#include
#include

#define WIN32_LEAN_AND_MEAN


LRESULT CALLBACK WinProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);




int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE hPrevInstance,
               LPSTR lpCmdLine, int nCmdShow)
{
   WNDCLASSEX sampleClass;
   HWND hwnd;
   MSG msg;

   sampleClass.cbSize = sizeof(WNDCLASSEX);
   sampleClass.style = CS_DBLCLKS | CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
   sampleClass.lpfnWndProc=WinProc;
   sampleClass.cbClsExtra=0;
   sampleClass.cbWndExtra=0;
   sampleClass.hInstance=hinstance;
   sampleClass.hIcon = LoadIcon(NULL, IDI_WINLOGO);
   sampleClass.hCursor = LoadCursor(NULL, IDC_ARROW);
   sampleClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
   sampleClass.lpszMenuName = NULL;
   sampleClass.lpszClassName = "Sample Class";
   sampleClass.hIconSm = LoadIcon(NULL, IDI_WINLOGO);

   if (!RegisterClassEx(&sampleClass)) return(0);

   if (!(hwnd = CreateWindowEx(NULL,
                              "Sample Class",
                        "Primer Pixel en Pantalla!",
                        WS_POPUP | WS_VISIBLE | WS_OVERLAPPEDWINDOW,
                        0, 0, 320, 240,
                        NULL,
                        NULL,
                        hinstance,
                        NULL)))  return(0);

   while(1)
   {
      if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
      {
         TranslateMessage(&msg);
         DispatchMessage(&msg);
      }
   }

   return(0);
}




LRESULT CALLBACK WinProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
   return(DefWindowProc(hwnd ,msg, wparam, lparam));
}









Siento el tocharro!! Por favor, si alguien ve el error que me lo explique, es que no logro entenderlo.. Quizás es algún mensaje que tengo que tratar en WinProc, o quizás es el bucle del programa..

Muchísimas gracias por adelantado,

SrDurden

PD=Mi primer Mensaje en el foro!!!!!!!!                                

tiutiu

                                Te falta tratar el mensaje WM_DESTROY en el WinProc. Este cacho de codigo formaria parte del switch(msg)



case WM_DESTROY:

   // Limpiar todo y terminar.

   PostQuitMessage(0);

   return 0;



Este mensaje me parece q se llama cuando se le da a Cerrar del menu contextual o a la X.

EDIT: Esta es la definicion que sale en 'C con clase' en http://winapi.conclase.net/curso/mensaje.p....php?WM_DESTROY

CitarEl mensaje WM_DESTROY se envía a una ventana que va a ser destruída. Es enviado por el procedimiento de ventana de la ventana que se destruirá antes de que sea retirada de la pantalla.

Este mensaje es enviado primero a la ventana a destruir y después a las ventanas hijas (si existen) que también serán destruidas. Durante el procesamiento del mensaje, se da por hecho que estas ventanas aún existen
b>:: Pandora's Box project ::
Notas e ideas sobre desarrollo de engines para juegos

SrDurden

                                He probado lo del quit_message pero sigue pasando lo mismo..
Puede ser algo que no elimine? El archivo se llama prova1, mientras lo ejecuto si hago un CTRL+ALT+SUP me aparece con el nombre de la aplicación ("Primer Pixel en pantalla!"), pero a la que le doy a la X de cerrar, se cierra pero al hacer un CTRL+ALT+SUP aparece prova1 (el nombre del archivo) como si se estuviese ejecutando..

Si sirve de algo este es el código que he añadido (gracias tiutiu!!):



LRESULT CALLBACK WinProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)

{

switch(msg) {

 case WM_DESTROY:

        PostQuitMessage(0);

        return 0;

  break;

}

 return(DefWindowProc(hwnd ,msg, wparam, lparam));

}



Sigue pasando lo mismo.. El caso es que el programa de ejemplo del Genesis (el de las estrellas) se ejecuta bien y sale bien, sin dejar ningún "rastro"..

Muchas gracias por contestarme, Saludotes,

SrDurden                                

[Over]

                                Hola.

Cuando controlas el WM_DESTROY y llamas a la funcion PostQuitMessage(0);, estas enviando el mensaje WM_QUIT. En el bluce principal que usas para controlar los mensajes:

while(1)
{
 if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
 {
   TranslateMessage(&msg);
   DispatchMessage(&msg);
 }
}

no estas controlando nada en si mismo. Tu aplicación se "apagara" al clikera en X, pero nunca se cerrará. Para terminar la aplicación pon esto en el bucle principal:

while(1)
{
 if (PeekMessage(&msg,NULL,0,0,PM_NOREMOVE))
 {
   if (!GetMessage(&msg,NULL,0,0))
     return msg.wParam;
   
   TranslateMessage(&msg);
   DispatchMessage(&msg);
 }
}

o esto otro:

while( GetMessage( &msg, NULL, 0, 0 ) )
{
 TranslateMessage( &msg );
 DispatchMessage( &msg );
}

Mira en la ayuda sobre la funcion GetMessage, pero basicamente si el mensaje pillado es WM_QUIT, devuelve 0, con lo que sale del while y con ello de la aplicación.

En el caso del primer control que te he puesto, si el mensaje pillado es WM_QUIT (que es 0, cumple el !GetMessage(...) ), devuelve el .wparam, que es 0,vaya...

Me explico muy mal, pero mirate la ayuda de la MSDN, que te explica muy bien las funciones esas y no te olvides de controlar WM_DESTROY en el WndProc.

Chao.                                

SrDurden

                                Por fin se apaga del todo ;P
El Problema es que me he dado cuenta de que no acabo de entender muy bien como va lo de coger mensajes..
Me lo miraré mejor en la ayuda y en el Genesis y si no lo entiendo ya volveré por aquí preguntando  :ojo:

Muchas gracias por vuestra ayuda, Saludotes,

SrDurden 8)                                

tiutiu

                               
CitarWhat Is WM_QUIT?
Normal message-processing loops in an application's WinMain routine usually exit when the GetMessage function returns a FALSE value. Internally, if GetMessage is about to return a WM_QUIT message, it returns FALSE instead of TRUE even though the message returned in the MSG structure (a WM_QUIT message) is valid. The only time GetMessage will ever return a FALSE value is when it is returning a WM_QUIT message. Conversely, PeekMessage returns WM_QUIT messages as it would any other message. Applications that use PeekMessage in their main message-processing loop must explicitly look for the WM_QUIT message.

The PostQuitMessage function does not actually post a WM_QUIT message to the application's task queue. Instead, it sets a flag that is tested inside GetMessage and PeekMessage. WM_QUIT is returned when GetMessage or PeekMessage detects that this flag is set and no other messages or events are pending for the application.

El PostQuitMessage() lo que hace es hacer q GetMessage y PeekMessage devuelvan un WM_QUIT cuando no haya mas mensajes pendientes, asi que segun dice aqui, si usas el Peek tienes q capturar el WM_QUIT tu mismo, y si usas el GetMessage pues lo pones en el while                                
b>:: Pandora's Box project ::
Notas e ideas sobre desarrollo de engines para juegos

SrDurden

                                Sigo haciendome la picha un lío  :(

He probado lo siguiente:

while(GetMessage(&msg,NULL,0,0))

{



 TranslateMessage(&msg);

 DispatchMessage(&msg);





}


Y tampoco se cierra del todo..

He probado lo siguiente..

while(GetMessage(&msg,NULL,0,0))

{

                if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))

    { TranslateMessage(&msg);

 DispatchMessage(&msg); }



    }

Y tampoco..

Ahora probaré
while(1)

{

 if (PeekMessage(&msg,NULL,0,0,PM_NOREMOVE))

 {

  if (!GetMessage(&msg,NULL,0,0)) return (0);



  TranslateMessage(&msg);

  DispatchMessage(&msg);

 }

}


Y como no, tampoco se ha cerrado bien.

Comienzo a hacerme un lio bastante grande sobre todas las funciones..

En teoría, peekMessage está vigilando que no llegue ningun mensaje, y en caso de que llegue algún mensaje, lo traduce y lo envía para que lo trate el WinProc, no?
Entonces, GetMessage que hace? Lo mismo que el WinProc pero a saco en el WinMain? Sin tener que traducirlo y enviarlo?

Muchas gracias, Saludotes,

SrDurden 8)                                

tiutiu

                                A ver, una cosa es el Message Loop y otra el WndProc. Cuando le das a la X para cerrar una ventana, se manda un mensaje WM_DESTROY al WndProc. Ahi tienes un switch(msg) donde entra en el case WM_DESTROY.
Entonces ahi le pondrias las funciones para descargar todo lo q tenga la aplicacion, por ejemplo destruir el RC del ogl, etc... y mandas un PostQuitMessage(0) que lo que hace es meter un WM_QUIT cuando no hay mas mensajes a procesar. Ese WM_QUIT tienes dos maneras de pillarlo, con GetMessage o con PeekMessage en el Message Loop (osea en el winmain.

Si usas GetMessage, no te hace falta hacer nada mas, simplemente el messageloop se compone de if(!GetMessage(...)) ya que si GetMessage recibe un WM_QUIT devuelve un 0 con lo cual el if se rompe y sale del message loop. Si usas el PeekMessage, tienes que tratarlo dentro, ya que PeekMessage copia el mensaje a una variable MSG q tu le pasas, asi q tendrias q hacer if(msg == WM_QUIT) break;                                
b>:: Pandora's Box project ::
Notas e ideas sobre desarrollo de engines para juegos

SrDurden

                                Siii, por fin va!  :P

No trataba el mensaje WM_DESTROY, y supongo que como no hacía el PostQuitMessage nunca salía de la aplicación..

Así me ha quedado el código finalmente:



#define WIN32_LEAN_AND_MEAN



/*Includes*/

#include <windows.h>

#include <windowsx.h>



/*Defines*/

#define WIN_CLASS_NAME "MyClass"



/*Variables Globales*/

HINSTANCE hInstance;

HWND hWnd;

int nWidth=400;

int nHeight=300;



/*Prototipos*/

LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);





/*Funcion Principal WinMain*/

int WINAPI WinMain(HINSTANCE hinstance,HINSTANCE hprevinstance,LPSTR lpcmdline,int ncmdshow)

{

WNDCLASSEX winclass;

HWND hwnd;          

MSG msg;            





winclass.cbSize =        sizeof(WNDCLASSEX);

winclass.style =         CS_DBLCLKS | CS_OWNDC | CS_HREDRAW | CS_VREDRAW;

winclass.lpfnWndProc =   WindowProc;     // message handler

winclass.cbClsExtra =    0;              // extra class info

winclass.cbWndExtra =    0;              // extra window info

winclass.hInstance =     hinstance;      // application handle

winclass.hIcon =         LoadIcon(NULL, IDI_WINLOGO);

winclass.hCursor =       LoadCursor(NULL, IDC_ARROW);

winclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);

winclass.lpszMenuName =  NULL;           // no menu, thanks

winclass.lpszClassName = WIN_CLASS_NAME; // identifier

winclass.hIconSm =       LoadIcon(NULL, IDI_WINLOGO); // small icon





if (!RegisterClassEx(&winclass)) return(0);





if (!(hwnd = CreateWindowEx(NULL,

    WIN_CLASS_NAME,                

    "Primera Ventana en Windows!",

    WS_OVERLAPPEDWINDOW | WS_VISIBLE,

    CW_USEDEFAULT, CW_USEDEFAULT,  

    nWidth, nHeight,                

    NULL,                          

    NULL,                          

    hinstance,                      

    NULL)))  return(0);





hWnd = hwnd;

hInstance = hinstance;







while(1)

{

 

 if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))

 {

  if (msg.message == WM_QUIT) break;

  TranslateMessage(&msg);

  DispatchMessage(&msg);

 }



}



return(msg.wParam);

}





/*CallBack Function*/

LRESULT CALLBACK WindowProc(HWND hwnd,UINT msg,WPARAM wparam,LPARAM lparam)

{

switch(msg)

{

case WM_DESTROY:

 PostQuitMessage(0);    

 return(0);

 break;

}



return(DefWindowProc(hwnd, msg, wparam, lparam));

}


Muchas gracias a todos, seguramente seguiré asaltando a dudas ;P

SrDurden 8)                                






Stratos es un servicio gratuito, cuyos costes se cubren en parte con la publicidad.
Por favor, desactiva el bloqueador de anuncios en esta web para ayudar a que siga adelante.
Muchísimas gracias.