=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
=-=[ 06 ]=-=[ Programando API em C++ para Windows, por Vo5 ]=-=-=-=-=-=-=-=-=-=
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
C++ API
Não vou dar noções básicas sobre C/C++.
A interface API (Application Program Interface) corresponde a um conjunto de
system calls oferecidas por um determinado sistema operacional. Neste caso,
Windows. A biblioteca API de Windows é extensa, contendo as mais variadas
funções. Não pretendo citar todas, mas sim as que eu considerar mais
importantes, mesmo assim, pretendo fazer um trabalho extenso. Para não tornar
essa matéria um tanto monótona, vou restringi-la à explicação à nível
superficial. Não entrarei em detalhes como estrutura das funções, pois isso
somente consumirá mais e mais bytes.
Um dos maiores atrativos do Windows é seu sistema de janelas, que permite ao
usuário navegar entre elas e coloca-las à disposição mais conveniente.
Programadores de VB sabem o quanto é fácil criar uma janela, mas em C++, isso
pode se tornar um processo que requer alguns procedimentos iniciais.
Primeiramente vamos analisar a estrutura mais básica de um programa Win32 em C++:
#include
int _stdcall WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR nCmdLine, int nCmdShow)
{
return 0;
}
Para manter compatibilidade, a função é declarada como _stdcall, porém em alguns
compiladores pode estar definida como WINAPI ou outras macros. A função WinMain
tem como objetivo definir o inicio do programa. É relativamente semelhante à
função main, só que é executada em contexto Win32 hehe. Os parâmetros são bem
simples:
Antes, o int de retorno: Da mesma maneira que a função main(), quando a função
WinMain() retornar um valor, esta finalizará o programa.
HINSTANCE: a HINSTANCE representa um valor de 32 bit´s que identifica um objeto
no sistema. O sistema operacional passa este valor para o aplicativo para
identificar o aplicativo enquanto ele está sendo executado e o libera quando o
aplicativo é finalizado.
A primeira HINSTANCE (hInstance) refere-se ao valor de identificação passado ao
aplicativo. A segunda (hPrevInstance) refere-se á um valor curioso, é nela que
vc recebe o valor da HINSTANCE de outra instância de seu aplicativo, dessa
maneira você pode monitorar se seu aplicativo está sendo executado mais de uma
vez e bloquear as instanciações de seu programa, caso o programa esteja sendo
executado primariamente, esse valor passa a ser NULL.
LPSTR é uma implementação de char*. nCmdLine corresponde á linha de comando
passada ao seu aplicativo, ou, aos parâmetros á ele passados. Como um simples
exemplo posso citar o Internet Explorer. A linha de comando á ele passada
corresponde à página que será exibida.
nCmdShow corresponde a um valor identificando o estado inicial da janela, é
recomendável que esse valor seja passado como 2º parâmetro de ShowWindow().
Aí está o ponto de entrada para qualquer programa Win32. Como esse tutorial tem
como foco a criação de um programa Win32, iremos direto ao ponto: Como criar uma
simples janela?
A API do Windows fornece uma estrutura que descreve os comportamentos padrões
para qualquer janela. Um tópico importante, é que num ambiente de programação em
C++ todas as classes e estruturas são consideradas como objetos. Essa visão se
traduz no Windows quando falamos sobre janelas e controles.
Tanto uma janela quanto um controle são objetos primários na construção de um
aplicativo Win32, e, pela analise do Windows, são iguais.
Uma janela corresponde à uma área (geralmente retangular) num espaço virtual
conhecido como desktop, não seria correto afirmar que um controle não passa de
uma janela dentro de um espaço conhecido como outra janela qualquer?
É assim que você deve interpretar janelas e controles, não como estruturas que
diferem entre si, mas estruturas semelhantes entre si.
A API do Windows fornece uma estrutura básica para qualquer janela, que,
geralmente em controles já é predefinida. Essa estrutura é conhecida como
WNDCLASS.
Como essa estrutura é pertencente à API do Win95, ficou atrasada para as
evoluções do software, assim sendo, foi criada uma estrutura equivalente, que
possui mais opções, a WNDCLASSEX.
Ao longo do tutorial, você verá muitas funções e estruturas que foram recriadas
com o sufixo EX, porém todas as funções e estruturas mais antigas prevalecem
ainda hoje. Por razões de compatibilidade vou citar mais as funções EX
(EXtended) do que as mais antigas.
A estrutura WNDCLASSEX possui os seguintes membros:
cbClsExtra – Corresponde à um valor em bytes que devem ser alocados depois da
WNDCLASSEX na memória, o Windows inicializa este valor como zero.
cbSize – Um unsigned int que corresponde ao tamanho da estrutura, geralmente um
sizeof(WNDCLASSEX) é suficiente ;]
cbWndExtra – Um valor que corresponde ao número de bytes que devem ser alocados
após a instância da janela, o Windows inicializa esse valor como zero, porém é
recomendável que este valor seja alterado para DLGWINDOWEXTRA caso você deseje
utilizar caixas de diálogos criadas com WNDCLASSEX.
hbrBackground – Um HBRUSH que corresponde ao fundo inicial da janela, geralmente
esse valor é igualado à um dos valores predefinidos do sistema, como
WINDOW_COLOR.
hCursor – Corresponde à um HCURSOR que representa o cursor que será exibido
dentro da janela.
hIcon – Corresponde ao Ícone grande a ser exibido representando a janela, como
no menu de alt+tab.
hIconSm – Corresponde ao ícone pequeno a ser exibido na barra de título da
janela.
hInstance – Corresponde à instância que identifica um objeto no sistema, esse
valor é passado ao programa para que ele não possa acessar objetos externos à
seu processo indevidamente. Deve-se atribuir à esse valor a hInstance que foi
passada à função WinMain.
lpfnWndProc – Corresponde à uma função que recebe as mensagens enviadas à
janela, em termos de leigo, corresponde à função responsável por gerenciar os
eventos que ocorrem dentro da janela.
lpszClassName – Corresponde à uma string que identifica a classe.
lpszMenuName – Corresponde à uma string que aponta para o nome de menu associado
à esta janela. Este tipo de menu é criado no arquivo de resources do aplicativo.
Caso o valor seja identificado como um inteiro no arquivo de resource, deve-se
utilizar a macro MAKEINTRESOURCE.
style – Corresponde à um comportamento padrão da janela.
Qualquer um destes membros pode ser validado como NULL, porém alguns são
essenciais na construção de uma janela. Agora vamos analisar algumas
peculiaridades de alguns deles.
A WNDCLASS não apresenta os seguintes valores: cbSize e hIconSm.
hbrBackground
Esta propriedade refere-se à um HBRUSH que identifica o tipo de fundo que uma
janela receberá. É recomendável que se utilize somente cores. Há valores padrões
do sistema que podem ser utilizados:
COLOR_ACTIVEBORDER
COLOR_ACTIVECAPTION
COLOR_APPWORKSPACE
COLOR_BACKGROUND
COLOR_BTNFACE
COLOR_BTNSHADOW
COLOR_BTNTEXT
COLOR_CAPTIONTEXT
COLOR_GRAYTEXT
COLOR_HIGHLIGHT
COLOR_HIGHLIGHTTEXT
COLOR_INACTIVEBORDER
COLOR_INACTIVECAPTION
COLOR_MENU
COLOR_MENUTEXT
COLOR_SCROLLBAR
COLOR_WINDOW
COLOR_WINDOWFRAME
COLOR_WINDOWTEXT
hCursor
Assim como hIcon e hIconSm, este valor pode ser criado no arquivo de resource,
porém há tipos predefinidos de cursors que podem ser carregados utilizando-se a
função LoadCursor, passando o primeiro valor (hInstance) como NULL e o segundo
como o valor a ser utilizado:
IDC_APPSTARTING
IDC_ARROW
IDC_CROSS
IDC_IBEAM
IDC_ICON
IDC_NO
IDC_SIZE
IDC_SIZEALL
IDC_SIZENESW
IDC_SIZENS
IDC_SIZENWSE
IDC_SIZEWE
IDC_UPARROW
IDC_WAIT
hIcon e hIconSm
Podem ser carregados valores do sistema utilizando-se a função LoadCursor,
passando o primeiro valor como NULL e o segundo como o valor a ser utilizado:
IDI_APPLICATION
IDI_ASTERISK
IDI_EXCLAMATION
IDI_HAND
IDI_QUESTION
IDI_WINLOGO
lpfnWndProc
O Window Procedure é uma função responsável por gerenciar as mensagens recebidas
em uma janela. A sintaxe do Window Procedure é:
LRESULT CALLBACK WinProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
O valor de retorno corresponde a um long.
HWND é um unsigned int que corresponde ao valor do window handle, ou seja, um
valor utilizado para a manipulação da janela.
Msg corresponde ao valor numérico da mensagem recebida pela janela, wParam
corresponde à um DWORD com valores passados à Msg, o mesmo vale para lParam.
style
Define estilos padrões que alteram a performance da janela:
CS_BYTEALIGNCLIENT e CS_BYTEALIGNWINDOW
Alinham a janela em um determinado contexto na posição horizontal para melhorar
a performance em operações gráficas. Estes estilos afetam a posição horizontal e
largura da janela. Não é muito utilizado
CS_CLASSDC
Aloca um DC para ser utilizado por todas as janelas da classe. É utilizado para
diminuir o tempo de espera em operações gráficas. Este estilo permite que
somente uma janela manipule operações gráficas por vez
CS_DBLCLKS
Permite que a janela receba mensagens sobre cliques duplos (DblClick)
CS_GLOBALCLASS
Permite que uma janela seja criada sem a necessidade que a hInstance da classe
seja a mesma da janela. É utilizada em controles que são inicializados em DLLs
CS_HREDRAW e CS_VREDRAW
Redesenha toda a janela caso esta seja modificada horizontalmente ou
verticalmente respectivamente. Tanto vale para movimentações como para reajustes
de tamanho
CS_NOCLOSE
Desabilita todas as opções naturais para se fechar uma janela
CS_OWNDC
Aloca um DC único para cada janela da classe
CS_PARENTDC
Permite que janelas Child possam realizar operações gráficas em suas janelas
pai. Essa opção aumenta a performance de operações gráficas, já que uma janela
dessa classe recebe um cachê de memória maior para alocar seu DC
CS_SAVEBITS
Caso uma janela seja parcialmente obscurecida por outra janela, essa opção salva
a parte obscurecida como um bitmap na memória para aumentar a rapidez no
processo de redesenhar a janela, porém um certo tempo é perdido para alocar o
bitmap. Essa opção não é recomendada
DC´s serão explicados mais tarde.
Operações gráficas referem-se ao ato de desenhar uma janela ou controle ou
outras funções GDI.
Um simples exemplo da construção de uma WNDCLASSEX:
WNDCLASSEX wnd;
wnd.cbClsExtra = 0;
wnd.cbSize = sizeof(WNDCLASSEX);
wnd.cbWndExtra = 0;
wnd.hbrBackground = (HBRUSH)(COLOR_WINDOW);
wnd.hCursor = LoadCursor(NULL,IDC_ARROW);
wnd.hIcon = LoadIcon(NULL,IDI_APPLICATION);
wnd.hIconSm = LoadIcon(NULL,IDI_APPLICATION);
wnd.hInstance = hInstance;
wnd.lpfnWndProc = (WNDPROC) WProc;
wnd.lpszClassName = "MainWnd";
wnd.lpszMenuName = NULL;
wnd.style = CS_OWNDC;
Programadores mais "avançados" podem estudar a sintaxe da WNDCLASSEX e montá-la
em somente uma linha de código ;]
Bom, após a criação da WNDCLASSEX, deve-se registrá-la para que possa ser
utilizada pelos threads do processo em execução. Isso se faz com o auxílio da
função RegisterClassEx.
RegisterClassEx(&wnd);
O único parâmetro é o endereço da WNDCLASSEX a ser registrada. Logicamente há
seu equivalente para a WNDCLASS:
RegisterClass(&WNDCLASS);
Estas funções retornam um valor (ATOM) que identifica unicamente a classe no
sistema. Caso haja erro, o valor de retorno é 0.
Bom, e agora? Agora vamos a parte principal, a tão esperada função que realmente
cria a janela, a CreateWindow(Ex).
A CreateWindowEX() possui 12 parâmetros, enquanto que a CreateWindow() possui
11, sendo assim elas só diferem no parâmetro dwExStyle, que, logicamente,
pertence à CreateWindowEx e não à CreateWindow.
Vamos dar uma olhada nos seus parâmetros:
dwExStyle – Esse valor é uma DWORD (int de 32 bit´s para os mais leigos) que
relata à função alguns comportamentos extendidos referentes à janela. Veremos
seus possíveis valores mais à frente.
lpClassName – Esse valor refere-se ao nome da WNDCLASS registrada, ou seja deve
ser o mesmo que lpszClassName da classe registrada.
lpWindowName – Um valor que na maioria das vezes serve como string primária da
janela.
dwtyle – Comportamentos padrões das janelas.
x e y – int´s que definem as posições horizontal e vertical (respectivamente) da
janela (Left e Top).
nWidth e nHeight – int´s que definem a largura e a altura da janela
(respectivamente) (Width e Height).
hWndParent – Corresponde à um HWND (calma aí) que identifica a janela pai da
janela a ser criada. É recomendável que este valor não seja NULL, assim sendo,
para janelas comuns, deve-se utilizar a função GetDesktopWindow(void); como
parâmetro para este valor.
hMenu – Identifica um Menu criado em API pertencente à esta janela.
HInstance – Use sua imaginação ;]
lpParam – Há muito esse parâmetro deixou de ser utilizado. Seu valor consiste em
uma estrutura que contêm todos os valores acima citados e estes da função são
substituídos pelos desta estrutura. Perda de memória, não? ;/
O valor de retorno corresponde à um HWND. O HWND, ou Window Handle, é um valor
de 32 bit´s que identifica uma janela para que esta possa ser manipulada por
diversas funções. Caso a função falhe, o retorno é NULL. Em API, toda função,
quando retorna um erro, pode ter esse valor de erro re-adquirido com a função
GetLastError(void), que retorna uma DWORD (int) com o valor de retorno da função
que retornou o erro.
Os possíveis valores para dwExStyle são:
WS_EX_ACCEPTFILES
Esta janela aceita arquivos arrastados até ela
WS_EX_CLIENTEDGE
Cria uma borda interna à área interna da janela
WS_EX_CONTEXTHELP
Inclui o botão de interrogação na barra de título da janela
WS_EX_CONTROLPARENT
Permite que seja possível navegar entre as janelas child desta janela
utilizando-se a tecla TAB
WS_EX_DLGMODALFRAME
Cria bordas em janelas com o valor WS_POPUP em dwStyle
WS_EX_LEFT e WS_EX_RIGHT
Cria uma janela que possui propriedades de texto alinhado à esquerda (padrão) ou
à direita, respectivamente
WS_EX_LEFTSCROLLBAR e WS_EX_RIGHTSCROLLBAR
Se a barra de rolagem estiver visível na janela, essas opções definem seu
alinhamento, à esquerda ou à direita (padrão) respectivamente
WS_EX_LTRREADING e WS_EX_RTLREADING
O texto da janela é apresentado da ordem especificada, esquerda-para-direita
(padrão) ou direita-para-esquerda. O segundo valor só funciona em línguas que
possuem suporte para este tipo de escrita, como o Hebraico
WS_EX_MDICHILD
Cria uma janela child
WS_EX_NOPARENTNOTIFY
Especifica que uma janela child não irá notificar sua janela-pai sobre sua
criação ou destruição
WS_EX_OVERLAPPEDWINDOW
Combina WS_EX_CLIENTEDGE e WS_EX_WINDOWEDGE
WS_EX_PALETTEWINDOW
Combina WS_EX_WINDOWEDGE, WS_EX_TOOLWINDOW e WS_EX_TOPMOST
WS_EX_STATICEDGE
Cria uma janela com uma borda (interna) em sua área externa, geralmente
utilizados em controles estáticos
WS_EX_TOOLWINDOW
Cria uma janela geralmente utilizada como janela de ferramentas, com uma borda e
fonte de título menores que o original. Esse tipo de janela não aparece na barra
de tarefas ou no menu de ALT+TAB
WS_EX_TOPMOST
Especifica que a janela deve sempre sobrepor as janelas que não possuem este
valor
WS_EX_TRANSPARENT
Cria uma janela 100% transparente (não translúcida ;|). Este tipo de janela é
comumente utilizado em operações de realinhamento de janela. Este tipo de janela
não é, geralmente, utilizado por aplicativos
WS_EX_WINDOWEDGE
Cria uma janela com uma borda (externa) em sua área externa
Para x,y, nWidth e nHeight, o sistema provê valores padrões que podem ser
utilizados igualando estes valores à CW_USEDEFAULT.
Os possíveis valores de dwStyle:
WS_BORDER
Cria uma janela com uma borda fina
WS_CAPTION
Cria uma janela com uma barra de título e WS_BORDER
WS_CHILD e WS_CHILDWINDOW
Cria uma janela child. Este valor não pode ser mesclado com WS_POPUP
WS_CLIPCHILDREN
Exclui a área ocupada pelas janelas child quando uma janela receber uma mensagem
WM_PAINT (operação gráfica). Esse valor deve ser utilizado em janelas pai
WS_CLIPSIBLINGS
Esse valor evita alguns problemas gráficos com janelas child. Você mesmo poderá
fazer um teste utilizandp 2 janelas child, uma com este valor e outra sem,
coloque uma sobre a outra e mude-as de tamanho e posição ;]
WS_DISABLED
Cria uma janela desabilitada. Esse tipo de janela não recebe entrada do usuário
WS_DLGFRAME
Cria uma borda que é comumente utilizada em caixas de diálogo
WS_GROUP
Especifica o primeiro controle em um grupo de controles
WS_HSCROLL e WS_VSCROLL
Cria uma janela que possui uma barra de rolagem horizontal e/ou vertical
(respectivamente)
WS_ICONIC e WS_MINIMIZE
Cria uma janela que está inicialmente minimizada
WS_MAXIMIZE
Cria uma janela que está inicialmente maximizada
WS_MAXIMIZEBOX e WS_MINIMIZEBOX
Cria uma janela que possui um botão de maximizar e/ou minimizar (respectivamente)
WS_OVERLAPPED e WS_TILED
Cria uma janela que possui uma borda e uma barra de titulo
WS_OVERLAPPEDWINDOW e WS_TILEDWINDOW
Cria uma janela num estilo mais comum mesclando WS_OVERLAPPED, WS_CAPTION,
WS_SYSMENU, WS_THICKFRAME, WS_MINIMIZEBOX e WS_MAXIMIZEBOX
WS_POPUP
Cria uma janela popup, sem bordas ou barra de titulo
WS_POPUPWINDOW
Mescla WS_BORDER, WS_POPUP e WS_SYSMENU
WS_SIZEBOX e WS_THICKFRAME
Cria uma janela que possui uma barra de reajuste de tamanho
WS_SYSMENU
Cria uma janela com um menu de janela comum. O valor WS_CAPTION é recomendado
WS_TABSTOP
Especifica um controle que pode receber o foco quando o usuário pressiona a
tecla TAB
WS_VISIBLE
Cria uma janela que esta inicialmente visível
Exemplo =D:
HWND MainWnd = CreateWindowEx(WS_EX_WINDOWEDGE,"MainWnd","Janela de exemplo",
WS_OVERLAPPEDWINDOW,120,150, CW_USEDEFAULT,450,GetDesktopWindow(),NULL,hInstance,NULL);
Uma simples verificação:
If(!MainWnd){PostQuitMessage(0);}
A função PostQuitMessage(int) finaliza o programa terminando o seu Message Loop
que será visto adiante.
Após a criação da janela, se esta não houver sido criada com WS_SHOW, é
necessário mostrá-la. Para isso utiliza-se ShowWindow(HWND, int).
Exemplo:
ShowWindow(MainWnd,SW_SHOWNORMAL);
Os valores do 2º parâmetro são:
SW_HIDE - Esconde a janela e passa o foco para a próxima janela
SW_MAXIMIZE - Maximiza a janela e recebe o foco
SW_MINIMIZE – Minimiza a janela e recebe o foco
SW_RESTORE - Restaura a janela a seu status padrão e recebe o foco
SW_SHOW – Mostra a janela e recebe o foco
SW_SHOWMAXIMIZED, SW_SHOWMINIMIZED – Mostra a janela e a maximiza ou minimiza
(respectivamente)
SW_SHOWMINNOACTIVE – Minimiza a janela e não recebe foco
SW_SHOWNA – Mostra a janela em seu estado atual, não recebe o foco
SW_SHOWNOACTIVE – Mostra a janela em sua posição e tamanho recentes, não recebe
o foco
SW_SHOWNORMAL – Mostra a janela, faz o mesmo que SW_RESTORE e recebe o foco
nCmdShow – Isso mesmo, este é o valor passado ao aplicativo por WinMain, que
pode ser utilizado como valor padrão para o inicio das janelas do aplicativo.
O valor de retorno é um bool. Caso a janela estivesse anteriormente escondida, o
valor de retorno é false (0), caso contrário é true (1).
É comum utilizar também UpdateWindow(HWND); para redesenhar a janela após
mostra-la:
UpdateWindow(MainWnd);
Caso a função falhe, o valor de retorno (bool) é false.
A partir daqui, caso você deseje que função subseqüentes sejam realizadas, pode
incluí-las no código.
Após tudo isso você pensa que acabamos com a WinMain???
Lembra-se que quando a função retorna um valor ou chega ao seu fim o programa
termina? Então, como os programas Win32 rodam por tempo indefinido?
Simples, com a utilização de um pequeno artifício chamado Message Loop.
O Message Loop, como seu nome sugere, consiste em um loop no qual uma mensagem é
analisada e enviada à janela. O loop consiste em 3 funções simples:
GetMessage(&MSG,HWND,unsigned int, unsigned int);
TranslateMessage(&MSG);
DispatchMessage(&MSG)
O MSG corresponde à um valor que identifica uma mensagem de sistema.
Sintáxe comum de um message loop:
MSG msg;
while ( GetMessage(&msg,NULL,0,0) )
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
Um sistema de mensagens é um artifício do sistema operacional para coordenar a
comunicação entre processos e não será abordado aqui.
A descrição do loop é simples:
while ( GetMessage(&msg,NULL,0,0) )
Esse linha simplesmente cria um loop no qual a função GetMessage pega a primeira
mensagem na fila de mensagens do thread atual. O fato de que as mensagens
correspondem ao thread atual e não à uma janela especifica provêm de que o
segundo parâmetro é neutro, e assim deve permanecer, pois, caso uma janela seja
descrita, com o fechamento de tal janela o aplicativo todo seria finalizado de
maneira indesejável.
O valor de retorno (bool), é true em casos normais, é false quando é processada
uma mensagem WM_QUIT (Assim como a enviada por PostQuitMessage()) e –1 quando a
função falha.
Caso você feche a janela descrita em HWND, a função retornaria –1 para o while
gerando, assim, um erro fatal ao aplicativo. Por estas razões, no message loop,
HWND deve sempre ser NULL.
O 3º parâmetro indica a primeira mensagem na fila e o 2º, a última. Estes
valores devem ser 0 para que as mensagens sejam processadas assim que chegarem à
fila.
TranslateMessage(&msg);
Essa função traduz mensagens que apresentam códigos virtuais para código ASCII.
Tais mensagens são geralmente enviadas somente pelo teclado.
DispatchMessage(&msg);
Essa função envia a mensagem para a WindowProc responsável pela janela que
recebeu a mensagem.
Após o message loop, pode-se incluir normalmente o return ;]
return 0;
Aí está uma simples WinMain. Agora, vamos à WindowProc, que analisará as
mensagens enviadas para a janela. Como já vimos, a sintaxe do Window Procedure
é:
LRESULT CALLBACK WinProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
E o valor de retorno corresponde a um long.
O primeiro parâmetro da função corresponde ao HWND da janela responsável por
receber a mensagem. O segundo, à mensagem em si, o terceiro e o quarto à demais
parâmetros da mensagem.
O método mais comum de se trabalhar com o WinProc é dando um switch e
verificando as mensagens enviadas:
LRESULT CALLBACK WinProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
switch(msg) {
case WM_DESTROY:{
PostQuitMessage(1);
}
case WM_CREATE:{
FazAlgumaCoisa();
}
}
return DefWindowProc(hWnd,msg,wParam,lParam);
}
As mensagens aí enviadas correspondem, respectivamente, à quando a janela é
finalizada e criada.
DefWindowProc corresponde à uma função que recepta as mensagens que não são
processadas pela WinProc. Os parâmetros são os mesmos da WinProc. Essa função
garante que todas as mensagens sejam receptadas de maneira correta.
return 0; geralmente funciona também ;]
As mensagens mais comuns são citadas a seguir com seus respectivos eventos:
WM_ACTIVATE
OnActivate, OnGetFocus, OnEnter
WM_ACTIVATEAPP, WM_KILLFOCUS
OnLostFocus, OnExit, OnDeactivate
WM_CLOSE
OnClose
WM_COPY
OnCopy
WM_CREATE
OnCreate, OnLoad
WM_CUT
OnCut
WM_DESTROY
OnDestroy
WM_ENABLE
OnEnable
WM_HELP
OnHelp
WM_KEYDOWN
OnKeyDown
WM_KEYUP
OnKeyUp
WM_KILLFOCUS
OnLostFocus, OnExit, OnDeactivate
WM_LBUTTONDNLCLK
OnDblClick (Botão esquerdo)
WM_LBUTTONDOWN
OnMouseDown (Botão esquerdo)
WM_LBUTTONUP
OnMouseUp (Botão esquerdo)
WM_MBUTTONDBLCLK
OnDblClick (Botão do meio)
WM_MBUTTONDOWN
OnMouseDown (Botão do meio)
WM_MBUTTONUP
OnMouseUp (Botão do meio)
WM_MOUSEMOVE
OnMouseMove
WM_MOUSEWHEEL
OnMouseWheel
WM_MOVE
OnMoved
WM_MOVING
OnMove
WM_PAINT
OnPaint, OnRepaint
WM_PASTE
OnPaste
WM_QUIT
OnTerminate
WM_RBUTTONDNLCLK
OnDblClick (Botão direito)
WM_RBUTTONDOWN
OnMouseDown (Botão direito)
WM_RBUTTONUP
OnMouseUp (Botão direito)
WM_SETFOCUS
OnActivate, OnGetFocus, OnEnter
WM_SIZE
OnResized
WM_SIZING
OnResizing, OnResize
WM_TIMER
OnTimer
WM_UNDO
OnUndo
A partir daí você já está apto a monitorar suas próprias mensagens, mas, por
enquanto, vamos montar um simples programa que não faça nada menos do que aquilo
que aprendemos até agora, exceto o uso da função API SetWindowText(HWND,char *)
que modifica a string da barra de título da janela (Caption):
/*Programa simples de exemplo*/
#include
#pragma hdrstop //diretiva de pré-processador
LRESULT CALLBACK WinProc(HWND,UINT,WPARAM,LPARAM);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR nCmdLine,
int nCmdShow)
{
MSG msg;
WNDCLASSEX wnd;
wnd.cbClsExtra = 0;
wnd.cbSize = sizeof(WNDCLASSEX);
wnd.cbWndExtra = 0;
wnd.hbrBackground = (HBRUSH) COLOR_WINDOW;
wnd.hCursor = LoadCursor(NULL,IDC_ARROW);
wnd.hIcon = LoadIcon(NULL,IDI_APPLICATION);
wnd.hIconSm = LoadIcon(NULL,IDI_APPLICATION);
wnd.hInstance = hInstance;
wnd.lpfnWndProc = (WNDPROC) WinProc;
wnd.lpszClassName = "Janela";
wnd.lpszMenuName = NULL;
wnd.style = NULL;
if(!RegisterClassEx(&wnd)){PostQuitMessage(0);}
HWND handle = CreateWindowEx(NULL,"Janela","Janela de Exemplo",
WS_OVERLAPPEDWINDOW,150,150,300,300,GetDesktopWindow(),NULL,hInstance,NULL);
if(!handle){PostQuitMessage(0);}
ShowWindow(handle,nCmdShow);
UpdateWindow(handle);
while(GetMessage(&msg,NULL,0,0)){
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
LRESULT CALLBACK WinProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
switch(Msg){
case WM_RBUTTONDOWN:
SetWindowText(hWnd,"Clique direito");
break;
case WM_LBUTTONDOWN:
SetWindowText(hWnd,"Clique esquerdo");
break;
case WM_MBUTTONDOWN:
SetWindowText(hWnd,"Clique com botão do meio");
break;
case WM_MOVE:
SetWindowText(hWnd,"Janela movida");
break;
case WM_SIZE:
SetWindowText(hWnd,"Tamanho modificado");
break;
case WM_KEYDOWN:
SetWindowText(hWnd,"Tecla pressionada");
break;
case WM_DESTROY:
PostQuitMessage(0);
}
return DefWindowProc(hWnd,Msg,wParam,lParam);
}
/*Fim do programa!
Este programa foi compilado em Visual Studio 6.0. A macro WIN_32_LEAN_AND_MEAN
foi utilizada, embora não tenha sido citada aqui. O programa compilado está
disponível aqui e possui 152 KB.*/
Bom, agora você já sabe criar uma janela simples e manipular as principais
mensagens que podem vir a ocorrer. No próximo capítulo entraremos em detalhes
nos controles simples de Windows, e ainda veremos alguns parâmetros das
mensagens mais comuns e aprenderemos alguns truquezinhos ;]]
Xor´s para todos ;]