Ir para conteúdo
Faça parte da equipe! (2024) ×

delphi WinApi em Delphi


Inoxybel
 Compartilhar

Posts Recomendados

Vou iniciar uma pequena série de artigos sobre WinApi em Delphi juntamente com a DarkProgramming Team!

 

Hoje vou explicar de uma maneira simplificada como funciona a estrutura básica de uma aplicação feita em WinApi. Esse artigo trás informações que são necessárias para entender definitivamente como funciona e como criar suas aplicações em puro código, largando de mão a poluição do Windows Forms.

 

Antes de começar a ler, certifique-se que você tem domínio dos temas abaixo:

 

- Lógica de programação {

- Variáveis

- Funções com e sem retorno de valores

}

 

Esses conhecimentos são necessários para você entender como as funções que utilizaremos para programar em WinApi funcionam. Caso você não tenha domínio sobre esses temas, por favor, volte para a área de tutoriais e leia os tópicos a respeito antes de ler este.

 

 

Iniciando, antes de colocarmos a mão na massa, precisamos entender como funcionam duas funções básicas, uma para criação dos componentes e outra para comunicação entre eles:

 

CreateWindowEx():

 

Essa função é responsável por criar janelas idêndica a função CreateWindow(), porém essa da algumas liberdades a mais como criar janelas com estilos "extras".

 

Vamos explorar seus parâmetros para aprender a usa-la:

 

É necessário se cadastrar para acessar o conteúdo.

 

dwExStyle - Esse parâmetro é o responsável por armazenar os estilos da janela (lembra da diferença entre as duas funções comentada acima? Esse é o parâmetro responsável por essa diferênça).

 

Aqui fica um link de referência para vocês verem todos os estilos "extras" possíveis de usar:

 

Estilos de Janelas

 

"Extras"

 

lpClassName - Aqui você indica a classe da janela, abordaremos logo abaixo mais sobre isso.

 

lpWindowName - Esse parâmetro recebe o nome da Janela, para você que está acostumado com Windows Forms, esse parâmetro é como se fosse o Caption do componente que vai ser criado.

 

dwStyle - Aqui você especifica os estilos 'normais' da janela. (O primeiro você especifica os estilos "extras").

 

Aqui fica outro link de referência para vocês verem todos os estilos "padrões" possíveis de usar:

Estilos de Janelas

 

 

X - Esse parâmetro recebe a posição Horizontal de onde a janela que está sendo criada vai estar. Se você estiver criando a janela principal, aqui você especifica quandos pixels de distância do lado esquerdo do monitor do usuário sua janela abrirá. Se for um componente como um botão por exemplo, que é um "Filho" da janela principal, aqui você indica um valor em pixels que o componente ficará distante da borda esquerda da janela principal.

 

Nesse parâmetro você pode definir o valor CW_USEDEFAULT, pois aí o Sistema Operacional definirá um valor padrão onde sua janela irá abrir, geralmente esse valor é uma posição próxima ao do ponteiro do mouse quando o usuário clica 2x para abrir a aplicação.

 

Duas coisas importantes para você saber caso queira declarar CW_USEDEFAULT no parâmetro X:

1 - Você só pode declarar para janelas sobrepostas, ou seja, janelas "principais", não pode declarar para componentes, caso contrário os valores dos parâmetros X e Y serão definidos 0.

 

2 - Ao declarar esse valor no parâmetro X, o valor do parâmetro Y é usada de outra forma.

 

Y - Esse parâmetro é similar ao X, porém na Vertical. Se CW_USEDEFAULT for definido nesse parâmetro, aí você vai precisar chamar a função ShowWindow() para definir o estado (visível ou não, maximizada, minimizada, etc) da janela ao ser criada.

 

Se CW_USEDEFAULT for definido no parâmetro anterior ( X ), então esse parâmetro recebe o valor do ESTADO da janela, que pode ser consultado nas flags do parâmetro nCmdShow da função ShowWindow() nesse link.

 

nWidth - Valor da largura da sua janela ou componente.

 

nHeight - Valor da altura da sua janela ou componente.

 

hWndParent - Aqui você especifica quem é o "Pai" da janela que está sendo criada, caso esteja sendo criado uma janela principal, defina esse parâmetro como 0, caso seja um componente, defina nesse parâmetro a janela principal onde o componente irá aparecer.

 

hMenu - Esse parâmetro recebe um identificador, não vamos entrar em detalhes nisso agora para não enrolar mais do que já está.

 

hInstance - Esse parâmetro também recebe um identificador para associar com a janela que está sendo criada, deixe-mos este para mais tarde também.

 

lpParam - Esse parâmetro recebe um ponteiro para um valor que vai ser passado como mensagem para a aplicação. Trataremos de mensagens a seguir.

 

 

 

Ufa, é extenso mas é necessário para deixar bem 'entendível'. Agora vamos para uma menor, SendMessage():

 

É necessário se cadastrar para acessar o conteúdo.

 

SendMessage() é um procedimento que tem por função enviar mensagens para alguma janela e aguarda essa mensagem ser processada pela aplicação para depois retornar um valor. Oposto da função PostMessage() que envia uma mensagem para a fila de mensagens da aplicação e já retorna.

 

hWnd - Parâmetro que recebe o identificador da janela que vai receber a mensagem.

 

Msg - Parâmetro que recebe mensagem que vai ser enviada.

 

wParam - Parâmetro que recebe especificações extras para ser enviado com a mensagem.

 

lParam - Parâmetro que recebe especificações extras para ser enviado com a mensagem.

 

 

Bem, com essas informações já estamos semi-preparados para iniciar a programação. Antes precisamos entender como a aplicação funciona de uma forma simples.

 

A aplicação enquanto rodando no Sistema Operacional, ela está constantemente recebendo e enviando Mensagens, mensagens para dizer que está aberta e como está aberta, mensagens com informações de uso de processamento e memória, mensagens de ações feitas na própria aplicação, enfim, toda a comunicação da aplicação com o sistema operacional e com ela mesma, é constante!

 

Com isso podemos iniciar um novo projeto no Delphi, Console Application:

0876fb23df.png

87cfc55a5a.png

 

Você terá um projeto novo similar a esse:

74063e9551.png

 

Apagamos tudo depois da primeira linha, e refazemos um esqueleto limpo, declarando somente as bibliotecas Windows e Messages:

37a84aee08.png

 

Pois bem, sabendo que toda aplicação trabalha com mensagens, precisamos construir uma função principal na aplicação que é responsável por tratar essas mensagens, vamos chamá-la de WinProc().

 

073e25b304.png

 

Com isso, temos uma função que recebe o remetente da mensagem que está sendo enviada (hWnd), a mensagem (uMsg), e as especificações das mensagens (wParam e lParam), e é aqui que vamos tratar toda a comunicação feita na nossa aplicação. Mas antes, vamos continuar montando a estrutura da nossa aplicação.

 

Continuando, nossa aplicação não é uma aplicação sem uma janela né, então vamos criar uma classe onde armazenará características básicas que definem nossa janela principal do programa. Acima da função WinProc() que acabamos de criar, crie um campo para declaração de variáveis e declare uma variável do tipo TWndClass, já aproveira e cria uma variável (TMsg) para manipularmos as mensagens que circularão na nossa aplicação.

 

É necessário se cadastrar para acessar o conteúdo.

 

Em Seguida, podemos iniciar a criação da nossa classe:

69c0cd3821.png

 

style é os estilos, definimos por enquanto só CS_HREDRAW e CS_VREDRAW que são as flags que indicam que nossa aplicação devem ser redesenhadas horizontalmente e verticalmente quando há alguma modificação na nossa aplicação, como o tamanho da janela.

 

lpfnWndProc é onde devemos especificar qual é a função que irá processar as mensagens da janela que for criada com essa classe.

 

hbrBackground é onde definimos a cor de fundo da nossa aplicação.

 

lpszClassName é onde devemos definir o nome da nossa classe.

 

hCursor - É onde definimos o ponteiro do mouse que aparecerá na nossa aplicação.

 

Podemos definir outras propriedades como o ícone que aparecerá na janela, entre outras, caso queira saber mais entre nesse link.

 

Agora que já temos a classe 'padrão' da nossa aplicação, podemos criar a janela principal. Mas antes, devemos criar um loop para pegar as mensagens que estão sendo processadas na nossa aplicação e converte-las de Chave-Virtual para simples Textos, para podermos trata-las.

 

6aef33db32.png

 

Pronto, agora que já cuidamos desses detalhes, podemos registrar nossa classe na aplicação com a API RegisterClass() para podermos definir nossa classe nas futuras janelas a serem criadas:

 

É necessário se cadastrar para acessar o conteúdo.

 

E por fim, criamos uma variável do tipo THandle para criarmos nossa janela:

 

db1548cfde.png

 

Compile e veja o resultado.

 

Para agora no finalmente, entendermos essa história de mensagens, vamos criar um botão na nossa janela principal. Para isso, declare outra variável do tipo THandle para criar o botão, em seguida utilize CreateWindowEx() para criar o botão, definindo no parâmetro hWndParent a nossa janela principal, definindo que nossa janela principal é PAI do botão, e inserindo nas flags do dwStyle WS_CHILD para definir que o botão é uma janela filho.

 

5a5d78ef43.png

 

E teremos algo próximo a isso:

 

4c0132c8e3.png

 

Bom, lembra que tudo na aplicação é feito por mensagens? Pois bem, se clicarmos no botão, uma mensagem em especial é enviada automaticamente, sem necessidade de uma API como a SendMessage() (Calma, ainda veremos uma utilização com ela). Essa mensagem é a WM_COMMAND. Podemos utilizar a estrutura case/of para tratar melhor cada tipo de mensagem, por hora, vamos tratar somente duas, WM_DESTROY e WM_COMMAND.

 

7d9b866361.png

 

 

A mensagem WM_DESTROY é enviada quando a aplicação está sendo "destruída". Por exemplo quando você clica no botão fechar da janela. Nela chamamos a API PostQuitMessage() com o valor 0 no parâmetro para solicitar o fechamento da janela ao S.O.

 

A mensagem WM_COMMAND é enviada quando um componente filho recebe um comando (um menu ou um botão recebe um click por exemplo). Segundo nossa grande amiga MSDN:

 

É necessário se cadastrar para acessar o conteúdo.

 

Para entendemos melhor o que é HIWORD e LOWORD, devemos saber que a mensagem é contem 8 bytes, ou seja um DWORD. Nos parâmetros a mensagem é enviada em 8 bytes, e é dividida em duas partes, HIWORD e LOWORD, cada uma dessas contém seus valores individuais que podemos utiliza-las de várias formas. Para entender melhor:

 

092503bffe.png

 

Segundo a MSDN, o WM_COMMAND divide essa mensagem em 3 parâmetros:

 

wNotifyCode é o HIWORD (os 4 bytes mais altos) da especificação do wParam, que diz se a mensagem está sendo enviada por um controle, um menu, etc.

 

wID é o LOWORD (os 4 bytes mais baixos) da especificação do wParam, que armazena o Identificador item de menu (O hMenu que deixamos para explicar outra hora, lembra?) que está enviando a mensagem (no nosso caso, o Button não tem uma ID).

 

hwndCtl é o identificador do componente que está enviando a mensagem.

 

 

Sabendo disso, então vamos utilizar agora somente o lParam, que contém o identificador do componente que está enviando a mensagem, nesse caso, o Button.

 

6d4aa23a2a.png

 

Bom, concluímos a tarefa. Agora vamos entender qual é a do SendMessage()?

 

Com ele podemos enviar mensagens através de componentes para outros componentes. No nosso projetinho, vamos fazer o botão que criamos fechar o programa, para isso, comente a linha do MessageBox() e vamos enviar a mensagem WM_DESTROY através do SendMessage() para a aplicação.

 

3670449d91.png

 

 

Compile e teste.

 

Qualquer erro ou dúvida poste no tópico.

 

 

Créditos:

 

Inoxybel

 

Mais conteúdos como esse só com a DarkProgramming Team

Meus brinquedos em WinAPI:

Calculador

MemoryScanner

Faça parte também da DarkProgramming Team!

Link para o comentário
Compartilhar em outros sites

Este tópico está impedido de receber novos posts.
 Compartilhar

×
×
  • Criar Novo...

Informação Importante

Nós fazemos uso de cookies no seu dispositivo para ajudar a tornar este site melhor. Você pode ajustar suas configurações de cookies , caso contrário, vamos supor que você está bem para continuar.