NovaMonoFix
Errores PHP
X
Usuario
Password
0 FPS

Tutorial WINAPI C++ 1.1 (POO y WinMain)

01 de Abril del 2010 por Josep Antoni Bover, 27 visitas, 0 comentarios, 0 votos
Categorías : Windows, Programación, C y C++.
La web está en segundo plano, animación en pausa.
Cargando animación...
Tutorial WINAPI C++ 1.1 (POO y WinMain)

Introducción básica a la Programación Orientada a Objetos :

En la programación orientada a objetos, un objeto es un conjunto de métodos que se han diseñado para llevar a cabo una tarea. En este ámbito debemos pensar que el objeto contiene miembros públicos desde donde otros objetos accederán a el, y miembros privados que se utilizan internamente para realizar la tarea del objeto. Si aplicamos esto a la programación orientada a objetos bajo windows debemos tener claro que una ventana será un objeto, los botones de esa ventana también serán objetos que residirán dentro de esta, y dichos botones no serán accesibles entre ellos, es decir el botón 1 no sabe el texto que tiene el botón 2 y viceversa. En el caso de que necesitáramos pasarle el texto del botón 1 al botón 2 esto se llevaría a cabo desde el objeto ventana, ya que dicho objeto tiene acceso a los métodos y funciones públicos de los 2 botones.

Grafico objetos calculadoraPara ver este concepto más claro vamos a plantearnos que necesitamos hacer una calculadora. Esa calculadora requiere una ventana, diez botones con los números del 0 al 9, cinco botones para las operaciones básicas (suma, resta, multiplicación, división y resultado), un marcador para que podamos ver los resultados por pantalla que ademas realizara las operaciones de la calculadora. En la parte derecha podéis ver un esquema de como podríamos estructurar los objetos de la calculadora.

Una vez tengamos esta estructuración en mente, ya podemos empezar a darle forma. Empezaremos por ver la función WinMain de Windows, que viene a ser un substituto del típico int main(void) .

La función quedaría más o menos así :

Archivo : Tutorial_WinMain.cpp
1
2
3
4
int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow){
// INICIO DE NUESTRA APLICACIÓN
return 0;
}

Como podéis ver el WinMain nos da 4 parámetros :

En principio estos parámetros no los vamos a necesitar, y en caso de necesitarlos se pueden obtener por funciones del API de windows. Para obtener la instancia de nuestra aplicación podemos usar GetModuleHandle(NULL), y para obtener la línea de comandos podemos usar GetCommandLine.

En una aplicación que utilice ventanas debemos crear un bucle que capte los mensajes de todas nuestras ventanas, y los distribuya a su correspondiente ventana.

Veamos como debería ser un bucle main :

Archivo : Tutorial_WinMain.cpp
1
2
3
4
5
6
7
8
int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
MSG Mensaje;
while (TRUE == GetMessage(&Mensaje, NULL, 0, 0)) {
TranslateMessage(&Mensaje);
DispatchMessage(&Mensaje);
}
return 0;
}

Este bucle lo que hace es esperar a que windows mande un mensaje a nuestra aplicación para luego pasárselo a nuestra ventana. Para ello intervienen 3 APIS : GetMessage, TranslateMessage y DispatchMessage

Normalmente este bucle no debería variar a no ser que nuestra aplicación requiera mas tiempo de ejecución es decir que requiera un uso pleno de la CPU como sucedería en la mayoría de juegos. En este caso necesitaríamos hacer un bucle distinto. La API GetMessage espera a que Windows pase un nuevo mensaje para nuestra aplicación. Esto lo hace así porque en la ventana se ha especificado NULL, y en wParam y lParam se ha especificado 0. También podríamos especificar que solo obtuviera mensajes de una sola ventana lo que no resultaría muy útil a la hora de controlar una segunda ventana / control, ya que solo se procesarían los mensajes de una y la otra quedaría como descolgada.

Cabe a destacar que cuando se use la API PostQuitMessage, esta enviara la notificación WM_QUIT, y GetMessage devolverá FALSE de forma que terminara el bucle y la aplicación.

El bucle anterior es suficiente para aplicaciones que esperen eventos de una o varias ventanas, pero y si necesitamos ejecutar algún proceso durante toda la ejecución, independientemente de los eventos que puedan recibir las ventanas?

Archivo : Tutorial_WinMain.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
MSG Mensaje;
bool FinApp = false;
while (FinApp == false) {
NuestrasOperaciones();
if (PeekMessage(&Mensaje, NULL, 0, 0, PM_REMOVE)) {
if (Mensaje.message == WM_QUIT) FinApp = true;
TranslateMessage(&Mensaje);
DispatchMessage(&Mensaje);
}
}
return 0;
}

Con este bucle Main lo que estaríamos haciendo es : ejecutar NuestrasOperaciones(), luego miramos si hay algún mensaje para nuestra aplicación, si es así lo procesamos. La API PeekMessage no espera a que windows nos pase un mensaje para nuestra aplicación, simplemente mira si existe algún mensaje, y en ese caso lo procesa.

De la misma forma que antes en la API PeekMessage se ha especificado NULL en la ventana, 0 en el lParam y 0 en el wParam, Así podemos obtener todos los mensajes de nuestra aplicación, no solo los de una ventana.

En esencia las API's GetMessage y PeekMessage hacen lo mismo con la diferencia de que GetMessage se espera hasta recibir un mensaje de forma que la aplicación queda suspendida, y PeekMessage mira si existe algún mensaje en la cola, en ese caso no retorna 0 y podemos pasar a procesar el mensaje. Por último cabe a destacar que al usar PeekMessage tenemos que controlar cuando recibimos la notificación WM_QUIT, que es la encargada de decirnos que la aplicación debe terminar.

Visto todo esto ya podéis pasar al siguiente punto del tutorial, 1.2 - Creación de una ventana y obtención de sus eventos.

Descargar tutorial WinAPI completo Calculadora compilada