A Aldeia Numaboa ancestral ainda está disponível para visitação. É a versão mais antiga da Aldeia que eu não quis simplesmente descartar depois de mais de 10 milhões de pageviews. Como diz a Sirley, nossa cozinheira e filósofa de plantão: "Misericórdia, ai que dó!"

Se você tiver curiosidade, o endereço é numaboa.net.br.

Leia mais...

Tutoriais e Programação

Linguagem C - Projeto Espião

Sex

28

Nov

2008


13:20

(6 votos, média 4.33 de 5) 


C

Já que é para fazer alguma coisa, não vamos nos contentar com uma janelinha que mostre um texto qualquer quando o usuário clicar num botão ou num item de menu. Nananinanão! Queremos um projeto mais ambicioso!

Vamos chamar este projeto de espião porque a idéia é mostrar num controle tipo árvore todas as janelas que estejam abertas num dado momento. Além disso, vamos colocar na barra de status algumas informações sobre as janelas encontradas. E dá-lhe, peão!

Criando o projeto Espião

Você já está careca de saber: clicar em |Project|Create| etc e tal. Dê o nome de "espiao" ao projeto, só para ficar compatível com o texto do tutorial. Ah! também criei um novo diretório para o projeto, o /lcc/projects/espiao/. Se você fizer o mesmo, aí fica tudo par e passo.

Crie um "Windows application" tipo "Single user", com "Single window" e "Status bar at the bottom". Na verdade, com exceção do nome, é tudo igual ao tutorial Uma janela de verdade. Deste modo, obtemos o esqueleto do aplicativo.

Criando uma janela-filha

A primeira providência é criar uma janela para um controle de árvore - um controle do tipo do explorer. Para criar janelas deste tipo, uma boa pedida é aproveitar a mensagem WM_CREATE que o sistemão envia para a central de mensagens da janela principal. Para interceptá-la, basta inserir no switch do procedimento MainWndProc um caso de WM_CREATE:

LRESULT CALLBACK MainWndProc( HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) { static HWND hwndTree; switch (msg) { case WM_CREATE: hwndTree = janelaTree(hwnd,IDJANELATREE); break; ...

Acho que está na hora de dizer que a tradução de "switch", entre outras coisas, é "ligar/desligar", "interruptor" e "mudar para outro trilho". Depois disso, não é difícil imaginar o que faz um switch interruptor ou uma chave de trilhos wink

Esta arquitetura é chamada de "top down" (de cima para baixo) porque os detalhes da criação da janela da árvore ficam escondidos numa função que retorna o manipulador (handle) da janela criada. Este manipulador é armazenado numa variável estática do tipo HWND, a hwndTree. Esta variável, por ser local, só é pode ser acessada quando se está no procedimento MainWndProc e não conserva seu valor quando saímos dele.

A função janelaTree

A função janelaTree recebe o manipulador (handle) da janela-mãe e o identificador (ID) numérico que o controle da árvore deve ter. O identificador numérico, que chamamos de IDJANELATREE, precisa ser definido no início do código para que possamos utilizá-lo. Optei pelo valor 10545:

#include #include #include #include #include "espiaores.h" #define IDJANELATREE 10545 ...

Chamamos o procedimento de criação de janelas, a função da API CreateWindowsEx com uma série de parâmetros. Esta função é derivada da função CreateWindow, apenas permite estilos mais elaborados. Veja abaixo:

HWND CreateWindowEx( DWORD dwExStyle, // estilo de janela ampliado LPCTSTR lpClassName, // ponteiro para o nome da classe registrada LPCTSTR lpWindowName, // ponteiro para o nome da janela DWORD dwStyle, // estilo da janela int x, // posição horizontal da janela int y, // posição vertical da janela int nWidth, // largura da janela int nHeight, // altura da janela HWND hWndParent, // handle para a janela-mãe ou proprietária HMENU hMenu, // handle para o menu // ou identificador da janela-filha HINSTANCE hInstance, // handle para a instância do aplicativo LPVOID lpParam // ponteiro para os dados // para a criação da janela );

A referência a esta função você encontra no help da API. Se você o instalou, basta posicionar o cursor sobre o nome da função e digitar F1. Conhecendo os parâmetros exigidos por CreateWindowEx, podemos elaborar a função que cria a janela da árvore:

static HWND _stdcall janelaTree(HWND hWnd,int ID) { return CreateWindowEx(WS_EX_CLIENTEDGE,WC_TREEVIEW,"", WS_VISIBLE|WS_CHILD|WS_BORDER|TVS_HASLINES| TVS_HASBUTTONS|TVS_DISABLEDRAGDROP, 0,0,0,0, hWnd,(HMENU)ID,hInst,NULL); }

Abaixo são analisados os parâmetros enviados:

  • DWORD dwExStyle: enviamos WS_EX_CLIENTEDGE para obter uma janela com as bordas rebaixadas. O valor de WS_EXCLIENTEDGE é 512.
  • LPCTSTR lpClassName: ponteiro para o nome da classe de controle predefinido no Windows, o WC_TREEVIEW.
  • LPCTSTR lpWindowName: ponteiro vazio para o nome da janela.
  • DWORD dwStyle: enviamos o estilo WS_VISIBLE|WS_CHILD|WS_BORDER|TVS_HASLINES| TVS_HASBUTTONS|TVS_DISABLEDRAGDROP, ou seja, uma sucessão de ORs ligando os bits para a janela visível (WS_VISIBLE = 0x10000000), do tipo janela-filha (WS_CHILD = 0x40000000), com borda de linha fina (WS_BORDER = 0x800000), do estilo da tree-view com linhas (TVS_HASLINES = 2), com botões (TVS_HASBUTTONS = 1) e desabilitando clicar e arrastar (TVS_DISABLEDRAGDROP = 16).
  • int x, y: a posição da janela está nas coordenadas 0,0.
  • int nWidth, nHeight: tanto a largura quanto a altura são zero. O tamanho real da janela será definido na interceptação da mensagem WM_SIZE na função MainWndProc, nossa central de mensagens. A vantagem é que, quando o usuário redimensionar a janela principal, a janela do controle da árvore acompanha o redimensionamento.
  • HWND hWndParent: o ponteiro para a janela-mãe (hWnd), recebido pela função CriaTree como parâmetro, é repassado para a função CreateWindowEx.
  • HMENU hMenu: é enviado como identificador da janela-filha, ou seja, o parâmetro int ID recebido pela função CriaTree é passado para a função CreateWindowEx como tipo HMENU com a notação (HMENU)ID.
  • HINSTANCE hInstance: podemos usar o valor de hInst como instância, uma vez que o código gerado pelo Wedit nos disponibiliza esta variável como global.
  • LPVOID lpParam: não há ponteiro para dados para a criação da janela, portanto, enviamos NULL.

O código para a criação da janela do controle da árvore está pronto. A explicação é muito mais longa do que o código propriamente dito. Mas pode ir se acostumando pois, se quiser produzir um código "enxuto", a romaria vai ser sempre a mesma: muita pesquisa e muita leitura para decidir usar algumas linhas de comando.

NÃO SE ESQUEÇA de colocar o protótipo da função no início do programa, senão o pre-processador vai estrilar. Mais um alerta: se não existir o protótipo, a posição da função dentro do código faz diferença - ela precisa estar ANTES de chamada à função, no nosso caso, antes da função MainWndProc. Mas, como somos programadores profissionais, incluímos o protótipo:

... HINSTANCE hInst; // manipulador da instância HWND hwndMain; // manipulador da janela principal LRESULT CALLBACK MainWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam); static HWND _stdcall janelaTree(HWND hWnd,int ID); ...

Informações adicionais