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); ...

Movendo e redimensionando a janela da árvore

Como foi dito acima, na descrição dos parâmetros nWidth e nHeight, vamos redimensionar a janela-filha da árvore na nossa central de mensagens através da interceptação da mensagem WM_SIZE. Completamos o código deste caso com o seguinte (linhas 5 e 14 a 17):

LRESULT CALLBACK MainWndProc( HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) { static HWND hwndTree; RECT rc, rcStatus; switch (msg) { case WM_CREATE: hwndTree = janelaTree(hwnd,IDJANELATREE); break; case WM_SIZE: SendMessage(hWndStatusbar,msg,wParam,lParam); InitializeStatusBar(hWndStatusbar,1); GetClientRect(hwnd,&rc); GetWindowRect(hWndStatusbar,&rcStatus); rc.bottom -= rcStatus.bottom-rcStatus.top; MoveWindow(hwndTree,0,0,rc.right,rc.bottom,1); break; ...

Inicialmente manifestamos rc e rcStatus como RECT. RECT é uma estrutura que define as coordenadas do canto superior esquerdo e do inferior direito de um retângulo. A definição do tipo é a seguinte:

typedef struct _RECT { // rc LONG left; // esquerda LONG top; // superior LONG right; // direita LONG bottom; // inferior } RECT;

Usando a função da API GetClientRect, o parâmetro hwnd leva o manipulador (handle) da janela-mãe e o parâmetro &rc é o ponteiro para o endereço onde os valores correspondentes às coordenadas da janela-mãe devem ser armazenados. Estas coordenadas marcam a área disponível, onde é possível desenhar, excluindo as bordas, o título, o menu e outras partes da janela.

Como temos uma barra de status na nossa janela-mãe, esta área precisa ser subtraída da área de desenho. Neste caso estamos interessados na área total da janela, e não apenas na área de desenho. Por isto utilizamos a função da API GetWindowRect e transferimos para o endereço indicado pelo ponteiro de rcStatus, o &rcStatus, as coordenadas referentes a este retângulo. A seguir, atribuímos a rc.bottom o valor da coordenada inferior da janela-mãe subtraído do valor da área da barra de status.

Uma vez que foi determinada a área de desenho realmente disponível para o controle da árvore, movemos a janela deste controle para as coordenadas desejadas através de uma chamada à função da API MoveWindow. Esta função pede inicialmente o manipulador da janela que deve ser movida (hwndTree), a janela-filha do controle da árvore. Seguem as coordenadas do retângulo que será preenchido pelo controle e, como último parâmetro, um valor lógico indicando se a janela deve ser redesenhada (TRUE ou 1) ou não (FALSE ou 0).

Observações da vó

É claro que, em se tratando de um projeto ambicioso, um módulo apenas não vai dar conta do recado. São muitos os aspectos que precisam ser abordados...

Mas, antes de prosseguir para a emocionante expedição de caça a janelas, dê uma conferida no código que foi adicionado (se você ainda não adicionou o código descrito, faça-o agora). Salve espiao.c para atualizar o código fonte, compile e rode o programa espiao.exe. Está bem, pode reclamar mas, se não deu erro e se não mudou nada no programa, fique feliz! Vida de programador é assim mesmo wink

Primeira constatação: se não deu erro é sinal que você digitou corretamente o código adicional. Segunda constatação: se o título, o menu e a barra de status da janela principal não foram detonados é sinal que você fez as contas certas para as coordenadas. A janela-filha do controle da árvore, apesar de vazia, está dentro da janela-mãe e não está fazendo estragos.

Se tudo estiver nos conformes, então vamos caçar janelas. O próximo tutorial vai testar a sua pontaria (e a minha também smile )

Вадим Логофет Сбербанксковорода для индукционных плит отзывыхарьков никас александр лобановскийmeizu pro 4 32gbхарьков события на площадиtopodin отзывы

Informações adicionais