Tag: SO2 – 2021 – Ficha 8 v.2.7 – Interface Grafica em Win32.pdf

sessão 11 – Programação gráfica orientada a eventos (2ª versão)

Referências bibliográficas:
Capítulos 2-5 e 7-9 do Livro Windows NT 4 Programming
MSDN:
Introduction to Windows Programming in C++
https://msdn.microsoft.com/en-us/library/ff381398(v=vs.85).aspx
Mouse Input
https://msdn.microsoft.com/en-us/library/gg153549(v=vs.85).aspx
Keyboard Input
https://msdn.microsoft.com/en-us/library/gg153546(v=vs.85).aspx
Mouse Movement
https://msdn.microsoft.com/en-us/library/gg153550(v=vs.85).aspx
Dialog Boxes
https://msdn.microsoft.com/en-us/library/windows/desktop/ms632588(v=vs.85).aspx
Menus
https://msdn.microsoft.com/en-us/library/windows/desktop/ms646977(v=vs.85).aspx
Windows Graphics Device Interface (GDI)
https://msdn.microsoft.com/en-us/library/dd145203(v=vs.85).aspx
Tutorial online: Win32 Fundamentals
http://www.functionx.com/win32/Lesson01.htm
Events
http://www.functionx.com/win32/Lesson05.htm
Object-Oriented Win32
http://www.functionx.com/win32/Lesson06.htm

Esta é a segunda revisão destes conteúdos, usar os recursos do win32 GDI:
1) adicionar recurso

2) escolher Icon

e apagar todos.. e ficar só com um.

3) aceder ao ID do recurso, e alterar para IDI_ICON_APP

4) adicionar um menu, com duas opções fixas e uma opção com submenus

o login, com popup a FALSE

e atribuir os ID a cada uma das opções.

5) as caixas de dialogo

e os componentes para a caixa de diálogo:

6) atalhos de teclas, aceleradores no windows

7) string table

ter um texto configurável, num recurso à parte. Utilidade: internacionalização da aplicação (tradução)

7) pointer

8) os comportamentos, usar o seguinte:

#include <windows.h>
#include <Windowsx.h>
#include <tchar.h>
#include "resource.h"

#define NUM_CLIENTES 3
#define LIST_SIZE 8

TCHAR* LIST_ITENS[] = {
	TEXT("10€"),
	TEXT("20€"),
	TEXT("40€"),
	TEXT("60€"),
	TEXT("80€"),
	TEXT("100€"),
	TEXT("150€"),
	TEXT("200€")
};

LRESULT CALLBACK TrataEventos(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK TrataEventosLogin(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK TrataEventosLevantar(HWND, UINT, WPARAM, LPARAM);

TCHAR szProgName[] = TEXT("Ficha8");

typedef struct {
	unsigned int ID;
	TCHAR username[16];
	TCHAR password[16];
	unsigned int saldo;
} cliente;

typedef struct {
	unsigned int tipo; // 1 = depósito, 2 = levantamento
	unsigned int quantia;
	unsigned int ID;
} operacao;

typedef struct {
	cliente clientes[NUM_CLIENTES];
	operacao historico[200];
	unsigned int numOperacoes;
} dados;

int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nCmdShow)
{
	HWND hWnd;
	MSG lpMsg;
	WNDCLASSEX wcApp;
	HANDLE hAccel;
	dados dadosPartilhados;

	wcApp.cbSize = sizeof(WNDCLASSEX);
	wcApp.hInstance = hInst;

	wcApp.lpszClassName = szProgName;
	wcApp.lpfnWndProc = TrataEventos;

	wcApp.style = CS_HREDRAW | CS_VREDRAW;

	wcApp.hIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_ICON_APP));
	wcApp.hIconSm = LoadIcon(hInst, MAKEINTRESOURCE(IDI_ICON_APP));
	wcApp.hCursor = LoadCursor(hInst, MAKEINTRESOURCE(IDC_POINTER));
	wcApp.lpszMenuName = MAKEINTRESOURCE(IDR_MENU_PRINCIPAL);

	wcApp.cbClsExtra = sizeof(dados);
	wcApp.cbWndExtra = 0;
	wcApp.hbrBackground = CreateSolidBrush(RGB(220, 220, 220));

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

	hWnd = CreateWindow(
		szProgName,
		TEXT("SO2 - Ficha 8"),
		WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT,
		CW_USEDEFAULT,
		300,
		150,
		(HWND)HWND_DESKTOP,
		(HMENU)NULL,
		(HINSTANCE)hInst,
		0);

	dadosPartilhados.numOperacoes = 5; // Apenas para testar...
	LONG_PTR x = SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)&dadosPartilhados);

	ShowWindow(hWnd, nCmdShow);

	hAccel = LoadAccelerators(NULL, MAKEINTRESOURCE(IDR_ACCELERATOR));

	while (GetMessage(&lpMsg, NULL, 0, 0))
	{
		if (!TranslateAccelerator(hWnd, hAccel, &lpMsg))
		{
			TranslateMessage(&lpMsg);
			DispatchMessage(&lpMsg);
		}
	}

	return((int)lpMsg.wParam);
}

LRESULT CALLBACK TrataEventos(HWND hWnd, UINT messg, WPARAM wParam, LPARAM lParam)
{
	TCHAR str1[512], str2[512];
	dados* dadosPartilhados;

	dadosPartilhados = (dados*)GetWindowLongPtr(hWnd, GWLP_USERDATA);

	switch (messg)
	{
	case WM_CREATE:
		EnableMenuItem(GetMenu(hWnd), ID_CONSULTA, MF_DISABLED | MF_GRAYED);
		EnableMenuItem(GetMenu(hWnd), ID_LEVANTAMENTOS, MF_DISABLED | MF_GRAYED);
		break;

	case WM_COMMAND:

		switch (LOWORD(wParam))
		{
		case ID_LOGIN:

			DialogBox(NULL, MAKEINTRESOURCE(IDD_DIALOG_LOGIN), hWnd, TrataEventosLogin);
			EnableMenuItem(GetMenu(hWnd), ID_CONSULTA, MF_ENABLED);
			EnableMenuItem(GetMenu(hWnd), ID_LEVANTAMENTOS, MF_ENABLED);
			break;

		case ID_CONSULTA:
		case ID_ACCELERATOR_CONSULTA:

			LoadString(NULL, IDS_STR_CONSULTA, str1, 512);
			_stprintf_s(str2, 512, TEXT("%s (%d)"), str1, dadosPartilhados->numOperacoes);
			MessageBox(hWnd, str2, TEXT("String Table"), MB_OK | MB_ICONINFORMATION);
			break;

		case ID_ACCELERATOR_LEVANTAMENTOS:
		case ID_LEVANTAMENTOS:

			DialogBox(NULL, MAKEINTRESOURCE(IDD_DIALOG_LEVANTAMENTO), NULL, TrataEventosLevantar);
			break;

		}

		break;

	case WM_DESTROY:
		PostQuitMessage(0);
		break;

	default:
		return DefWindowProc(hWnd, messg, wParam, lParam);
		break;
	}

	return(0);
}

LRESULT CALLBACK TrataEventosLogin(HWND hWnd, UINT messg, WPARAM wParam, LPARAM lParam)
{
	TCHAR username[16];

	switch (messg)
	{
	case WM_COMMAND:

		if (LOWORD(wParam) == IDOK)
		{
			GetDlgItemText(hWnd, IDC_EDIT_LOGIN, username, 16);
			MessageBox(hWnd, username, TEXT("Username"), MB_OK | MB_ICONINFORMATION);
		}
		else if (LOWORD(wParam) == IDCANCEL)
		{
			EndDialog(hWnd, 0);
			return TRUE;
		}

		break;

	case WM_CLOSE:

		EndDialog(hWnd, 0);
		return TRUE;
	}

	return FALSE;
}

LRESULT CALLBACK TrataEventosLevantar(HWND hWnd, UINT messg, WPARAM wParam, LPARAM lParam)
{
	int i;

	switch (messg)
	{
	case WM_INITDIALOG:

		HWND hwndList = GetDlgItem(hWnd, IDC_LIST_MONTANTES);
		SendMessage(hwndList, LB_RESETCONTENT, 0, 0);

		for (i = 0; i < LIST_SIZE; i++)
			SendMessage(hwndList, LB_ADDSTRING, 0, (LPARAM)LIST_ITENS[i]);

		break;

	case WM_COMMAND:

		if (LOWORD(wParam) == IDC_LIST_MONTANTES)
		{
			switch (HIWORD(wParam))
			{
			case LBN_DBLCLK:

				HWND hwndList = GetDlgItem(hWnd, IDC_LIST_MONTANTES);
				i = (int)SendMessage(hwndList, LB_GETCURSEL, 0, 0);
				MessageBox(hWnd, LIST_ITENS[i], TEXT("ListBox"), MB_OK | MB_ICONINFORMATION);

				break;
			}
		}

		break;

	case WM_CLOSE:

		EndDialog(hWnd, 0);
		return TRUE;
	}

	return FALSE;
}

Alguns comentários:

#include <windows.h>
#include <Windowsx.h>
#include <tchar.h>
#include "resource.h" //aceder aos ids, macros simbólicas

#define NUM_CLIENTES 3
#define LIST_SIZE 8

TCHAR* LIST_ITENS[] = {
	TEXT("10€"),
	TEXT("20€"),
	TEXT("40€"),
	TEXT("60€"),
	TEXT("80€"),
	TEXT("100€"),
	TEXT("150€"),
	TEXT("200€")
};

//tratamento de eventos das janelas
LRESULT CALLBACK TrataEventos(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK TrataEventosLogin(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK TrataEventosLevantar(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK TrataEventosAcerca(HWND, UINT, WPARAM, LPARAM);

TCHAR szProgName[] = TEXT("Ficha8");

typedef struct {
	unsigned int ID;
	TCHAR username[16];
	TCHAR password[16];
	unsigned int saldo;
} cliente;

typedef struct {
	unsigned int tipo; // 1 = depósito, 2 = levantamento
	unsigned int quantia;
	unsigned int ID;
} operacao;

//partilhar informação entre o mains e as funções de tratamentos de eventos
typedef struct {
	cliente clientes[NUM_CLIENTES];
	operacao historico[200];
	unsigned int numOperacoes;
} dados;

int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nCmdShow)
{
	HWND hWnd;
	MSG lpMsg;
	WNDCLASSEX wcApp;
	HANDLE hAccel;
	dados dadosPartilhados; //partilha de recursos

	wcApp.cbSize = sizeof(WNDCLASSEX);
	wcApp.hInstance = hInst;

	wcApp.lpszClassName = szProgName;
	wcApp.lpfnWndProc = TrataEventos;

	wcApp.style = CS_HREDRAW | CS_VREDRAW;
	//para poder usar as macros fazer uso do MAKEINTRESOURCE
	wcApp.hIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_ICON_APP)); 
	wcApp.hIconSm = LoadIcon(hInst, MAKEINTRESOURCE(IDI_ICON_APP));
	wcApp.hCursor = LoadCursor(hInst, MAKEINTRESOURCE(IDC_POINTER));
	wcApp.lpszMenuName = MAKEINTRESOURCE(IDR_MENU_PRINCIPAL);

	wcApp.cbClsExtra = sizeof(dados);
	wcApp.cbWndExtra = 0;
	wcApp.hbrBackground = CreateSolidBrush(RGB(220, 220, 220));

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

	hWnd = CreateWindow(
		szProgName,
		TEXT("SO2 - Ficha 8"),
		WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT,
		CW_USEDEFAULT,
		300,
		150,
		(HWND)HWND_DESKTOP,
		(HMENU)NULL,
		(HINSTANCE)hInst,
		0);

	//partilha de recursos
	dadosPartilhados.numOperacoes = 5; // Apenas para testar...
	LONG_PTR x = SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)&dadosPartilhados);

	ShowWindow(hWnd, nCmdShow);

	//ciclo de processamentos das mensagens, dos atalhos
	hAccel = LoadAccelerators(NULL, MAKEINTRESOURCE(IDR_ACCELERATOR));
	
	while (GetMessage(&lpMsg, NULL, 0, 0))
	{
		if (!TranslateAccelerator(hWnd, hAccel, &lpMsg))
		{
			TranslateMessage(&lpMsg);
			DispatchMessage(&lpMsg);
		}
	}

	return((int)lpMsg.wParam);
}

LRESULT CALLBACK TrataEventos(HWND hWnd, UINT messg, WPARAM wParam, LPARAM lParam)
{
	TCHAR str1[512], str2[512];
	dados* dadosPartilhados;
	 
	dadosPartilhados = (dados*)GetWindowLongPtr(hWnd, GWLP_USERDATA); //partilha de recursos

	switch (messg)
	{
	case WM_CREATE:
		//código de inicialização do sistema
		EnableMenuItem(GetMenu(hWnd), ID_CONSULTA, MF_DISABLED | MF_GRAYED);
		EnableMenuItem(GetMenu(hWnd), ID_LEVANTAMENTOS, MF_DISABLED | MF_GRAYED);
		break;

	
	case WM_COMMAND:
		//a parte menos significativa trás o ID da opção da janela que deu origem ao WM_COMMAND	
		switch (LOWORD(wParam))
		{
		case ID_LOGIN:
			//contexto, ID da macro da dialog box, o handler da janela principal, função para tratar o evento
			DialogBox(NULL, MAKEINTRESOURCE(IDD_DIALOG_LOGIN), hWnd, TrataEventosLogin);
			EnableMenuItem(GetMenu(hWnd), ID_CONSULTA, MF_ENABLED);
			EnableMenuItem(GetMenu(hWnd), ID_LEVANTAMENTOS, MF_ENABLED);
			break;

		//a parte menos significativa trás o ID da opção da janela que deu origem ao WM_COMMAND	
		case ID_CONSULTA:
		case ID_ACCELERATOR_CONSULTA:

			LoadString(NULL, IDS_STR_CONSULTA, str1, 512);
			_stprintf_s(str2, 512, TEXT("%s (%d)"), str1, dadosPartilhados->numOperacoes);
			MessageBox(hWnd, str2, TEXT("String Table"), MB_OK | MB_ICONINFORMATION);
			break;

		case ID_ACCELERATOR_LEVANTAMENTOS:
		case ID_LEVANTAMENTOS:

			DialogBox(NULL, MAKEINTRESOURCE(IDD_DIALOG_LEVANTAMENTO), NULL, TrataEventosLevantar);
			break;

		}

		break;

	case WM_DESTROY:
		PostQuitMessage(0);
		break;

	default:
		return DefWindowProc(hWnd, messg, wParam, lParam);
		break;
	}

	return(0);
}

LRESULT CALLBACK TrataEventosLogin(HWND hWnd, UINT messg, WPARAM wParam, LPARAM lParam)
{
	TCHAR username[16];

	switch (messg)
	{
	case WM_COMMAND:

		if (LOWORD(wParam) == IDOK)
		{
			GetDlgItemText(hWnd, IDC_EDIT_LOGIN, username, 16);
			MessageBox(hWnd, username, TEXT("Username"), MB_OK | MB_ICONINFORMATION);
		}
		else if (LOWORD(wParam) == IDCANCEL)
		{
			EndDialog(hWnd, 0);
			return TRUE;
		}

		break;

	case WM_CLOSE:

		EndDialog(hWnd, 0);
		return TRUE;
	}

	return FALSE;
}

LRESULT CALLBACK TrataEventosLevantar(HWND hWnd, UINT messg, WPARAM wParam, LPARAM lParam)
{
	int i;

	switch (messg)
	{
	case WM_INITDIALOG:

		HWND hwndList = GetDlgItem(hWnd, IDC_LIST_MONTANTES);
		SendMessage(hwndList, LB_RESETCONTENT, 0, 0);

		for (i = 0; i < LIST_SIZE; i++)
			SendMessage(hwndList, LB_ADDSTRING, 0, (LPARAM)LIST_ITENS[i]);

		break;

	case WM_COMMAND:

		if (LOWORD(wParam) == IDC_LIST_MONTANTES)
		{
			switch (HIWORD(wParam))
			{
			case LBN_DBLCLK:

				HWND hwndList = GetDlgItem(hWnd, IDC_LIST_MONTANTES);
				i = (int)SendMessage(hwndList, LB_GETCURSEL, 0, 0);
				MessageBox(hWnd, LIST_ITENS[i], TEXT("ListBox"), MB_OK | MB_ICONINFORMATION);

				break;
			}
		}

		break;

	case WM_CLOSE:

		EndDialog(hWnd, 0);
		return TRUE;
	}

	return FALSE;
}

Tags : , , , , ,

sessão 10 – Programação gráfica orientada a eventos (2ª versão)

Referências bibliográficas:
Capítulos 2-5 e 7-9 do Livro Windows NT 4 Programming
MSDN:
Introduction to Windows Programming in C++
https://msdn.microsoft.com/en-us/library/ff381398(v=vs.85).aspx
Mouse Input
https://msdn.microsoft.com/en-us/library/gg153549(v=vs.85).aspx
Keyboard Input
https://msdn.microsoft.com/en-us/library/gg153546(v=vs.85).aspx
Mouse Movement
https://msdn.microsoft.com/en-us/library/gg153550(v=vs.85).aspx
Dialog Boxes
https://msdn.microsoft.com/en-us/library/windows/desktop/ms632588(v=vs.85).aspx
Menus
https://msdn.microsoft.com/en-us/library/windows/desktop/ms646977(v=vs.85).aspx
Windows Graphics Device Interface (GDI)
https://msdn.microsoft.com/en-us/library/dd145203(v=vs.85).aspx
Tutorial online: Win32 Fundamentals
http://www.functionx.com/win32/Lesson01.htm
Events
http://www.functionx.com/win32/Lesson05.htm
Object-Oriented Win32
http://www.functionx.com/win32/Lesson06.htm

Esta é a segunda revisão destes conteúdos (desenhar completo):

#include <windows.h>
#include <tchar.h>
#include <windowsx.h>

//função que vai ser chamada pelo windows sempre que acontece alguma coisa: eventos..
LRESULT CALLBACK TrataEventos(HWND, UINT, WPARAM, LPARAM);

TCHAR szProgName[] = TEXT("Base"); //nome da janela

//winMain: main na parte gráfica
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nCmdShow) {
	HWND hWnd; // hWnd é o handler da janela, gerado mais abaixo por CreateWindow()
	MSG lpMsg; // MSG é uma estrutura definida no Windows para as mensagens
	WNDCLASSEX wcApp; // WNDCLASSEX definir as características da classe da janela


	//1. caracteristicas da janela
	wcApp.cbSize = sizeof(WNDCLASSEX); // Tamanho da estrutura WNDCLASSEX
	wcApp.hInstance = hInst;// Instância da janela actualmente exibida
	
	wcApp.lpszClassName = szProgName;       // Nome da janela (neste caso = nome do programa)
	wcApp.lpfnWndProc = TrataEventos; //indicar a a função que trata eventos  
	wcApp.style = CS_HREDRAW | CS_VREDRAW;  // Estilo da janela: Fazer o redraw se for
											// modificada horizontal ou verticalmente

	wcApp.hIcon = LoadIcon(NULL, IDI_INFORMATION);   // "NULL" = Icon definido no Windows
										   
	wcApp.hIconSm = LoadIcon(NULL, IDI_INFORMATION);  // "NULL" = Icon definido no Windows

	wcApp.hCursor = LoadCursor(NULL, IDC_ARROW);	// "hCursor" = handler do cursor (rato) 
							  // "NULL" = Forma definida no Windows
							  // "IDC_ARROW" Aspecto "seta" 
	wcApp.lpszMenuName = NULL; // (NULL = não tem menu)
	wcApp.cbClsExtra = 0; // Livre, para uso particular
	wcApp.cbWndExtra = 0; // Livre, para uso particular
	wcApp.hbrBackground = CreateSolidBrush(RGB(0,255,0)); //cor de fundo
		
	// 2. Registar a classe "wcApp" no Windows
	if (!RegisterClassEx(&wcApp))
	return(0);

	// 3. Criar a janela
	hWnd = CreateWindow(
		szProgName, // Nome da janela (programa) definido acima
		TEXT("Estudo para o exame"),// Texto que figura na barra do título
		WS_OVERLAPPEDWINDOW, // Estilo da janela (WS_OVERLAPPED= normal)
		CW_USEDEFAULT, // Posição x pixels (CW_USEDEFAULT=à direita da última)
		CW_USEDEFAULT, // Posição y pixels (CW_USEDEFAULT=abaixo da última)
		800, // Largura da janela (em pixels)
		600, // Altura da janela (em pixels)
		(HWND)HWND_DESKTOP,	// handle da janela pai ou HWND_DESKTOP se a janela for a primeira, criada a partir do "desktop"
		(HMENU)NULL, // handle do menu da janela (se tiver menu)
		(HINSTANCE)hInst,
		0);				
	  
	  // 4. Mostrar a janela
	ShowWindow(hWnd, nCmdShow);	// "hWnd"= handler da janela, devolvido por 
					  // "CreateWindow"; "nCmdShow"= modo de exibição (p.e. 
					  // normal/modal); é passado como parâmetro de WinMain()
	UpdateWindow(hWnd);		// Refrescar a janela (Windows envia à janela uma  mensagem para pintar, mostrar dados, (refrescar)… 

	// 5. Loop de Mensagens
	while (GetMessage(&lpMsg, NULL, 0, 0)) {
		TranslateMessage(&lpMsg); // pre processar os eventos
		DispatchMessage(&lpMsg); //
	} //GetMessage se recebe zero, fechar a janela, sai do ciclo

	// 6. Fim do programa
	return((int)lpMsg.wParam); // Retorna sempre o parâmetro wParam da estrutura lpMsg
}

int contaCliques =0;


typedef struct
{
	int xPos, yPos;
	TCHAR c;
} PosicaoCaracter;

LRESULT CALLBACK TrataEventos(HWND hWnd, UINT messg, WPARAM wParam, LPARAM lParam) {
	// UINT messg: código do evento de carregar numa tecla
	// valor da tecla que foi carregada é do WPARAM wParam
	// lParam: posixaoX, posicaoY do rato na janela

	static TCHAR c = '?'; //ou global
	//static int posX = 0; //ou static ou global, com o BeginPaint
	//static int posY = 0; //ou static ou global, com o BeginPaint
	

	HDC hdc; //para a escrita em janela!, handle device content

	RECT rect; //espaço de desenho

	static TCHAR charValue = '?';

	PAINTSTRUCT ps;

	//array dos histórico das posicções
	static PosicaoCaracter posicoes[500];
	static int totoalPosicoes = 0;
	int i;

	switch (messg) {

		case WM_PAINT: //evento para refresh da janela
		//operação de escrita REAL na janela é aqui
			hdc= BeginPaint(hWnd, &ps); //substitui GetDC(hWnd);
		// a posição da escrita
			GetClientRect(hWnd, &rect);
			FillRect(hWnd, &rect, CreateSolidBrush(RGB(0, 255, 0))); //pintar funto controlado
			SetTextColor(hdc, RGB(0, 123, 0));
			//fundo transparente
			SetBkColor(hdc, TRANSPARENT);

			for(i=0; i < totoalPosicoes; i++){
				rect.left = posicoes[i].xPos;
				rect.top = posicoes[i].yPos;
				//escrita do texto
				DrawText(hdc, &posicoes[i].c, 1, &rect, DT_SINGLELINE | DT_NOCLIP);
			}
		
			
			EndPaint(hWnd, &ps); //substitui ReleaseDC(hWnd, hdc);
		break;

		//case WM_ERASEBKGND: //somos nós a tratar o BKRND
		//	return TRUE;
					
		case WM_CHAR:
			c = (TCHAR)wParam;
			break;
		
		case WM_LBUTTONDOWN: 
			contaCliques++;
			charValue = contaCliques + '0';
		break;
		
		case WM_RBUTTONDOWN:
			if(totoalPosicoes < 500){
				posicoes[totoalPosicoes].xPos = GET_X_LPARAM(lParam); //macro GET_X_LPARAM
				posicoes[totoalPosicoes].yPos = GET_Y_LPARAM(lParam);//macro GET_Y_LPARAM
				posicoes[totoalPosicoes].c = charValue;
				totoalPosicoes++;
				InvalidateRect(hWnd, NULL, FALSE); //janela invalida, pinta de novo
			}
			//limpar a janela com o beginpaint
			
			
			//inicio processo desenhar/escrever
			//hdc = GetDC(hWnd);
			
			
			//fim processo desenhar/escrever
			//ReleaseDC(hWnd, hdc);
			break;
		
		case WM_CLOSE: //fechar a janela
			if(
				MessageBox(
				hWnd, 
				TEXT("tem a certeza que quer sair?"), 
				TEXT("Confirmação"),
				MB_YESNO | MB_ICONQUESTION) //combinar flags |
					== IDYES)
				{
					DestroyWindow(hWnd);
					//fechar a janela
				}
			break;
		case WM_DESTROY: // Destruir a janela e terminar o programa 
			PostQuitMessage(0); // "PostQuitMessage(Exit Status)"		
			break;
		default: //mt importante, para lidar com o que não foi feito tratamento
			return(DefWindowProc(hWnd, messg, wParam, lParam));
			break;  // break tecnicamente desnecessário por causa do return
	}
	return(0);
}

Esta é a segunda revisão destes conteúdos (desenhar completo e limpo):

#include <windows.h>
#include <tchar.h>
#include <windowsx.h>

LRESULT CALLBACK TrataEventos(HWND, UINT, WPARAM, LPARAM);

TCHAR szProgName[] = TEXT("Base");

int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nCmdShow) {
	HWND hWnd; 
	MSG lpMsg; 
	WNDCLASSEX wcApp; 
	
	wcApp.cbSize = sizeof(WNDCLASSEX);
	wcApp.hInstance = hInst;
	wcApp.lpszClassName = szProgName; 
	wcApp.lpfnWndProc = TrataEventos; 
	wcApp.style = CS_HREDRAW | CS_VREDRAW;  
	wcApp.hIcon = LoadIcon(NULL, IDI_INFORMATION);
	wcApp.hIconSm = LoadIcon(NULL, IDI_INFORMATION);
	wcApp.hCursor = LoadCursor(NULL, IDC_ARROW);
							  
	wcApp.lpszMenuName = NULL;
	wcApp.cbClsExtra = 0; 
	wcApp.cbWndExtra = 0; 
	wcApp.hbrBackground = CreateSolidBrush(RGB(0,255,0)); 
		
	if (!RegisterClassEx(&wcApp))
	return(0);

	hWnd = CreateWindow(
		szProgName, 
		TEXT("Estudo para o exame"),
		WS_OVERLAPPEDWINDOW, 
		CW_USEDEFAULT, 
		CW_USEDEFAULT, 
		800, 
		600, 
		(HWND)HWND_DESKTOP,
		(HMENU)NULL, 
		(HINSTANCE)hInst,
		0);				
	  
	ShowWindow(hWnd, nCmdShow);
	UpdateWindow(hWnd);

	while (GetMessage(&lpMsg, NULL, 0, 0)) {
		TranslateMessage(&lpMsg);
		DispatchMessage(&lpMsg);
	}
	return((int)lpMsg.wParam);
}

int contaCliques =0;


typedef struct
{
	int xPos, yPos;
	TCHAR c;
} PosicaoCaracter;

LRESULT CALLBACK TrataEventos(HWND hWnd, UINT messg, WPARAM wParam, LPARAM lParam) {
	static TCHAR c = '?';
	HDC hdc; 
	RECT rect;
	static TCHAR charValue = '?';

	PAINTSTRUCT ps;
	static PosicaoCaracter posicoes[500];
	static int totoalPosicoes = 0;
	int i;

	switch (messg) {
		case WM_PAINT:
			hdc= BeginPaint(hWnd, &ps);
			GetClientRect(hWnd, &rect);
			FillRect(hWnd, &rect, CreateSolidBrush(RGB(0, 255, 0)));
			SetTextColor(hdc, RGB(0, 123, 0));
			SetBkColor(hdc, TRANSPARENT);

			for(i=0; i < totoalPosicoes; i++){
				rect.left = posicoes[i].xPos;
				rect.top = posicoes[i].yPos;
				DrawText(hdc, &posicoes[i].c, 1, &rect, DT_SINGLELINE | DT_NOCLIP);
			}
			EndPaint(hWnd, &ps);
		break;
			
		case WM_CHAR:
			c = (TCHAR)wParam;
			break;
		
		case WM_LBUTTONDOWN: 
			contaCliques++;
			charValue = contaCliques + '0';
		break;
		
		case WM_RBUTTONDOWN:
			if(totoalPosicoes < 500){
				posicoes[totoalPosicoes].xPos = GET_X_LPARAM(lParam);
				posicoes[totoalPosicoes].yPos = GET_Y_LPARAM(lParam);
				posicoes[totoalPosicoes].c = charValue;
				totoalPosicoes++;
				InvalidateRect(hWnd, NULL, FALSE); 
			}
			break;
		
		case WM_CLOSE:
			if(
				MessageBox(
				hWnd, 
				TEXT("tem a certeza que quer sair?"), 
				TEXT("Confirmação"),
				MB_YESNO | MB_ICONQUESTION) 
				== IDYES)
				{
					DestroyWindow(hWnd);
				}
			break;
		case WM_DESTROY:
			PostQuitMessage(0);
			break;
		default:
			return(DefWindowProc(hWnd, messg, wParam, lParam));
			break;
	}
	return(0);
}

Usar uma BMP na janela (segunda versão):

#include <windows.h>
#include <tchar.h>
#include <windowsx.h>
//exercicio 6)
LRESULT CALLBACK TrataEventos(HWND, UINT, WPARAM, LPARAM);

TCHAR szProgName[] = TEXT("Base");

//lidar com o bitmap, globais: têm que ser acedidas por várias funções, ou uma struct 1 uma variavel global
HBITMAP hBMP; //acesso ao bitmap
HDC bmpDC;
BITMAP bmp; //estrutura do bitmap
int xBitmap;
int yBitmap;

int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nCmdShow) {
	HWND hWnd;
	MSG lpMsg;
	WNDCLASSEX wcApp;

	wcApp.cbSize = sizeof(WNDCLASSEX);
	wcApp.hInstance = hInst;
	wcApp.lpszClassName = szProgName;
	wcApp.lpfnWndProc = TrataEventos;
	wcApp.style = CS_HREDRAW | CS_VREDRAW;
	wcApp.hIcon = LoadIcon(NULL, IDI_INFORMATION);
	wcApp.hIconSm = LoadIcon(NULL, IDI_INFORMATION);
	wcApp.hCursor = LoadCursor(NULL, IDC_ARROW);

	wcApp.lpszMenuName = NULL;
	wcApp.cbClsExtra = 0;
	wcApp.cbWndExtra = 0;
	wcApp.hbrBackground = CreateSolidBrush(RGB(0, 255, 0));

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

	hWnd = CreateWindow(
		szProgName,
		TEXT("Estudo para o exame"),
		WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT,
		CW_USEDEFAULT,
		800,
		600,
		(HWND)HWND_DESKTOP,
		(HMENU)NULL,
		(HINSTANCE)hInst,
		0);

	//lidar com o bitmap
	hBMP = (HBITMAP)LoadImage(NULL, TEXT("imagem.bmp"), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
	//preciso da informação da imagem (metadados)
	GetObject(hBMP, sizeof(bmp), &bmp);
	//passar a informação para o device content
	HDC hdc;
	hdc = GetDC(hWnd);
	//criar a copia
	bmpDC = CreateCompatibleDC(hdc);
	//aplicar o bitmap ao DC
	SelectObject(bmpDC, hBMP);
	ReleaseDC(hWnd, hdc);
	//definir as posições iniciais da imagem: ao centro
	RECT rect; //largura da janela actual do cliente
	GetClientRect(hWnd, &rect);
	//xBitmap = (rect.right / 2) - (bmp.bmWidth / 2);
	//yBitmap = (rect.bottom / 2) - (bmp.bmHeight / 2);

	ShowWindow(hWnd, nCmdShow);
	UpdateWindow(hWnd);

	while (GetMessage(&lpMsg, NULL, 0, 0)) {
		TranslateMessage(&lpMsg);
		DispatchMessage(&lpMsg);
	}
	return((int)lpMsg.wParam);
}


LRESULT CALLBACK TrataEventos(HWND hWnd, UINT messg, WPARAM wParam, LPARAM lParam) {

	HDC hdc;
	RECT rect;
	PAINTSTRUCT ps;

	switch (messg) {
	case WM_PAINT:
		hdc = BeginPaint(hWnd, &ps);
		GetClientRect(hWnd, &rect);
		FillRect(hdc, &rect, CreateSolidBrush(RGB(0, 255, 0)));
		//SetTextColor(hdc, RGB(0, 123, 0));
		//SetBkColor(hdc, TRANSPARENT);

		//desenhar
		BitBlt(hdc, xBitmap, yBitmap, bmp.bmWidth, bmp.bmHeight, bmpDC, 0, 0, SRCCOPY);

		EndPaint(hWnd, &ps);
		break;

	case WM_SIZE:
		//lidar com o resize da janela
		//LOWORD(lParam) -> parte menos significativa, largura
		xBitmap = (LOWORD(lParam) / 2) - (bmp.bmWidth / 2);
		//LOWORD(lParam) -> parte mais significativa, altura
		yBitmap = (HIWORD(lParam) / 2) - (bmp.bmHeight / 2);
		break;

	case WM_CLOSE:
		if (
			MessageBox(
				hWnd,
				TEXT("tem a certeza que quer sair?"),
				TEXT("Confirmação"),
				MB_YESNO | MB_ICONQUESTION)
			== IDYES)
		{
			DestroyWindow(hWnd);
		}
		break;

	case WM_DESTROY:
		PostQuitMessage(0);
		break;

	default:
		return(DefWindowProc(hWnd, messg, wParam, lParam));
		break;
	}
	return(0);
}

Usar um BMP animado na janela (segunda versão):

#include <windows.h>
#include <tchar.h>
#include <windowsx.h>
//exercicio 6)
LRESULT CALLBACK TrataEventos(HWND, UINT, WPARAM, LPARAM);

TCHAR szProgName[] = TEXT("Base");

//lidar com o bitmap, globais: têm que ser acedidas por várias funções, ou uma struct 1 uma variavel global
HBITMAP hBMP; //acesso ao bitmap
HDC bmpDC;
BITMAP bmp; //estrutura do bitmap
int xBitmap;
int yBitmap;

//lidar com a animção
int limDireito;
HWND hWndGlobalJanela;

DWORD WINAPI MovimentaImagem(LPVOID lParam)
{
	int direcaoMovimento = 1; // 1: direita, -1: esquerda
	int saltoPixeis = 2;

	while (1)
	{
		xBitmap = xBitmap + (direcaoMovimento)*saltoPixeis;
		if (xBitmap <= 0)
		{
			xBitmap = 0;
			direcaoMovimento = 1;
		}
		else if (xBitmap >= limDireito)
		{
			xBitmap = limDireito;
			direcaoMovimento = -1;
		}
		//nova pintua da janela: avisar o SO
		InvalidateRect(hWndGlobalJanela, NULL, FALSE);
		Sleep(10);
	}
}


int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nCmdShow) {
	HWND hWnd;
	MSG lpMsg;
	WNDCLASSEX wcApp;

	wcApp.cbSize = sizeof(WNDCLASSEX);
	wcApp.hInstance = hInst;
	wcApp.lpszClassName = szProgName;
	wcApp.lpfnWndProc = TrataEventos;
	wcApp.style = CS_HREDRAW | CS_VREDRAW;
	wcApp.hIcon = LoadIcon(NULL, IDI_INFORMATION);
	wcApp.hIconSm = LoadIcon(NULL, IDI_INFORMATION);
	wcApp.hCursor = LoadCursor(NULL, IDC_ARROW);

	wcApp.lpszMenuName = NULL;
	wcApp.cbClsExtra = 0;
	wcApp.cbWndExtra = 0;
	wcApp.hbrBackground = CreateSolidBrush(RGB(0, 255, 0));

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

	hWnd = CreateWindow(
		szProgName,
		TEXT("Estudo para o exame"),
		WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT,
		CW_USEDEFAULT,
		800,
		600,
		(HWND)HWND_DESKTOP,
		(HMENU)NULL,
		(HINSTANCE)hInst,
		0);

	//lidar com o bitmap
	hBMP = (HBITMAP)LoadImage(NULL, TEXT("imagem.bmp"), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
	//preciso da informação da imagem (metadados)
	GetObject(hBMP, sizeof(bmp), &bmp);
	//passar a informação para o device content
	HDC hdc;
	hdc = GetDC(hWnd);
	//criar a copia
	bmpDC = CreateCompatibleDC(hdc);
	//aplicar o bitmap ao DC
	SelectObject(bmpDC, hBMP);
	ReleaseDC(hWnd, hdc);
	//definir as posições iniciais da imagem: ao centro
	RECT rect; //largura da janela actual do cliente
	GetClientRect(hWnd, &rect);
	//xBitmap = (rect.right / 2) - (bmp.bmWidth / 2);
	//yBitmap = (rect.bottom / 2) - (bmp.bmHeight / 2);
	
	//para o MovimentaImagem
	limDireito = rect.right - bmp.bmWidth;
	hWndGlobalJanela = hWnd;

	CreateThread(NULL, 0, MovimentaImagem, NULL, 0, NULL);
	
	ShowWindow(hWnd, nCmdShow);
	UpdateWindow(hWnd);

	while (GetMessage(&lpMsg, NULL, 0, 0)) {
		TranslateMessage(&lpMsg);
		DispatchMessage(&lpMsg);
	}
	return((int)lpMsg.wParam);
}

LRESULT CALLBACK TrataEventos(HWND hWnd, UINT messg, WPARAM wParam, LPARAM lParam) {

	HDC hdc;
	RECT rect;
	PAINTSTRUCT ps;

	switch (messg) {
	case WM_PAINT:
		hdc = BeginPaint(hWnd, &ps);
		GetClientRect(hWnd, &rect);
		FillRect(hdc, &rect, CreateSolidBrush(RGB(0, 255, 0)));
		//SetTextColor(hdc, RGB(0, 123, 0));
		//SetBkColor(hdc, TRANSPARENT);

		//desenhar
		BitBlt(hdc, xBitmap, yBitmap, bmp.bmWidth, bmp.bmHeight, bmpDC, 0, 0, SRCCOPY);

		EndPaint(hWnd, &ps);
		break;

	case WM_SIZE:
		//lidar com o resize da janela
		//LOWORD(lParam) -> parte menos significativa, largura
		xBitmap = (LOWORD(lParam) / 2) - (bmp.bmWidth / 2);
		//LOWORD(lParam) -> parte mais significativa, altura
		yBitmap = (HIWORD(lParam) / 2) - (bmp.bmHeight / 2);
		//a ver com a animação, update
		limDireito = LOWORD(lParam) - bmp.bmWidth;
		break;

	case WM_CLOSE:
		if (
			MessageBox(
				hWnd,
				TEXT("tem a certeza que quer sair?"),
				TEXT("Confirmação"),
				MB_YESNO | MB_ICONQUESTION)
			== IDYES)
		{
			DestroyWindow(hWnd);
		}
		break;

	case WM_DESTROY:
		PostQuitMessage(0);
		break;

	default:
		return(DefWindowProc(hWnd, messg, wParam, lParam));
		break;
	}
	return(0);
}

Esta é a segunda revisão destes conteúdos (desenhar animado e lidar com a concorrência):

#include <windows.h>
#include <tchar.h>
#include <windowsx.h>
//exercicio 6)
LRESULT CALLBACK TrataEventos(HWND, UINT, WPARAM, LPARAM);

TCHAR szProgName[] = TEXT("Base");

//lidar com o bitmap, globais: têm que ser acedidas por várias funções, ou uma struct 1 uma variavel global
HBITMAP hBMP; //acesso ao bitmap
HDC bmpDC;
BITMAP bmp; //estrutura do bitmap
int xBitmap;
int yBitmap;

//lidar com a animação
int limDireito;
HWND hWndGlobalJanela;

//concorrencia, problema de sincronização
HANDLE hMutex;

DWORD WINAPI MovimentaImagem(LPVOID lParam)
{
	int direcaoMovimento = 1; // 1: direita, -1: esquerda
	int saltoPixeis = 2;

	while (1)
	{
		WaitForSingleObject(hMutex, INFINITE); //problema de sincronização
		xBitmap = xBitmap + (direcaoMovimento)*saltoPixeis;
		
		if (xBitmap <= 0)
		{
			xBitmap = 0;
			direcaoMovimento = 1;
		}
		else if (xBitmap >= limDireito)
		{
			xBitmap = limDireito;
			direcaoMovimento = -1;
		}
		ReleaseMutex(hMutex);
		
		//nova pintua da janela: avisar o SO
		InvalidateRect(hWndGlobalJanela, NULL, FALSE);
		Sleep(10);
	}
}


int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nCmdShow) {
	HWND hWnd;
	MSG lpMsg;
	WNDCLASSEX wcApp;

	wcApp.cbSize = sizeof(WNDCLASSEX);
	wcApp.hInstance = hInst;
	wcApp.lpszClassName = szProgName;
	wcApp.lpfnWndProc = TrataEventos;
	wcApp.style = CS_HREDRAW | CS_VREDRAW;
	wcApp.hIcon = LoadIcon(NULL, IDI_INFORMATION);
	wcApp.hIconSm = LoadIcon(NULL, IDI_INFORMATION);
	wcApp.hCursor = LoadCursor(NULL, IDC_ARROW);

	wcApp.lpszMenuName = NULL;
	wcApp.cbClsExtra = 0;
	wcApp.cbWndExtra = 0;
	wcApp.hbrBackground = CreateSolidBrush(RGB(0, 255, 0));

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

	hWnd = CreateWindow(
		szProgName,
		TEXT("Estudo para o exame"),
		WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT,
		CW_USEDEFAULT,
		800,
		600,
		(HWND)HWND_DESKTOP,
		(HMENU)NULL,
		(HINSTANCE)hInst,
		0);

	//lidar com o bitmap
	hBMP = (HBITMAP)LoadImage(NULL, TEXT("imagem.bmp"), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
	//preciso da informação da imagem (metadados)
	GetObject(hBMP, sizeof(bmp), &bmp);
	//passar a informação para o device content
	HDC hdc;
	hdc = GetDC(hWnd);
	//criar a copia
	bmpDC = CreateCompatibleDC(hdc);
	//aplicar o bitmap ao DC
	SelectObject(bmpDC, hBMP);
	ReleaseDC(hWnd, hdc);
	//definir as posições iniciais da imagem: ao centro
	RECT rect; //largura da janela actual do cliente
	GetClientRect(hWnd, &rect);
	//xBitmap = (rect.right / 2) - (bmp.bmWidth / 2);
	//yBitmap = (rect.bottom / 2) - (bmp.bmHeight / 2);
	
	//para o MovimentaImagem
	limDireito = rect.right - bmp.bmWidth;
	hWndGlobalJanela = hWnd;

	hMutex = CreateMutex(NULL, FALSE, NULL);
	CreateThread(NULL, 0, MovimentaImagem, NULL, 0, NULL);
	
	ShowWindow(hWnd, nCmdShow);
	UpdateWindow(hWnd);

	while (GetMessage(&lpMsg, NULL, 0, 0)) {
		TranslateMessage(&lpMsg);
		DispatchMessage(&lpMsg);
	}
	return((int)lpMsg.wParam);
}

LRESULT CALLBACK TrataEventos(HWND hWnd, UINT messg, WPARAM wParam, LPARAM lParam) {

	HDC hdc;
	RECT rect;
	PAINTSTRUCT ps;

	switch (messg) {
	case WM_PAINT:
		hdc = BeginPaint(hWnd, &ps);
		GetClientRect(hWnd, &rect);
		FillRect(hdc, &rect, CreateSolidBrush(RGB(0, 255, 0)));
		//SetTextColor(hdc, RGB(0, 123, 0));
		//SetBkColor(hdc, TRANSPARENT);

		//desenhar
		WaitForSingleObject(hMutex, INFINITE); //problema de sincronização
		BitBlt(hdc, xBitmap, yBitmap, bmp.bmWidth, bmp.bmHeight, bmpDC, 0, 0, SRCCOPY);
		ReleaseMutex(hMutex);
		
		EndPaint(hWnd, &ps);
		break;

	case WM_SIZE:
		//lidar com o resize da janela
		//LOWORD(lParam) -> parte menos significativa, largura

		WaitForSingleObject(hMutex, INFINITE); //problema de sincronização
		xBitmap = (LOWORD(lParam) / 2) - (bmp.bmWidth / 2);
		ReleaseMutex(hMutex);
		//LOWORD(lParam) -> parte mais significativa, altura
		yBitmap = (HIWORD(lParam) / 2) - (bmp.bmHeight / 2);
		//a ver com a animação, update
		limDireito = LOWORD(lParam) - bmp.bmWidth;
		break;

	case WM_CLOSE:
		if (
			MessageBox(
				hWnd,
				TEXT("tem a certeza que quer sair?"),
				TEXT("Confirmação"),
				MB_YESNO | MB_ICONQUESTION)
			== IDYES)
		{
			DestroyWindow(hWnd);
		}
		break;

	case WM_DESTROY:
		PostQuitMessage(0);
		break;

	default:
		return(DefWindowProc(hWnd, messg, wParam, lParam));
		break;
	}
	return(0);
}

Esta é a segunda revisão destes conteúdos (desenhar animado e lidar com a concorrência e lidar com a flickering cintilação) com uso do doubleBuffering:

#include <windows.h>
#include <tchar.h>
#include <windowsx.h>
//exercicio 6)
LRESULT CALLBACK TrataEventos(HWND, UINT, WPARAM, LPARAM);

TCHAR szProgName[] = TEXT("Base");

HBITMAP hBMP; 
HDC bmpDC;
BITMAP bmp;
int xBitmap;
int yBitmap;

int limDireito;
HWND hWndGlobalJanela;

HANDLE hMutex;

//1) lidar com o flickering 
HDC memDC = NULL;
HBITMAP hCopiaBMP; //copiar as caracteristicas

DWORD WINAPI MovimentaImagem(LPVOID lParam)
{
	int direcaoMovimento = 1; 
	int saltoPixeis = 2;

	while (1)
	{
		WaitForSingleObject(hMutex, INFINITE);
		xBitmap = xBitmap + (direcaoMovimento)*saltoPixeis;
		
		if (xBitmap <= 0)
		{
			xBitmap = 0;
			direcaoMovimento = 1;
		}
		else if (xBitmap >= limDireito)
		{
			xBitmap = limDireito;
			direcaoMovimento = -1;
		}
		ReleaseMutex(hMutex);
		
		InvalidateRect(hWndGlobalJanela, NULL, FALSE);
		Sleep(10);
	}
}


int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nCmdShow) {
	HWND hWnd;
	MSG lpMsg;
	WNDCLASSEX wcApp;

	wcApp.cbSize = sizeof(WNDCLASSEX);
	wcApp.hInstance = hInst;
	wcApp.lpszClassName = szProgName;
	wcApp.lpfnWndProc = TrataEventos;
	wcApp.style = CS_HREDRAW | CS_VREDRAW;
	wcApp.hIcon = LoadIcon(NULL, IDI_INFORMATION);
	wcApp.hIconSm = LoadIcon(NULL, IDI_INFORMATION);
	wcApp.hCursor = LoadCursor(NULL, IDC_ARROW);

	wcApp.lpszMenuName = NULL;
	wcApp.cbClsExtra = 0;
	wcApp.cbWndExtra = 0;
	wcApp.hbrBackground = CreateSolidBrush(RGB(0, 255, 0));

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

	hWnd = CreateWindow(
		szProgName,
		TEXT("Estudo para o exame"),
		WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT,
		CW_USEDEFAULT,
		800,
		600,
		(HWND)HWND_DESKTOP,
		(HMENU)NULL,
		(HINSTANCE)hInst,
		0);
	
	hBMP = (HBITMAP)LoadImage(NULL, TEXT("imagem.bmp"), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
	
	GetObject(hBMP, sizeof(bmp), &bmp);
	
	HDC hdc;
	hdc = GetDC(hWnd);
	
	bmpDC = CreateCompatibleDC(hdc);
	
	SelectObject(bmpDC, hBMP);
	ReleaseDC(hWnd, hdc);

	RECT rect;
	GetClientRect(hWnd, &rect);
		
	limDireito = rect.right - bmp.bmWidth;
	hWndGlobalJanela = hWnd;

	hMutex = CreateMutex(NULL, FALSE, NULL);
	CreateThread(NULL, 0, MovimentaImagem, NULL, 0, NULL);
	
	ShowWindow(hWnd, nCmdShow);
	UpdateWindow(hWnd);

	while (GetMessage(&lpMsg, NULL, 0, 0)) {
		TranslateMessage(&lpMsg);
		DispatchMessage(&lpMsg);
	}
	return((int)lpMsg.wParam);
}

LRESULT CALLBACK TrataEventos(HWND hWnd, UINT messg, WPARAM wParam, LPARAM lParam) {

	HDC hdc;
	RECT rect;
	PAINTSTRUCT ps;

	switch (messg) {
	case WM_PAINT:
		hdc = BeginPaint(hWnd, &ps);
		GetClientRect(hWnd, &rect);
		
		//2) lidar com o flickering
		if(memDC == NULL)
		{
			//primeiro vez que estou a passar pela memoria
			//criar a cópia
			memDC = CreateCompatibleDC(hdc);
			hCopiaBMP = CreateCompatibleBitmap(hdc, rect.right, rect.bottom);
			SelectObject(memDC, hCopiaBMP);
			DeleteObject(hCopiaBMP);
		}

		//3) usar a copia em memoria e nao na principal
		//FillRect(hdc, &rect, CreateSolidBrush(RGB(0, 255, 0)));
		FillRect(memDC, &rect, CreateSolidBrush(RGB(0, 255, 0)));

		WaitForSingleObject(hMutex, INFINITE); 
		//BitBlt(hdc, xBitmap, yBitmap, bmp.bmWidth, bmp.bmHeight, bmpDC, 0, 0, SRCCOPY);
		BitBlt(memDC, xBitmap, yBitmap, bmp.bmWidth, bmp.bmHeight, bmpDC, 0, 0, SRCCOPY);
		ReleaseMutex(hMutex);

		//4) escrever a copia em memoria e aplicar na totalidade da janela
		BitBlt(hdc, 0, 0, rect.right, rect.bottom, memDC, 0, 0, SRCCOPY);
		
		EndPaint(hWnd, &ps);
		break;

	case WM_SIZE:

		WaitForSingleObject(hMutex, INFINITE);
		xBitmap = (LOWORD(lParam) / 2) - (bmp.bmWidth / 2);
		yBitmap = (HIWORD(lParam) / 2) - (bmp.bmHeight / 2);
		limDireito = LOWORD(lParam) - bmp.bmWidth;
		//5) para obrigar a entrar no if no WM_PAINT
		ReleaseDC(hWnd, memDC);
		memDC = NULL;
		
		ReleaseMutex(hMutex);
		break;

	case WM_CLOSE:
		if (
			MessageBox(
				hWnd,
				TEXT("tem a certeza que quer sair?"),
				TEXT("Confirmação"),
				MB_YESNO | MB_ICONQUESTION)
			== IDYES)
		{
			DestroyWindow(hWnd);
		}
		break;

	case WM_DESTROY:
		PostQuitMessage(0);
		break;

	default:
		return(DefWindowProc(hWnd, messg, wParam, lParam));
		break;
	}
	return(0);
}

Tags : , , , , ,

sessão 10 – Programação gráfica orientada a eventos (os recursos win32)

O uso de recursos vem ajudar a construir elementos gráficos e sem ter que os desenhar!

Para fazer uso, é adicionar a um projeto vazio o recurso:

Existem vários tipos:

Sendo que uma das primeiras opções podem ser o Icon:

O ícone pode ser desenhado, pelo que é recomendado que primeiro se eliminem os que já existem, quando faltar um, adicionamos um vazio de 24 bits para termos o máximo de cores disponíveis, e de seguida voltamos a eliminar o ultimo ícone que ficou e que existia por defeito.

 

Usando a barra de desenho no topo podemos alterar este ícone

 

Nas propriedades podemos alterar o nome do ID, por exemplo para IDI_ICON_APP

Outro recurso pode ser o uso de menus..

Nas propriedades podemos indicar que as opções na barra de menus sejam de ação ao invés de mostrar outras opções no menu:
Popup -> FALSE

As caixa de diálgo:

E as opções das caixas de diálogo:
Static Text
Edit Control
Button
Accelerator (para lidar com as teclas de atalho)
String Table
(…)

Nos Accelerator são definidas os comportamentos das teclas de atalho:

As Strings table (definir ID e definir um texto para eles):

e ainda o cursor, sendo que no final:

e os comportamentos dos componentes..

um exemplo:

#include <windows.h>
#include <Windowsx.h>
#include <tchar.h>
#include "resource.h" //importante para acesso aos IDs..

#define NUM_CLIENTES 3
#define LIST_SIZE 8

TCHAR* LIST_ITENS[] = {
	TEXT("10€"),
	TEXT("20€"),
	TEXT("40€"),
	TEXT("60€"),
	TEXT("80€"),
	TEXT("100€"),
	TEXT("150€"),
	TEXT("200€")
};

//três soluções para tratamentos de eventos de janelas: dialog boxes
LRESULT CALLBACK TrataEventos(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK TrataEventosLogin(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK TrataEventosLevantar(HWND, UINT, WPARAM, LPARAM);

TCHAR szProgName[] = TEXT("Ficha8");

typedef struct {
	unsigned int ID;
	TCHAR username[16];
	TCHAR password[16];
	unsigned int saldo;
} cliente;

typedef struct {
	unsigned int tipo; // 1 = depósito, 2 = levantamento
	unsigned int quantia;
	unsigned int ID;
} operacao;

//estrutura agreagadora para nao usar variaveis globais
typedef struct {
	cliente clientes[NUM_CLIENTES];
	operacao historico[200];
	unsigned int numOperacoes;
} dados;

int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nCmdShow)
{
	HWND hWnd;
	MSG lpMsg;
	WNDCLASSEX wcApp;
	HANDLE hAccel;
	dados dadosPartilhados;

	wcApp.cbSize = sizeof(WNDCLASSEX);
	wcApp.hInstance = hInst;

	wcApp.lpszClassName = szProgName;
	wcApp.lpfnWndProc = TrataEventos;

	wcApp.style = CS_HREDRAW | CS_VREDRAW;

	wcApp.hIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_ICON_APP)); // ID
	wcApp.hIconSm = LoadIcon(hInst, MAKEINTRESOURCE(IDI_ICON_APP));
	wcApp.hCursor = LoadCursor(hInst, MAKEINTRESOURCE(IDC_POINTER));
	wcApp.lpszMenuName = MAKEINTRESOURCE(IDR_MENU_PRINCIPAL);

	wcApp.cbClsExtra = sizeof(dados); //janela tem espaço extra
	wcApp.cbWndExtra = 0;
	wcApp.hbrBackground = CreateSolidBrush(RGB(220, 220, 220));

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

	hWnd = CreateWindow(
		szProgName,
		TEXT("SO2 - win 32"),
		WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT,
		CW_USEDEFAULT,
		300,
		150,
		(HWND)HWND_DESKTOP,
		(HMENU)NULL,
		(HINSTANCE)hInst,
		0);

	dadosPartilhados.numOperacoes = 5; // Apenas para testar...
	LONG_PTR x = SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)&dadosPartilhados); //obter da janela bytes da struct de dados

	ShowWindow(hWnd, nCmdShow);


	//processamento dos atalhos
	hAccel = LoadAccelerators(NULL, MAKEINTRESOURCE(IDR_ACCELERATOR));

	while (GetMessage(&lpMsg, NULL, 0, 0))
	{
		if (!TranslateAccelerator(hWnd, hAccel, &lpMsg))
		{
			TranslateMessage(&lpMsg);
			DispatchMessage(&lpMsg);
		}
	}

	return((int)lpMsg.wParam);
}

LRESULT CALLBACK TrataEventos(HWND hWnd, UINT messg, WPARAM wParam, LPARAM lParam)
{
	TCHAR str1[512], str2[512];
	dados* dadosPartilhados;

	dadosPartilhados = (dados*)GetWindowLongPtr(hWnd, GWLP_USERDATA);

	switch (messg)
	{
	case WM_CREATE:
		EnableMenuItem(GetMenu(hWnd), ID_CONSULTA, MF_DISABLED | MF_GRAYED);
		EnableMenuItem(GetMenu(hWnd), ID_LEVANTAMENTO, MF_DISABLED | MF_GRAYED);
		break;

	case WM_COMMAND:

		switch (LOWORD(wParam))
		{
		case ID_LOGIN:

			DialogBox(NULL, MAKEINTRESOURCE(IDD_DIALOG_LOGIN), hWnd, TrataEventosLogin);
			EnableMenuItem(GetMenu(hWnd), ID_CONSULTA, MF_ENABLED); //ficam disponiveis
			EnableMenuItem(GetMenu(hWnd), ID_LEVANTAMENTO, MF_ENABLED); //ficam disponiveis
			break;

		case ID_CONSULTA:
		case ID_ACCELERATOR_C:

			LoadString(NULL, IDS_STR_CONSULTA, str1, 512);
			_stprintf_s(str2, 512, TEXT("%s (%d)"), str1, dadosPartilhados->numOperacoes);
			MessageBox(hWnd, str2, TEXT("String Table"), MB_OK | MB_ICONINFORMATION);
			break;

		case ID_ACCELERATOR_L:
		case ID_LEVANTAMENTO:

			DialogBox(NULL, MAKEINTRESOURCE(IDD_DIALOG_LEVANTAMENTO), NULL, TrataEventosLevantar);
			break;

		}

		break;

	case WM_DESTROY:
		PostQuitMessage(0);
		break;

	default:
		return DefWindowProc(hWnd, messg, wParam, lParam);
		break;
	}

	return(0);
}

LRESULT CALLBACK TrataEventosLogin(HWND hWnd, UINT messg, WPARAM wParam, LPARAM lParam)
{
	TCHAR username[16];

	switch (messg)
	{
		//lidar com clique no menu
	case WM_COMMAND:

		if (LOWORD(wParam) == IDOK)
		{
			GetDlgItemText(hWnd, IDC_LEVANTAMENTO_LOGIN, username, 16);
			MessageBox(hWnd, username, TEXT("Username"), MB_OK | MB_ICONINFORMATION);
		}
		else if (LOWORD(wParam) == IDCANCEL)
		{
			EndDialog(hWnd, 0);
			return TRUE;
		}

		break;

	case WM_CLOSE:

		EndDialog(hWnd, 0);
		return TRUE;
	}

	return FALSE;
}

LRESULT CALLBACK TrataEventosLevantar(HWND hWnd, UINT messg, WPARAM wParam, LPARAM lParam)
{
	int i;

	switch (messg)
	{
	case WM_INITDIALOG:

		HWND hwndList = GetDlgItem(hWnd, IDC_LIST_MONTANTES);
		SendMessage(hwndList, LB_RESETCONTENT, 0, 0);

		for (i = 0; i < LIST_SIZE; i++)
			SendMessage(hwndList, LB_ADDSTRING, 0, (LPARAM)LIST_ITENS[i]);

		break;

	case WM_COMMAND:

		if (LOWORD(wParam) == IDC_LIST_MONTANTES)
		{
			switch (HIWORD(wParam))
			{
			case LBN_DBLCLK:

				HWND hwndList = GetDlgItem(hWnd, IDC_LIST_MONTANTES);
				i = (int)SendMessage(hwndList, LB_GETCURSEL, 0, 0);
				MessageBox(hWnd, LIST_ITENS[i], TEXT("ListBox"), MB_OK | MB_ICONINFORMATION);

				break;
			}
		}

		break;

	case WM_CLOSE:

		EndDialog(hWnd, 0);
		return TRUE;
	}

	return FALSE;
}
Tags : , , , , ,

sessão 10 – Programação gráfica orientada a eventos

Referências bibliográficas:
Capítulos 2-5 e 7-9 do Livro Windows NT 4 Programming
MSDN:
Introduction to Windows Programming in C++
https://msdn.microsoft.com/en-us/library/ff381398(v=vs.85).aspx
Mouse Input
https://msdn.microsoft.com/en-us/library/gg153549(v=vs.85).aspx
Keyboard Input
https://msdn.microsoft.com/en-us/library/gg153546(v=vs.85).aspx
Mouse Movement
https://msdn.microsoft.com/en-us/library/gg153550(v=vs.85).aspx
Dialog Boxes
https://msdn.microsoft.com/en-us/library/windows/desktop/ms632588(v=vs.85).aspx
Menus
https://msdn.microsoft.com/en-us/library/windows/desktop/ms646977(v=vs.85).aspx
Windows Graphics Device Interface (GDI)
https://msdn.microsoft.com/en-us/library/dd145203(v=vs.85).aspx
Tutorial online: Win32 Fundamentals
http://www.functionx.com/win32/Lesson01.htm
Events
http://www.functionx.com/win32/Lesson05.htm
Object-Oriented Win32
http://www.functionx.com/win32/Lesson06.htm

Como começar?
no visualstudio 2019, podemos começar com uma aplicação normal de consola.
alterar de projeto gráfico nas propriedades


um exemplo de um ficheiro base:

nclude <windows.h>
#include <tchar.h>

/* ===================================================== */
/* Programa base (esqueleto) para aplicações Windows     */
/* ===================================================== */
// Cria uma janela de nome "Janela Principal" e pinta fundo de branco
// Modelo para programas Windows:
//  Composto por 2 funções: 
//	WinMain()     = Ponto de entrada dos programas windows
//			1) Define, cria e mostra a janela
//			2) Loop de recepção de mensagens provenientes do Windows
//     TrataEventos()= Processamentos da janela (pode ter outro nome)
//			1) É chamada pelo Windows (callback) 
//			2) Executa código em função da mensagem recebida

LRESULT CALLBACK TrataEventos(HWND, UINT, WPARAM, LPARAM);

// Nome da classe da janela (para programas de uma só janela, normalmente este nome é 
// igual ao do próprio programa) "szprogName" é usado mais abaixo na definição das 
// propriedades do objecto janela
TCHAR szProgName[] = TEXT("Base");

// ============================================================================
// FUNÇÃO DE INÍCIO DO PROGRAMA: WinMain()
// ============================================================================
// Em Windows, o programa começa sempre a sua execução na função WinMain()que desempenha
// o papel da função main() do C em modo consola WINAPI indica o "tipo da função" (WINAPI
// para todas as declaradas nos headers do Windows e CALLBACK para as funções de
// processamento da janela)
// Parâmetros:
//   hInst: Gerado pelo Windows, é o handle (número) da instância deste programa 
//   hPrevInst: Gerado pelo Windows, é sempre NULL para o NT (era usado no Windows 3.1)
//   lpCmdLine: Gerado pelo Windows, é um ponteiro para uma string terminada por 0
//              destinada a conter parâmetros para o programa 
//   nCmdShow:  Parâmetro que especifica o modo de exibição da janela (usado em  
//        	   ShowWindow()

int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nCmdShow) {
  HWND hWnd;		// hWnd é o handler da janela, gerado mais abaixo por CreateWindow()
  MSG lpMsg;		// MSG é uma estrutura definida no Windows para as mensagens
  WNDCLASSEX wcApp;	// WNDCLASSEX é uma estrutura cujos membros servem para 
			// definir as características da classe da janela

  // ============================================================================
  // 1. Definição das características da janela "wcApp" 
  //    (Valores dos elementos da estrutura "wcApp" do tipo WNDCLASSEX)
  // ============================================================================
  wcApp.cbSize = sizeof(WNDCLASSEX);      // Tamanho da estrutura WNDCLASSEX
  wcApp.hInstance = hInst;		         // Instância da janela actualmente exibida 
						         // ("hInst" é parâmetro de WinMain e vem 
		                               // inicializada daí)
  wcApp.lpszClassName = szProgName;       // Nome da janela (neste caso = nome do programa)
  wcApp.lpfnWndProc = TrataEventos;       // Endereço da função de processamento da janela
                                          // ("TrataEventos" foi declarada no início e
                                          // encontra-se mais abaixo)
  wcApp.style = CS_HREDRAW | CS_VREDRAW;  // Estilo da janela: Fazer o redraw se for
                                          // modificada horizontal ou verticalmente

  wcApp.hIcon = LoadIcon(NULL, IDI_APPLICATION);   // "hIcon" = handler do ícon normal
							             // "NULL" = Icon definido no Windows
							             // "IDI_AP..." Ícone "aplicação"
  wcApp.hIconSm = LoadIcon(NULL, IDI_INFORMATION); // "hIconSm" = handler do ícon pequeno
							             // "NULL" = Icon definido no Windows
							             // "IDI_INF..." Ícon de informação
  wcApp.hCursor = LoadCursor(NULL, IDC_ARROW);	// "hCursor" = handler do cursor (rato) 
							// "NULL" = Forma definida no Windows
							// "IDC_ARROW" Aspecto "seta" 
  wcApp.lpszMenuName = NULL;			// Classe do menu que a janela pode ter
							// (NULL = não tem menu)
  wcApp.cbClsExtra = 0;				// Livre, para uso particular
  wcApp.cbWndExtra = 0;				// Livre, para uso particular
  wcApp.hbrBackground =(HBRUSH)GetStockObject(WHITE_BRUSH); 
  // "hbrBackground" = handler para "brush" de pintura do fundo da janela. Devolvido por
  // "GetStockObject".Neste caso o fundo será branco

  // ============================================================================
  // 2. Registar a classe "wcApp" no Windows
  // ============================================================================
  if (!RegisterClassEx(&wcApp))
     return(0);	

  // ============================================================================
  // 3. Criar a janela
  // ============================================================================
    hWnd = CreateWindow(
	szProgName,			// Nome da janela (programa) definido acima
	TEXT("Exemplo de Janela Principal em C"),// Texto que figura na barra do título
	WS_OVERLAPPEDWINDOW,	// Estilo da janela (WS_OVERLAPPED= normal)
	CW_USEDEFAULT,		// Posição x pixels (default=à direita da última)
	CW_USEDEFAULT,		// Posição y pixels (default=abaixo da última)
	CW_USEDEFAULT,		// Largura da janela (em pixels)
	CW_USEDEFAULT,		// Altura da janela (em pixels)
	(HWND) HWND_DESKTOP,	// handle da janela pai (se se criar uma a partir de
					// outra) ou HWND_DESKTOP se a janela for a primeira, 
					// criada a partir do "desktop"
	(HMENU) NULL,			// handle do menu da janela (se tiver menu)
	(HINSTANCE) hInst,		// handle da instância do programa actual ("hInst" é 
					// passado num dos parâmetros de WinMain()
	0);				// Não há parâmetros adicionais para a janela
  // ============================================================================
  // 4. Mostrar a janela
  // ============================================================================
  ShowWindow(hWnd, nCmdShow);	// "hWnd"= handler da janela, devolvido por 
					// "CreateWindow"; "nCmdShow"= modo de exibição (p.e. 
					// normal/modal); é passado como parâmetro de WinMain()
  UpdateWindow(hWnd);		// Refrescar a janela (Windows envia à janela uma 
					// mensagem para pintar, mostrar dados, (refrescar)… 
  // ============================================================================
  // 5. Loop de Mensagens
  // ============================================================================
  // O Windows envia mensagens às janelas (programas). Estas mensagens ficam numa fila de
  // espera até que GetMessage(...) possa ler "a mensagem seguinte"	
  // Parâmetros de "getMessage":
  // 1)"&amp;lpMsg"=Endereço de uma estrutura do tipo MSG ("MSG lpMsg" ja foi declarada no  
  //   início de WinMain()):
  //			HWND hwnd		handler da janela a que se destina a mensagem
  //			UINT message		Identificador da mensagem
  //			WPARAM wParam		Parâmetro, p.e. código da tecla premida
  //			LPARAM lParam		Parâmetro, p.e. se ALT também estava premida
  //			DWORD time		Hora a que a mensagem foi enviada pelo Windows
  //			POINT pt		Localização do mouse (x, y) 
  // 2)handle da window para a qual se pretendem receber mensagens (=NULL se se pretendem
  //   receber as mensagens para todas as
  // janelas pertencentes à thread actual)
  // 3)Código limite inferior das mensagens que se pretendem receber
  // 4)Código limite superior das mensagens que se pretendem receber

  // NOTA: GetMessage() devolve 0 quando for recebida a mensagem de fecho da janela,
  // 	  terminando então o loop de recepção de mensagens, e o programa 

  while (GetMessage(&amp;lpMsg,NULL,0,0)) {	
     TranslateMessage(&amp;lpMsg);	// Pré-processamento da mensagem (p.e. obter código 
					// ASCII da tecla premida)
     DispatchMessage(&amp;lpMsg);	// Enviar a mensagem traduzida de volta ao Windows, que
					// aguarda até que a possa reenviar à função de 
					// tratamento da janela, CALLBACK TrataEventos (abaixo)
  }

  // ============================================================================
  // 6. Fim do programa
  // ============================================================================
  return((int)lpMsg.wParam);	// Retorna sempre o parâmetro wParam da estrutura lpMsg
}

// ============================================================================
// FUNÇÃO DE PROCESSAMENTO DA JANELA
// Esta função pode ter um nome qualquer: Apenas é necesário que na inicialização da
// estrutura "wcApp", feita no início de // WinMain(), se identifique essa função. Neste
// caso "wcApp.lpfnWndProc = WndProc"
//
// WndProc recebe as mensagens enviadas pelo Windows (depois de lidas e pré-processadas
// no loop "while" da função WinMain()
// Parâmetros:
//		hWnd	O handler da janela, obtido no CreateWindow()
//		messg	Ponteiro para a estrutura mensagem (ver estrutura em 5. Loop...
//		wParam	O parâmetro wParam da estrutura messg (a mensagem)
//		lParam	O parâmetro lParam desta mesma estrutura
//
// NOTA:Estes parâmetros estão aqui acessíveis o que simplifica o acesso aos seus valores
//
// A função EndProc é sempre do tipo "switch..." com "cases" que descriminam a mensagem
// recebida e a tratar.
// Estas mensagens são identificadas por constantes (p.e. 
// WM_DESTROY, WM_CHAR, WM_KEYDOWN, WM_PAINT...) definidas em windows.h
// ============================================================================

LRESULT CALLBACK TrataEventos(HWND hWnd, UINT messg, WPARAM wParam, LPARAM lParam) {	
  switch (messg) {	
    case WM_DESTROY:	// Destruir a janela e terminar o programa 
                        // "PostQuitMessage(Exit Status)"		
	PostQuitMessage(0);
	break;		
    default:
      // Neste exemplo, para qualquer outra mensagem (p.e. "minimizar","maximizar","restaurar")
      // não é efectuado nenhum processamento, apenas se segue o "default" do Windows
      return(DefWindowProc(hWnd,messg,wParam,lParam));
      break;  // break tecnicamente desnecessário por causa do return
  }
  return(0);
}

uma unica janela e com a informação persistente..

#include <windows.h>
#include <tchar.h>
#include <windowsx.h>

LRESULT CALLBACK TrataEventos(HWND, UINT, WPARAM, LPARAM);

TCHAR szProgName[] = TEXT("Base");

//main
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nCmdShow) {
	HWND hWnd;		
	MSG lpMsg;		
	WNDCLASSEX wcApp;
	//caracteristicas especificas de todas as janelas, comuns:
	// o ícone, título, cor de fundo, localização

	wcApp.cbSize = sizeof(WNDCLASSEX);
	wcApp.hInstance = hInst;
	wcApp.lpszClassName = szProgName;
	wcApp.lpfnWndProc = TrataEventos;
									
	wcApp.style = CS_HREDRAW | CS_VREDRAW; 
	wcApp.hIcon = LoadIcon(NULL, IDI_WARNING);   
	wcApp.hIconSm = LoadIcon(NULL, IDI_SHIELD); 
	wcApp.hCursor = LoadCursor(NULL, IDC_ARROW );	
	wcApp.lpszMenuName = NULL;			
	wcApp.cbClsExtra = 0;				
	wcApp.cbWndExtra = 0;				
	//wcApp.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
	wcApp.hbrBackground = CreateSolidBrush(RGB(0, 255, 0));
	
	if (!RegisterClassEx(&wcApp))
		return(0);

	//caracteristicas especificas de cada Janela!!! -> CreateWindow
	hWnd = CreateWindow(
		szProgName,			
		TEXT("S02 - Exercício 01"),
		WS_OVERLAPPEDWINDOW,
		200, // Posição x pixels
		200, // Posição y pixels
		600, // Largura da janela (em pixels)
		600, // Altura da janela (em pixels)
		(HWND)HWND_DESKTOP,	
		(HMENU)NULL,		
		(HINSTANCE)hInst,
		0);				
	ShowWindow(hWnd, nCmdShow);
	UpdateWindow(hWnd);		

	//ciclo que mantem o programa a funcionar
	while (GetMessage(&lpMsg, NULL,0, 0)) {
		TranslateMessage(&lpMsg);	
		DispatchMessage(&lpMsg);	
	}
	return((int)lpMsg.wParam);	
}

//função que trata os eventos, chamada pelo sistema operativo
//esta função pode estar associada a diferentes janelas
//coleção de eventos: UINT messg

//TCHAR c = '?'; //global

//para guardar o historial dos desenhos
typedef struct
{
	int xPos;
	int yPos;
	TCHAR c;
} PosChar;

LRESULT CALLBACK TrataEventos(HWND hWnd, UINT messg, WPARAM wParam, LPARAM lParam) {
	HDC hdc;
	RECT rect;
	//int xPos, yPos;
	//static int xPos, yPos; //serem globais ou static para serem presistentes
	static PosChar posicoes[500]; //array de posições
	static int totalPos = 0;
	int i;
	
	static TCHAR chardAtual = '?'; //ou local

	PAINTSTRUCT ps;
	
	switch (messg) {
		//evento que é sempre disparado qd acontece o refresh!
		//todas as operações que escrevem na janela têm que surgir aqui WM_PAINT
		//todas as operaçõe de escrita é aqui WM_PAINT
	case WM_PAINT:
		hdc = BeginPaint(hWnd, &ps); //inicio de escrita na janela
		//deseho
		//hdc = GetDC(hWnd);
		GetClientRect(hWnd, &rect); //toda a area do cliente
		FillRect(hdc, &rect, CreateSolidBrush(RGB(0, 255, 0))); //fundo da janela
		SetTextColor(hdc, RGB(255, 0, 255));
		SetBkMode(hdc, TRANSPARENT);
		
		for (i = 0; i < totalPos; i++) {
			rect.left = posicoes[i].xPos;
			rect.top = posicoes[i].yPos;
			DrawText(hdc, &posicoes[i].c, 1, &rect, DT_SINGLELINE | DT_NOCLIP);
		}
		
		//ReleaseDC(hWnd, hdc);
		EndPaint(hWnd, &ps); //fim de escrita na janela
		break;

	//ignorar a limpeza do fundo, depois é usado o FillRect no WM_PAINT
	case WM_ERASEBKGND:
		return TRUE;
		
	/*case WM_PAINT:
		for(auto i : ops)
		{
			hdc = GetDC(hWnd);

			GetClientRect(hWnd, &rect);
			rect.bottom = i.xPos;
			rect.top = i.yPos;

			SetTextColor(hdc, RGB(0, 0, 0));
			SetBkMode(hdc, TRANSPARENT);

			DrawText(hdc, &i.pChar, 1, &rect, DT_SINGLELINE | DT_NOCLIP);

			ReleaseDC(hWnd, hdc);
		}
		
		break;
		*/

		
	case WM_LBUTTONDOWN:
		//xPos = GET_X_LPARAM(lParam); //#include <windowsx.h>
		//yPos = GET_Y_LPARAM(lParam); //#include <windowsx.h>
		if(totalPos<500){
			posicoes[totalPos].xPos = GET_X_LPARAM(lParam); //#include <windowsx.h>
			posicoes[totalPos].yPos = GET_Y_LPARAM(lParam); //#include <windowsx.h>
			posicoes[totalPos].c = chardAtual;
			totalPos++;
			InvalidateRect(hWnd, NULL, FALSE); //refresh da janela, ajuda a lidar com o fundo
		}

		////deseho
		//hdc = GetDC(hWnd);
		//GetClientRect(hWnd, &rect);
		//SetTextColor(hdc, RGB(255, 0, 255));
		//SetBkMode(hdc, TRANSPARENT);
		//rect.left = xPos;
		//rect.top = yPos;
		//DrawText(hdc, &c, 1, &rect, DT_SINGLELINE | DT_NOCLIP);
		//ReleaseDC(hWnd, hdc);
		
		break;
	case WM_CHAR:
		chardAtual = (TCHAR)wParam;
		break;
		
	case WM_CLOSE:
			if(
			MessageBox(hWnd,
			TEXT("Tem a certeza que quer sair?"),
			TEXT("Confirmação"), 
			MB_YESNO | MB_ICONQUESTION) == IDYES)
			{
			DestroyWindow(hWnd);
			}
		break;
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	default:
		return(DefWindowProc(hWnd, messg, wParam, lParam));
		break;  
	}
	return(0);
}

lidar com animações e com o flickering / oscilante

#include <windows.h>
#include <tchar.h>
#include <windowsx.h>

LRESULT CALLBACK TrataEventos(HWND, UINT, WPARAM, LPARAM);

TCHAR szProgName[] = TEXT("Base");

//(todas elas vão ser inicializadas na main, e não podem ser usadas variaveis estáticas)
//mas podia estar dentro de uma estrutura
//handle/acesso para o bitmap
HBITMAP hBmp;
//handle para o device content, o que vai permitir passar o bmp para este formato
HDC bmpDC;
//informação sobre a estrutura do bitmap (pe: largura e altura..)
BITMAP bmp;
//posição da imagem
int xBitmap;
int yBitmap;

//ou isto assim agora ou criar uma estrutura!
int limDireitoJanela;
HWND hWandGlobal;

//lidar com o flikring a centilação e lidar com os acesso concorrentes: mutex
HANDLE hMutex;


//lidar com a copia em memoria, double buffering
HDC memoriaCopiaDC = NULL;
HBITMAP hCopiaBitMap;//vai copiar as caracteristicas para a copia


//crair uma thread para lidar com as animações/tempo que passa
DWORD WINAPI movimentaImagem(LPVOID param)
{
	int direcaoMovimento = 1; //1, direita e -1,  esquerda
	int salto = 2; //salto de posições em termos de pixeis

	while(1)
	{
		WaitForSingleObject(hMutex, INFINITE);
		xBitmap = xBitmap + (direcaoMovimento * salto);
		if(xBitmap <=0)
		{
			xBitmap = 0;
			direcaoMovimento = 1;
		}
		else if(xBitmap >= limDireitoJanela)
		{
			xBitmap = limDireitoJanela;
			direcaoMovimento = -1;
		}
		ReleaseMutex(hMutex);
		
		//temos sempre que avisar o sistema para fazer uma nova pintura da janela
		InvalidateRect(hWandGlobal, NULL, FALSE);

		Sleep(1);
	}
}


int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nCmdShow) {
	HWND hWnd;
	MSG lpMsg;
	WNDCLASSEX wcApp;
	//caracteristicas especificas de todas as janelas, comuns:
	// o ícone, título, cor de fundo, localização

	wcApp.cbSize = sizeof(WNDCLASSEX);
	wcApp.hInstance = hInst;
	wcApp.lpszClassName = szProgName;
	wcApp.lpfnWndProc = TrataEventos;

	wcApp.style = CS_HREDRAW | CS_VREDRAW;
	wcApp.hIcon = LoadIcon(NULL, IDI_WARNING);
	wcApp.hIconSm = LoadIcon(NULL, IDI_SHIELD);
	wcApp.hCursor = LoadCursor(NULL, IDC_ARROW);
	wcApp.lpszMenuName = NULL;
	wcApp.cbClsExtra = 0;
	wcApp.cbWndExtra = 0;
	//wcApp.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
	wcApp.hbrBackground = CreateSolidBrush(RGB(0, 255, 0));

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

	//caracteristicas especificas de cada Janela!!! -> CreateWindow
	hWnd = CreateWindow(
		szProgName,
		TEXT("S02 - Exercício 01"),
		WS_OVERLAPPEDWINDOW,
		200, // Posição x pixels
		200, // Posição y pixels
		600, // Largura da janela (em pixels)
		600, // Altura da janela (em pixels)
		(HWND)HWND_DESKTOP,
		(HMENU)NULL,
		(HINSTANCE)hInst,
		0);

	//aqui vem a a informação do bitmap
	//1º carregar o bitmap (124x124)
	hBmp = LoadImage(NULL, TEXT("flag.bmp"), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
	//ir buscar informações sobre o recurso, carregar os metadados da imagem
	GetObject(hBmp, sizeof(bmp), &bmp);
	//passar do handle da imagem para o device content
	HDC hdc;
	hdc = GetDC(hWnd);
	//criar uma copia
	bmpDC = CreateCompatibleDC(hdc); //devolve um novo handle
	//aplicar o bitmap ao device content
	SelectObject(bmpDC, hBmp);
	//fechar o device content da janela
	ReleaseDC(hWnd, hdc);

	//definir as posições iniciais da imagem, e centrar por exemplo
	RECT rect;
	GetClientRect(hWnd, &rect);
	//xBitmap = (LARGURA_JANELA / 2) - (bmp.bmWidth/2);
	//yBitmap = (ALTURA_JANELA / 2) - (bmp.bmHeight / 2);
	xBitmap = (rect.right / 2) - (bmp.bmWidth/2);
	yBitmap = (rect.bottom / 2) - (bmp.bmHeight / 2);
	//escrever a imagem no tratamento de eventos..

	//definir o que é o limite dieito
	limDireitoJanela = rect.right - bmp.bmWidth;
	hWandGlobal = hWnd;

	hMutex = CreateMutex(NULL, FALSE, NULL);
	
	//criar a thread
	CreateThread(NULL, 0, movimentaImagem, NULL, 0, NULL);
	
	
	ShowWindow(hWnd, nCmdShow);
	UpdateWindow(hWnd);

	//ciclo que mantem o programa a funcionar
	while (GetMessage(&lpMsg, NULL, 0, 0)) {
		TranslateMessage(&lpMsg);
		DispatchMessage(&lpMsg);
	}
	return((int)lpMsg.wParam);
}




LRESULT CALLBACK TrataEventos(HWND hWnd, UINT messg, WPARAM wParam, LPARAM lParam) {
	HDC hdc;
	RECT rect;
	PAINTSTRUCT ps;

	switch (messg) {
	
	case WM_PAINT:
		hdc = BeginPaint(hWnd, &ps); //inicio de escrita na janela
		GetClientRect(hWnd, &rect); //toda a area do cliente
		
		//fazer a copia para o buffering
		if(memoriaCopiaDC == NULL)
		{
			//ainda nao foi feita a copia em memoria
			//criar a copia
			memoriaCopiaDC = CreateCompatibleDC(hdc);
			//obter as caracteristicas, copia figdigna mas falta lidar com o resize..
			hCopiaBitMap = CreateCompatibleBitmap(hdc, rect.right, rect.bottom);
			SelectObject(memoriaCopiaDC, hCopiaBitMap);
			DeleteObject(hCopiaBitMap); //libertar recursos
		}		
		
		//FillRect(hdc, &rect, CreateSolidBrush(RGB(0, 255, 0))); //fundo da janela
		FillRect(memoriaCopiaDC, &rect, CreateSolidBrush(RGB(0, 255, 0))); //fundo da janela

		WaitForSingleObject(hMutex, INFINITE);
		//BitBlt(hdc, xBitmap, yBitmap, bmp.bmWidth, bmp.bmHeight, bmpDC, 0, 0, SRCCOPY);
		BitBlt(memoriaCopiaDC, xBitmap, yBitmap, bmp.bmWidth, bmp.bmHeight, bmpDC, 0, 0, SRCCOPY);
		//SRCCOPY copiar a totalidade dos pixeis
		ReleaseMutex(hMutex); // resolver problemas do xBitmap, yBitmap

		//vai ser necessário copiar para a principal
		BitBlt(hdc,0,0, rect.right, rect.bottom, memoriaCopiaDC, 0, 0, SRCCOPY);

		EndPaint(hWnd, &ps);
		break;
		
	//lidar com o resize da janela, redimensionamento da janela
	case WM_SIZE:
		WaitForSingleObject(hMutex, INFINITE);
		//LOWORD(lParam) -> menos significativa representa a largura
		//HIWORD(lParam) -> mais significativa representa a altura
		xBitmap = (LOWORD(lParam) / 2) - (bmp.bmWidth / 2);
		yBitmap = (HIWORD(lParam) / 2) - (bmp.bmHeight / 2);
		//temos tb que ajusatr o limite da janela
		limDireitoJanela = LOWORD(lParam) - bmp.bmWidth;

		//libterar o memoriaCopiaDC
		ReleaseDC(hWnd, memoriaCopiaDC);
		memoriaCopiaDC = NULL;
		
		ReleaseMutex(hMutex);
		break;

		
	case WM_ERASEBKGND:
		return TRUE;
	
	case WM_CLOSE:
		if (
			MessageBox(hWnd,
				TEXT("Tem a certeza que quer sair?"),
				TEXT("Confirmação"),
				MB_YESNO | MB_ICONQUESTION) == IDYES)
		{
			DestroyWindow(hWnd);
		}
		break;
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	default:
		return(DefWindowProc(hWnd, messg, wParam, lParam));
		break;
	}
	return(0);
}

Tags : , , , ,