Herramientas de usuario

Herramientas del sitio


fw:winapi

¡Esta es una revisión vieja del documento!


WinAPI

WinMain y el WndProc

Estudiaremos estos dos elementos cogiendo un código general de un programa que utilice la API de Windows:

#include <windows.h>
 
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
 
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
	HWND hWnd;
	MSG Message;
	WNDCLASS WndClass;
 
	WndClass.style = CS_HREDRAW | CS_VREDRAW;
        WndClass.lpfnWndProc = WindowProcedure;
	WndClass.cbClsExtra=0;
	WndClass.cbWndExtra = 0;
	WndClass.hbrBackground = (HBRUSH) GetStockObject (LTGRAY_BRUSH);
	WndClass.hCursor = LoadCursor (NULL, IDC_ARROW);
	WndClass.hIcon= LoadIcon (NULL, IDI_APPLICATION);
	WndClass.hInstance = hInstance;
	WndClass.lpszClassName = "NUESTRA_CLASE";
	WndClass.lpszMenuName = NULL;
 
	RegisterClass (&WndClass);
 
	hWnd = CreateWindow (
		"NUESTRA_CLASE",
		"Ventana de ejemplo",
		WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT,
		CW_USEDEFAULT,
		320,
		200,
		HWND_DESKTOP,
		NULL,
		hInstance,
		NULL
		);
 
	ShowWindow(hWnd, SW_SHOWDEFAULT);
 
	while (TRUE==GetMessage(&Message, 0,0,0))
	{
		TranslateMessage(&Message);
		DispatchMessage(&Message);
	}
 
	return Message.wParam;
}
 
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	switch(msg)
	{
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	default:
		return DefWindowProc (hwnd, msg, wParam, lParam);
	}
	return DefWindowProc(hwnd,message,wParam,lParam);
}

En el código anterior aparecen dos funciones: WinMain y WindowProcedure. El WinMain es lo que es el main a un programa convencional en C: el punto de entrada, la primera función que se ejecuta. La WndProc es la función encargada de recibir y procesar todos los mensajes que el SO manda a tu ventana (teclas presionadas, cambio de tamaño…).
Recuerda incluir el windows.h cuando programes con la Win32.
Es posible que si desarrollas con Visual Studio el código generado dé problemas (en la WndClass o en la CreateWindow) debido a conversiones de strings, esto es debido al juego de carácteres configurado como Unicode, hay que configurarlo como Multibyte (en las propiedades generales del proyecto).

WinMain

Parámetros

Su declaración recibe los siguientes parámetros:

  • Una HINSTANCE, el identificador del programa asignado por el SO.
  • Una segunda HINSTANCE, esta se usaba para la Win16 por lo que no la necesitaremos.
  • El LPSTR corresponden a los parámetros que se le han pasado en la ejecución.
  • El int es un flag que indica cómo ha de mostrarse la ventana (SW_HIDE, SW_MAXIMIZE, SW_MINIMIZE, SW_SHOWNORMAL…)

Bloques que contiene

  1. Declaración de variables y elementos iniciales para el programa (HWND, WNDCLASS…).
  2. Especificación de las características del programa (asignación de valores a las propiedades de la WNDCLASS y registro de esta).
  3. Creación de la ventana principal del programa (CreateWindow).
  4. Bucle del programa (o bucle de mensajes (message loop)), el while que irá recibiendo los mensajes y gestionándolos.

Tipos internos

  • HWND, es el handle de la ventana. El identificador de la ventana en Windows.
  • MSG, es el tipo de variable que corresponde a los mensajes del sistema. En la WinAPI toda la interacción SO - Programa - Usuario se hace mediante estos mensajes.
  • WNDCLASS es una estructura que indica las características de la clase ventana que vamos a utilizar, una vez la hayamos definido tendremos que registrarla mediante RegisterClass. Sus propiedades son:
    • style, el estilo de la ventana que puede ser, entre otros una combinación de CS_HREDRAW, CS_VREDRAW (redibujar la ventana si se cambia el tamaño en horizontal o vertical), CS_NOCLOSE (desactiva el botón de cerrado)…
    • lpfnWndProc, puntero a la función WndProc.
    • cbClsExtra, para indicar bytes extra de registro de la clase :?:, ponlo a 0.
    • cbWndExtra, como el anterior pero para la instancia. :?:
    • hInstance, la instancia del programa que contiene la ventana, es del tipo HINSTANCE y deberá ser el primer parámetro del WinMain.
    • hIcon, icono de la aplicación (32×32). LoadIcon (NULL, IDI_APPLICATION); → Hará que se cargue el icono por defecto.
    • hCursor, cursor de la aplicación. LoadCursor(NULL, IDC_ARROW); → Hará que se cargue el cursor por defecto.
    • hbrBackground, el color de fondo, es un objeto HBRUSH. Para asignarlo puedes indicar un objeto color: (HBRUSH)GetStockObject (WHITE_BRUSH);.
    • lpszMenuName, el nombre del recurso menú dado a la aplicación.
    • lpszClassName, el nombre con el que tu clase ventana será registrado.
  • También existe la WNDCLASSEX que es una WNDCLASS extendida, sus diferencias con la anterior son nuevas propiedades y que necesitamos la función RegisterClassEx para registrarla en vez de la RegisterClass. Las nuevas propiedades son:
    • cbSize, corresponde al tamaño de la estructura. Has de pasarle un sizeof(WNDCLASSEX);.
    • hIconSM, otro icono (16×16) correspondiente al que sale en la izquierda superior de la ventana.

Funciones que utiliza

  • RegisterClass, a la que le has de pasar una referencia del objeto WNDCLASS creado y lo registrará en el sistema.
  • CreateWindow\CreateWindowEx, es la función que crea la ventana en sí, cuando la llames te devolverá el HWND de esta. Recibe los siguientes parámetros (vemos los de CreateWindowEx):
    • Estilo de la ventana, una serie de flags.
    • Nombre con el que se ha registrado la aplicación (propiedad lpszClassName del WNDCLASS).
    • Texto del título de la ventana.
    • Flags sobre el estilo de creación de la ventana. Flags. Por ejemplo tenemos los siguientes:
      • WS_THICKFRAME: Crea la ventana como un popup, sin botones ni icono.
      • WS_OVERLAPPED: Sin botones, ni icono, ni escalable.
      • WS_SYSMENU: Con botón para cerrar, icono pero no escalable.
    • Dos integers correspondientes a la posición (x,y).
    • Dos integers correspondientes al ancho y alto.
    • HWND de la ventana padre (por si es un MDI), si no, NULL.
    • Menú de la ventana, pásalo a NULL.
    • Instancia de la aplicación.
    • Otro que has de pasar como NULL, a no ser que sea una aplicación MDI.
  • ShowWindow, a la que le pasas el HWND de la ventana y el int que te viene en el WinMain. En notas tienes el link de referencia a la documentación, por si quieres pasar otro argumento distinto.
  • TranslateMessage y DispatchMessage son para la gestión de mensajes.

WndProc

Es la función de tu aplicación a la que le llegan los mensajes enviados por el sistema operativo, generalmente contiene un switch que es donde se elige qué mensaje ha llegado, y por tanto, como gestionarlo. El mensaje viene como un int, y su valor correspondrá a uno de los defines declarados en windows.h, junto a él vienen dos parámetros wParam y lParam, estos dan más información sobre el mensaje. Algunos de los mensajes existentes son los siguientes:

  • WM_CLOSE: Cuando se ha indicado que se ha de cerrar la ventana (pulsando el botón de cerrar, haciendo ctrl+F4…).
  • WM_DESTROY: Cuando se cierra la aplicación.
  • WM_CREATE: Cuando se abre la aplicación.
  • WM_KEYDOWN: Cuando se apreta una tecla, en el wParam vendrá la tecla pulsada (VK_ESCAPE…).
  • WM_TIMER: Cuando llama un temporizador. En wParam vendrá el índice del temporizador.
  • WM_LBUTTONDOWN, WM_RBUTTONDOWN, WM_LBUTTONUP, WM_RBUTTONUP: Cuando se apreta o suelta el botón izquierdo\derecho del ratón.
  • WM_MOUSEMOVE: Cuando el ratón se mueve, desde lParam sabremos la posición del ratón (mira el apartado de consultar varios valores en el lParam). Si además queremos saber si está pulsando el botón (p.ej.) derecho tenemos que mirar el wParam: bool rightButtonDown=wParam & MK_RBUTTON;
  • WM_SIZE: Cuando se cambie el tamaño de la ventana, el nuevo tamaño vendrá en el lParam (mira el apartado de consultar varios valores en el lParam).

Cómo consultar varios valores en el lParam

Si lParam contiene varios valores utilizaremos las macros: LOWORD y HIWORD:

xPos=LOWORD(lParam);
yPos=HIWORD(lParam);

Gestión manual de mensajes

En windows toda ventana que se crea tiene asociado un thread y una función para procesar mensajes (wndproc). Una vez se crea la ventana a esta le empiezan a llegar mensajes, estos se van enconlando en una cola de mensajes global del sistema e identifican la ventana por su hwnd.

Funciones

Todas estas funciones manipulan una estructura denominada MSG. Generalmente se les pasa un puntero a una variable de este tipo y estas funciones dan los valores concretos.

  • PostMessage y SendMessage, envia un mensaje a una ventana concreta indicando el hwnd, la diferencia entre los dos es que el primero no espera a que el otro hwnd procese el mensaje y el segundo sí.
  • PostThreadMessage, envia un mensaje al thread indicado. Muy parecido al PostMessage pero los mensajes se envian por id de thread.
  • GetMessage y PeekMessage, recogen un mensaje de la cola de mensajes, la diferencia es que si no existe mensaje en esta el primero se espera y el segundo no, devolviendo true si ha recogido algo.
  • TranslateMessage transforma un mensaje a un mensaje de carácteres (de tratamiento más sencillo).
  • DispatchMessage envia un mensaje al window procedure.
  • PostQuitMessage se indica al thread que el proceso ha de terminar.
  • WaitMessage hace que se suspenda el thread hasta que no haya otro mensaje en la cola.

Documentación de estas funciones en la msdn

GDI

GDI es el conjunto de funciones que se utilizan para pintar sobre una ventana. Lo mejor es usarlas en el WndProc, cuando le llegue el mensaje: WM_PAINT, ya que es cuando el sistema pide un repintado. Recuerda, para utilizarlas tendrás que linkar la gdi32.lib.
Para dibujar necesitamos declarar una PAINTSTRUCT. El dibujo lo definiremos entre las llamadas a BeginPaint y EndPaint, estas reciben el HWND y el PAINTSTRUCT.

PAINTSTRUCT ps;
BeginPaint (hwnd, &ps);
...
EndPaint (hwnd, &ps);

Generalmente, el elementos que necesitaremos para hacer nuestros dibujos será la propiedad hdc del PAINTSTRUCT.

  • Todo dibujo va desde la posición actual hasta la indicada, para mover la posición actual utilizaremos MoveToEx.
MoveToEx(ps.hdc, 40,40,NULL);
  • Dibujar una línea, desde la posición actual hasta la indicada, pasándole el hdc del PAINTSTRUCT.
LineTo(ps.hdc, 50,50);
  • Para cambiar el estilo de una pluma (el tipo de línea) utilizamos la función: CreatePen (int estilo, int anchura, COLOREF color);. El estilo puede ser: PS_SOLID, PS_DASH, PS_DOT, PS_DASHOOT, PS_DASHDOTDOT. Devuelve una variable HPEN.
HPEN RedPen = CreatePen (PS_SOLID, 2, RGB(255,0,0));
  • Para asignar una pluma, fuente, brocha… al dibujo actual utilizaremos la función SelectObject. Esta función devuelve el objeto pluma, fuente, brocha… (según lo asignado) anterior.
HPEN OldPen = (HPEN) SelectObject(hdc, RedPen);
  • Podemos eliminar una pluma, fuente, brocha… utilizando DeleteObject, de esa forma liberaremos los recursos asociados a este.
  • Podemos dar color a un pixel concreto de nuestra ventana (un punto en una posición concreta): SetPixel(hdc, x, y, COLORREF);. O recoger el color de un pixel concreto: COLORREF GetPixel (hdc, x, y);
  • Podemos crear brochas (tipo de relleno) mediante las funciones CreateSolidBrush (color sólido), CreateHatchBrush (con adornos (HS_BDIAGONAL, HS_CROSS…) O CreatePatternBrush (relleno a partir de una imágen).
  • Figuras que podemos dibujar:
    • Rectangulo, con Rectangle(hdc, x1, y1, x2, y2);
    • Elipse, con Ellipse (hdc, x1, y1, x2, y2);
    • Polígonos, con Polygon (hdc, array de POINT, el número de vertices que se dibujarán);, el array de POINT corresponde a la posición de cada vértice del polígono:
POINT vertices[3];
vertices[0].x =25;
vertices[0].y =25;
vertices[1].x =50;
vertices[1].y =25;
vertices[2].x =AnchoVent;
vertices[2].y =AltoVent;
Polygon(hdc, vertices, 3);
  • El fondo de las figuras lo eligiremos mediante SetBkColor(hdc, COLORREF); y el tipo de fondo (OPAQUE o TRANSPARENT): SetBkMode(hdc, modo);
  • Para escribir texto usaremos la función TextOut (hdc, X, Y, puntero a la string o la string misma, número de caracteres de la string);, para darle color tendremos que llamar antes a la función: SetTextColor(hdc, COLORREF);.
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
TextOut(hdc,10,10,"Hello World",11);
EndPaint(hWnd, &ps);

Cómo...

General

  • Para mandar un mensaje a la cola de mensajes del sistema utilizamos la función PostMessage, sus parámetros son hwnd, el mensaje y los dos parámetros wParam y lParam: PostMessage(hwnd, WM_DESTROY, 0,0);
  • Para cambiar el cursor a medio programa usaremos la función SetCursor.
  • Para cambiar el título de la ventana utilizamos la función SetWindowText (hWnd, <cadena de caracteres>);
  • Para reproducir un sonido utilizaremos la función PlaySound (tendrás que linkar la winmm.lib): PlaySound(“window_open.wav”, NULL, SND_FILENAME | SND_ASYNC); Esta función recibe como parámetros:
    • El nombre del archivo wav que reproducirá.
    • Como reproducimos un fichero esto se pone a NULL.
    • SND_FILENAME indica que el sonido proviene de un fichero, SND_ASYNC que es asincrono. También está SND_LOOP para mantenerlo en un bucle.
  • Para saber el tamaño del área de cliente en la ventana le pasaremos el HWND y una referencia de una variable del tipo RECT (que será donde nos volcará el tamaño) a la función GetClientRect.
  • Para hacer invisible el cursor: ShowCursor(FALSE);
  • Cómo coger la posición actual del cursor? Pues con GetCursorPos al cual le pasas una referencia a una variable POINT.
  • Puedes convertir coordenadas con las funciones ScreenToClient o ClientToScreen; a las dos has de pasarle el HWND y un POINT.
  • Para terminar el programa utilizaremos el código PostQuitMessage(0);, esto envia el mensaje WM_QUIT al WndProc, lo que es una finalización definitiva.
  • Para recoger una HINSTANCE nueva, o de otro programa, utilizaremos la función GetModuleHandle a la que si le pasamos NULL nos devolverá una instancia válida para nuestro programa.
  • Para controlar el estado de la ventana (se minimiza, se maximiza, recibe el foco…) el mensaje que se lanza es el WM_ACTIVATE, cuando la HIWORD del wParam viene a true es que ha recibido el foco, cuando viene a false es que se ha minimizado o perdido el foco:
switch (uMsg) {
	case WM_ACTIVATE:
		if (!HIWORD(wParam)) active = TRUE;
		else active = FALSE;
		break;
...

Funciones avanzadas de control de teclado

  • GetAsyncKeyState: Indica si la tecla ha sido pulsada desde la última vez que se llamó a GetAsyncKeyState.
  • GetKeyState: Dice si la tecla está pulsada.

A las dos se les pasa como parámetro el nombre de la tecla: VK_LSHIFT, VK_RSHIFT, VK_LCONTROL…

if (GetAsyncKeyState(VK_LSHIFT)) MessageBox(NULL, "hol", NULL, NULL);

Creación de un Timer

Normalico

Para crear un Timer convencional utilizamos la función SetTimer, esta recibe los siguientes parámetros:

  • El manipulador de ventana (HWND).
  • Identificador del timer, un integer dado por nosotros.
  • Tiempo asignado al timer en milisegundos, cada x milisegundos el timer enviará la señal.
  • Un TimerProc al que se llamará cada x milisegundos. Una opción es poner este parámetro a NULL y controlar el timer mediante mensajes.
SetTimer(hWnd, 101, 1, NULL);

Para recibir los mensajes del timer lo haremos desde el WndProc, llegará un mensaje WM_TIMER. En el wParam vendrá el identificador del timer:

case WM_TIMER: 
     switch (wParam) { 
        case IDT_TIMER1: ... break;
        case IDT_TIMER2: ... break;
    } 

Para destruir un timer utilizamos KillTimer, pasándole:

  • El manipulador de ventana (HWND).
  • El identificador del timer.
De alta resolución

:!: Este tipo de timers requieren linkar la librería winmm.lib.

Construiremos un timer haciendo uso de las funciones QueryPerformanceFrequency y QueryPerformanceCounter, a las dos se les pasa un puntero a referencia a LARGE_INTEGER, la primera coloca en este la frecuencia del contador de alta resolución (si no puede porque el sistema no acepta este tipo de contadores coloca un 0), la segunda devuelve el valor actual del contador.
Para construir nuestro timer utilizaremos la siguiente estructura:

struct {
  __int64		frequency;			// Frecuencia
  float			resolution;			// Resolución
  bool			performance_timer;		// Indica si es un timer de alta resolución
  unsigned long		mm_timer_start;			// Momento en el que inicia (baja resolución)
  unsigned long		mm_timer_elapsed;		// Momento en el que finaliza (baja resolución)
  __int64		performance_timer_start;	// Momento en el que inicia (alta resolución)
  __int64		performance_timer_elapsed;	// Momento en el que finaliza (alta resolución)
} timer;

Usaremos la función que inicia el timer y la que recoge el momento actual. La que inicia el timer recogerá la frecuencia del contador de alta resolución, si este es soportado configurará el timer con los parámetros adecuados para este. Si no, conficurará un timer de baja resolución. Un timer de baja resolución utilizará la función timeGetTime, esta devuelve en milisegundos la hora del sistema (su frecuencia por tanto será de 1000 en un segundo y su resolución de 0.0001). Para el de alta esto vendrá según el parámetro dado por el sistema.

void TimerInit() {
	memset(&timer, 0, sizeof(timer));						
	if (!QueryPerformanceFrequency((LARGE_INTEGER *) &timer.frequency)) {
		timer.performance_timer	= FALSE;					
		timer.mm_timer_start	= timeGetTime();			
		timer.resolution	= 1.0f/1000.0f;				
		timer.frequency		= 1000;						
		timer.mm_timer_elapsed	= timer.mm_timer_start;	
	} else {
		QueryPerformanceCounter((LARGE_INTEGER *) &timer.performance_timer_start);
		timer.performance_timer		= TRUE;	
		timer.resolution		= (float) (((double)1.0f)/((double)timer.frequency));
		timer.performance_timer_elapsed	= timer.performance_timer_start;
	}
}

Ahora, recogemos el tiempo actual y lo restamos del inicial:

float TimerGetTime() {
	__int64 time;											
	if (timer.performance_timer) {
		QueryPerformanceCounter((LARGE_INTEGER *) &time);
		return ( (float) ( time - timer.performance_timer_start) * timer.resolution)*1000.0f;
	} else {
		return( (float) ( timeGetTime() - timer.mm_timer_start) * timer.resolution)*1000.0f;
	}
}

Configurar la resolución de pantalla y crear aplicaciones fullscreen

Puedes sacar algo de cambios de resolución o de convertir la aplicación a una de pantalla completa si lees el artículo de OpenGL que habla de ello, encontrarás información sobre un DEVMODE, la función ChangeDisplaySettings y EnumDisplaySettings.

Existen otras funciones que pueden serte de utilidad si haces aplicaciones de este estilo:

  • SetForegroundWindow que hace que se le dé más prioridad al thread de la clase ventana que se le indica.
  • SetFocus dá el foco a la ventana indicada.

Controles

Mostrar un mensaje

MessageBox(NULL, “Mensaje”, “Título”, NULL);

El primer parámetro corresponde al hwnd. Luego viene el mensaje y el título. En el último parámetro podremos elegir que icono y que botón queremos que aparezcan (icono | boton).

  • Iconos: MB_ICONWARNING, MB_ICONSTOP....
  • Botones: MB_OK, MB_YESNO, MB_RETRYCANCEL...

Luego podrá devolver distintos valores: IDNO, IDOK, IDCANCEL…

Trabajar con el menú de la aplicación

Tenemos que crear el menú como resource y luego asignarlo a la WNDCLASS.

winclass.lpszMenuName  = MAKEINTRESOURCE(IDR_MENU1);
  • A cada elemento del menú se le dá un ID distintivo.
  • Para interceptar los mensajes que este envía añadiremos un nuevo mensaje: WM_COMMAND. En el wParam de este se nos devolverá el id del elemento seleccionado.
case WM_COMMAND:
	switch (wParam)	{
		case ID_MENU1_MOSTRARCUADRO: ... break;
		case ID_MENU2_CONFIG: ... break;
	}
	break;

GDI

  • Para llamar a repintar la ventana existen dos funciones:
    • Utilizando la función UpdateWindow, que lo que hace es enviar a esta un mensaje WM_PAINT. Como parámetro has de ponerle el HWND de la ventana.
    • Utilizando la función InvalidateRect, esta actualiza una función en concreto. Hay que pasarle el HWND de la ventana, un objeto RECT y un booleano, true si queremos que se borre lo que ya había.

Crear doble buffer

  1. Crearemos un hdc a parte del que tenemos y compatible con este.
  2. Dibujaremos sobre este hdc.
  3. Volcaremos este sobre el que dibuja en la pantalla. De esa forma no mostramos y dibujamos a la vez.

Las variables que necesitamos:

HDC hdcBackBuffer;
HDC hdc;
HBITMAP BMPantes;
HBITMAP BMPahora;

Para conseguir un hdc compatible con el de la ventana utilizamos el método CreateCompatibleDC.

hdcBackBuffer = CreateCompatibleDC(NULL);
hdc = GetDC(hwnd);
BMPahora = CreateCompatibleBitmap(hdc, AnchoVent, AltoVent);
BMPantes = (HBITMAP) SelectObject(hdcBackBuffer, BMPahora);

Utilizaremos la función BitBlt para pintar sobre los hdc:

BitBlt(hdcBackBuffer, 0, 0, AnchoVent, AltoVent, NULL, NULL, NULL, WHITENESS);
RectX += velX;
RectY += velY;
SelectObject(hdcBackBuffer, Brocha);
Ellipse(hdcBackBuffer, RectX, RectY, RectX+tam,RectY+tam);
BitBlt(ps.hdc, 0, 0, AnchoVent, AltoVent, hdcBackBuffer, 0, 0, SRCCOPY);

Si la ventana cambia de tamaño tendremos que hacer los cambios adecuados en los bitmaps creados:

SelectObject(hdcBackBuffer, BMPantes);
DeleteObject(BMPahora); 
hdc = GetDC(hwnd);
BMPahora = CreateCompatibleBitmap(hdc,AnchoVent,AltoVent);
ReleaseDC(hwnd, hdc);
SelectObject(hdcBackBuffer, BMPahora);

La función BitBlt hace un volcado pixel a pixel de un hdc a otro, recibe los siguientes parámetros:

  • El HDC destino.
  • Dos ints correspondientes a la coordenada x,y de donde empiza a copiar.
  • Dos ints correspondientes al ancho y alto de la copia.
  • El HDC orígen.
  • Dos ints correspondientes a la coorenada x,y de donde copiará en el destino.
  • La flag que indique el tipo de operación: WHITENESS (pintar de blanco), SRCCOPY (copiar)…

Para ver las flags y más información sobre la función: MSDN - BitBlt

Threads y procesos

Procesos

  • Saber el proceso actual: GetCurrentProcess
  • Cambiar la prioridad del proceso actual: SetPriorityClass

Threads

  • Crear un thread: CreateThread

Notas

  • En la programación para Windows existen las funciones CALLBACK (como el WndProc), este identificador indica que la función es del sistema operativo, es decir, que se llama automáticamente. La clausula CALLBACK se coloca después del tipo devuelto:
void CALLBACK TimerProc(hwnd, uMsg, idEvent, dwTime) {...
  • Para recoger algún elemento de los resources utilizamos la macro MAKEINRESOURCE, a la que le pasamos el identificador del elemento deseado; esta devolverá un objeto que tendremos que castear.
  • Para cambiar el icono del .exe generado tendremos que tirar de los resources, importando a estos el deseado. Lo mismo pasa con el cursor de la aplicación, que podemos cogerlo de los resources del compilado. Para cargar un icono utilizamos la función LoadIcon y para cargar un cursor la LoadCursor.
WndClass.hIcon= LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_ICON1));
WndClass.hCursor = LoadCursor (GetModuleHandle(NULL), MAKEINTRESOURCE(IDC_CURSOR1));
  • La función ZeroMemory llena un bloque de memoria con ceros (lo limpia). Se le pasa un puntero y un tamaño en int (con el sizeof ya va bien). Perfecto para inicializar estructuras y muy parecido al memset.

Enlaces externos

Documentos

fw/winapi.1217415401.txt.gz · Última modificación: 2020/05/09 09:24 (editor externo)