Ejemplo: window click
Bien, tenemos una ventana pero esta no hace nada excepto lo que DefWindowProc( ) le permite que haga: cambiar el tama�o, ser maximizada, minimizada etc... Nada realmente excitante.
En la siguiente secci�n voy a mostrar como modificar lo que ya tenemos para que haga algo nuevo. As�, yo solo podr�a decirte "Procesa este mensaje y haz esto en �l..." y tu sabr�s lo que digo y ser�s capaz de hacerlo sin mirar un ejemplo entero. Esto es lo que espero, de todas maneras presta atenci�n.
Ok, para comenzar tomemos el ejemplo de la �ltima ventana en la que trabajamos y asegur�monos que compila y se ejecuta como lo esperamos. Puedes seguir trabajando en este archivo o puedes copiar el c�digo a un nuevo proyecto.
Vamos a agregarle a la ventana la capacidad de mostarle al usuario cu�l es el nombre del programa. ESto se har� cada vez que el usuario realice un click sobre la ventana. Nada excitante, es b�sicamente para ir entendiendo como manejar mensajes. Observemos que tenemos en nuestro WndProc():
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
Si queremos manipular clicks del mouse, necesitamos agregar un menejador (o procesador) WM_LBUTTONDOWN (o WM_RBUTTONDOWN, MBUTTONDOWN para clicks con el bot�n derecho y medio, respectivamente).
Cuando decimos "procesar un mensaje" significa agregar dicho mensaje dentro del WinProc( ) de nuestra clase ventana, lo hacemos de la siguiente manera:
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_LBUTTONDOWN: // <-
// <- agregamos esto
break; // <-
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
El orden en cual manejamos los mensajes raramente importa. Solo aseg�rate de poner el "break" despues de cada uno. Como puedes ver necesitamos otro case dentro de nuestro switch(). Ahora queremos que algo suceda cuando llegamos a esta nueva parte de nuestro programa.
Primero presentar� el c�digo que queremos agregar (el que le mostrar� al usuario el nombre del archivo del programa) y luego lo integrar� dentro del nuestro programa. Mas adelante, probablemente solo te muestre el c�digo y te dejar� que lo integres tu mismo. Esto es, por su puesto, mejor para mi porque no tengo que andar tipeando demasiado y mejor para vos porque ser�s capaz de agregar el c�digo dentro de CUALQUIER programa, no solamente el que estamos presentando. De todas maneras, si no est�s seguro de como hacerlo puedes mirar el c�digo fuente correspondiente a esta secci�n inclu�do en el archivo zip.
GetModuleFileName(hInstance, szFileName, MAX_PATH); MessageBox(hwnd, szFileName, "This program is:", MB_OK | MB_ICONINFORMATION);
Este c�digo no puede ser copiado en cualquier lugar dentro de nuestro programa. Especificamente queremos que �ste se ejecute cuando el usuario clickea el mouse, por lo tanto veremos como poner dicho c�digo dentro de nuestro programa:
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_LBUTTONDOWN:
// Comienzo del nuevo c�digo
{
char szFileName[MAX_PATH];
HINSTANCE hInstance = GetModuleHandle(NULL);
GetModuleFileName(hInstance, szFileName, MAX_PATH);
MessageBox(hwnd, szFileName, "This program is:", MB_OK | MB_ICONINFORMATION);
}
// Fin del nuevo c�digo
break;
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
Observa el nuevo conjunto de llaves { }. Estas son necesarias cuando declaramos una variable dentro de una sentencia switch( ). Esto es conocimiento b�sico de C pero pienso que es bueno recordarlo para aquellos que est�n haciendo las cosas por el camino dif�cil.
Una vez que has agregado el c�digo, comp�lalo. Si funciona, has click dentro de la ventana y ver�s desplegado un cuadro con el nombre del archivo .exe .
Habr�s notado que hemos agregado dos variables, hInstance y szFileName. Observa la funci�n GetModuleFileName y ver�s que el primer par�metro es un HINSTANCE refiri�ndose al m�dulo ejecutable (nuestro programa,el archivo .exe). �Donde obtenemos eso? GetModuleHandle( ) es la respuesta. Las referencias de GetModuleHandle( ) indican que si pasamos NULL como par�metro, nos retornar� un "Handle al archivo usado para crear el proceso de llamada" que es exactamente lo que necesitamos: el HINSTANCE anteriormente mencionado. Poniendo todo esto, finalizamos con la siguiente declaraci�n:
HINSTANCE hInstance = GetModuleHandle(NULL);
Ahora, con el segundo par�metro, nuevamente usamos nuestro confiable manual de referencia. Este dice: "un puntero al buffer que recibe la ruta y el nombre de archivo del modulo especificado" y el tipo de dato es LPTSTR (o LPSTR si tu referencia es vieja). Debido a que LPSTR es equivalente a char* podemos declarar un arreglo de caracteres como el siguiente:
char szFileName[MAX_PATH];
MAX_PATH es una macro inclu�da v�a <windows.h> definida como la m�xima longitud de un buffer necesario para almacenar el nombre de un archivo bajo Win32. Pasamos MAX_PATH a la funci�n GetModuleFileName( ) para que �sta conozca el tama�o del buffer.
Luego de que GetModuleFileName( ) es llamado, el b�ffer szFileName ser� llenado con un string terminado en cero conteniendo el nombre de nuestro archivo exe. Pasamos este valor a MessageBox() porque es una forma f�cil de mostrarlo en pantalla.
Por lo tanto, si has agregado esto en el c�digo, comp�lalo. Si funciona haz click en la ventana y deber�s ver desplegado un mensaje con el nombre del archivo.
Si esto no funciona, aqu� esta el c�digo completo. Comp�ralo con el tuyo para encontrar que errores has cometido.
#include <windows.h>
const char g_szClassName[] = "myWindowClass";
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_LBUTTONDOWN:
{
char szFileName[MAX_PATH];
HINSTANCE hInstance = GetModuleHandle(NULL);
GetModuleFileName(hInstance, szFileName, MAX_PATH);
MessageBox(hwnd, szFileName, "This program is:", MB_OK | MB_ICONINFORMATION);
}
break;
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wc;
HWND hwnd;
MSG Msg;
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wc.lpszMenuName = NULL;
wc.lpszClassName = g_szClassName;
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
if(!RegisterClassEx(&wc))
{
MessageBox(NULL, "Window Registration Failed!", "Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
hwnd = CreateWindowEx(
WS_EX_CLIENTEDGE,
g_szClassName,
"The title of my window",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 240, 120,
NULL, NULL, hInstance, NULL);
if(hwnd == NULL)
{
MessageBox(NULL, "Window Creation Failed!", "Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
while(GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return Msg.wParam;
}
Version en Espa�ol: Federico Pizarro - 2003.