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 III

Dom

30

Nov

2008


21:20

(1 voto de 5.00) 


Identificando a janela

De posse de um grito válido, precisamos identificar a janela correspondente ao item clicado e extrair algumas informações da mesma. É aí que entra a função PegaItemInfo que irá analisar a estrutura TV_ITEM, a qual contém todas as informações dos itens da árvore. Esta estrutura da API do Windows consta como:

typedef struct _TV_ITEM { UINT mask; HTREEITEM hItem; UINT state; UINT stateMask; LPSTR pszText; int cchTextMax; int iImage; int iSelectedImage; int cChildren; LPARAM lParam; } TV_ITEM, FAR *LPTV_ITEM;

Dos 10 campos desta estrutura, os que nos interessam são os campos UINT mask, HTREEITEM hItem e LPARAM lParam. O primeiro, mask, é um array de flags que especifica os atributos do item. O segundo, hItem, identifica o item ao qual esta estrutura se refere e o terceiro, lParam, é um valor de 32 bits associado ao item. Vejamos como a função PegaItemInfo usa estes campos:

static HWND PegaItemInfo(HWND hwndTree,HTREEITEM hti) { TV_ITEM tvi; memset(&tvi,0,sizeof(TV_ITEM)); tvi.mask = TVIF_PARAM; tvi.hItem = hti; TreeView_GetItem(hwndTree,&tvi); return (HWND) tvi.lParam; }
  1. Inicialmente manifestamos a variável tvi do tipo estrutura TV_ITEM.
  2. Limpamos a área de memória alocada para a estrutura tvi com memset.
  3. Definida a estrutura, atribuímos o valor TVIF_PARAM ao campo mask, indicando com isso que o campo lParam é um campo válido.
  4. Atribuímos ao campo hItem o item hti recebido como parâmetro. É o item que foi clicado.
  5. Com a macro TreeView_GetItem preenchemos a estrutura tvi com o restante dos atributos do item em questão.
  6. Retornamos o valor do campo lParam para a função chamadora. lParam contém o manipulador da janela associada ao item, por isso retornamos este valor como HWND.

Pondo informações da janela na barra de status

Se temos o manipulador da janela associada ao item clicado, temos tudo que precisamos para extrair informações a seu respeito. A função PoeTextoStatus obtém algumas das informações e as coloca na barra de status:

void PoeTextoStatus(HWND hParent,HWND hwnd) { RECT rc; HANDLE pid; char info[4096],*pNomeProcesso; GetWindowRect(hwnd,&rc); GetWindowThreadProcessId(hwnd,&pid); pNomeProcesso = NomeIDProcesso((ULONG)pid); wsprintf(info, "Handle: 0x%x %s, esq %d, topo %d, dir %d, base %d, altura %d, larg %d, Processo: %s", hwnd, IsWindowVisible(hwnd)? "Visível" : "Escondida", rc.left,rc.top,rc.right,rc.bottom, rc.bottom-rc.top, rc.right-rc.left, pNomeProcesso); UpdateStatusBar(info, 0, 0); }

O algoritmo desta função é:

  1. Obter o retângulo da janela.
  2. Obter o ID do processo da linha de execução (thread) da janela.
  3. Chamar uma subrotina para obter o nome do processo referente ao ID do processo.
  4. Formatar os dados numa string.
  5. Atualizar a barra de status.

A função UpdateStatusBar é uma função preparada pelo Wedit que podemos chamar diretamente. A função para se obter o nome do processo da linha de execução da janela conhecendo-se a ID do processo se baseia numa técnica de programação mais avançada que será descrita a seguir:

static char * NomeIDProcesso( DWORD processoID ) { static char szNomeProcesso[MAX_PATH]; HMODULE hMod; DWORD cbNeeded; HANDLE hProcesso = OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processoID ); szNomeProcesso[0] = 0; if ( hProcesso ) { if ( EnumProcessModules( hProcesso, &hMod, sizeof(hMod), &cbNeeded) ) { GetModuleBaseName( hProcesso, hMod, szNomeProcesso, sizeof(szNomeProcesso) ); } CloseHandle( hProcesso ); } return szNomeProcesso; }
  1. A função da API OpenProcess retorna o manipulador (handle) de um objeto processo existente. O primeiro parâmetro é uma flag que indica o tipo de acesso desejado: PROCESS_QUERY_INFORMATION permite obter informações do objeto processo e PROCESS_VM_READ permite a leitura da memória virtual do processo. O parâmetro FALSE se refere à flag de herança do manipulador e o último é o identificador do processo.
  2. O primeiro elemento do array szNomeProcesso é zerado.
  3. Se existir um handle para o processo, avaliamos o retorno da função EnumProcessModules da API, manifestada em Psapi.h. A função cria uma lista dos módulos usados por um aplicativo. Esta lista define o conjunto de arquivos necessários para que o módulo seja carregado e executado. A função é manifestada da seguinte forma:
    BOOL EnumProcessModules( HANDLE hProcess, // manipulador do processo HMODULE* lphModule, // ponteiro para o array que recebe a // lista de manipuladores dos módulos DWORD cb, // tamanho do array lphModule LPDWORD lpcbNeeded // número de bytes necessários para // armazenar todos os manipuladores dos // módulos no array lphModule );
    Pelo cuidado que se tem com o tamanho do array fica claro que é preciso tomar cuidado para que seu espaço não estoure devido a um excesso de manipuladores.
  4. Se EnumProcessModules retornar verdadeiro, chamamos a função, também da API Psapi, GetModuleBaseName, que retorna o nome básico de um módulo no terceiro parâmetro (szNomeProcesso).
  5. Fechamos o manipulador com CloseHandle e retornamos o nome do processo.

Informações adicionais