Visual Basic 6 - Usando funções das APIs no VB6
"API - Application Program Interface - é um conjunto de funções predefinidas utilizadas para controlar a aparência e o comportamento de cada elemento do Windows." Gostaram do começo ?
O VB foi um divisor de águas que permitiu a criação de programas para o ambiente Windows a um grande número de usuários . Antes isto estava restrito aos programadores C , C++ e de outras linguagens não tão amigáveis.
Mas por trás da aparente simplicidade de um formulário , de um click de mouse , de uma chamada a uma função ou de uma simples linha de código , muitas coisas ocorrem nos bastidores para que tudo possa estar funcionando...
Na verdade cada linha de código escrita em um projeto esta sendo traduzida pelo VB em uma função API e enviada ao Windows que processa a mensagem e retorna o resultado. Assim quando você escreve algo como Form1.Print o VB chama a função API TextOut com os respectivos parâmetros.
Mas onde estão estas funções ? E como elas se comportam e funcionam ?
As funções API residem em arquivos DLL - Dinamic Link Library - que são bibliotecas de rotinas utilizadas pelo sistema Windows e podem ser encontradas na pasta Windows/System. As DLLs podem ser utilizadas por quaisquer aplicativos externos ao Windows e o VB usa e abusa das DLLs e das APIs.
As DLL´s permitiram que o Windows apresentasse uma interface padrão ao usuário. O exemplo mais conhecido é a Commom Dialog - Commdlg32.dll. Este arquivo contém todo o código necessário para criar diversas janelas de diálogos padrões do Windows - A janela Abrir , Salvar , Imprimir, etc...
Então as DLLs são arquivos externos que podem ser usados por sua aplicação VB . Assim se a DLL que você for usar estiver presente no Windows basta você criar um link para ela no seu projeto (você faz isto declarando a API) e indicar qual função deseja usar ; seu programa vai ficar menor pois você não vai precisar distribuir este arquivo. Se a DLL não estiver presente no Windows você usa o mesmo procedimento só que vai ter que incluir a DLL no seu KIT de distribuição. (lembrete: você pode criar a sua própria DLL e usá-la no VB). Abaixo temos uma esquematização deste processo:
Os principais arquivos DLLs do Windows são:
Arquivo DLL | Descrição |
KERNEL32 | Gerencia a memória ; multitarefa... |
USER32 | Gerencia mensagens , menus, cursores, comunicações, etc... |
GID32 | Graphics Device Interface - Recursos de desenho , telas e objetos , redimensionamentos... |
COMDL32 | Janelas comuns : impressão , salvar , abrir, ... |
WINMM | Recursos multimídia, som , video, ... |
Lz32 | Rotinas de compressão e compactação |
Como usar uma API ?
Tudo bem, eu já sei onde estão as funções API , mas , como posso usá-las no Visual Basic ? Boa pergunta! Você usa uma função API como usa qualquer função : fazendo a declaração da função e dos parâmetros que ela vai usar e depois fazendo a chamada a função que você declarou. (acho que a resposta não foi muito boa ...). Então:
A declaração de uma API possui a seguinte estrutura básica:
Private/Public Declare Function/Sub NomedaFunção Lib NomedaDLL Alias "NomeFunçãoAPI(Argumentos)" As TipodeDados
Vejamos como exemplo a declaração da API FindWindow:
Private Declare Function FindWindow Lib "User32" Alias "FindWindowA" (ByVal lpClassName as String , ByVal lpWindowName as String) As Long
Nota:
O parâmetro Alias indica o
verdadeiro nome da uma função API como ela é encontrada no arquivo DLL
. Este nome pode ser diferente do nome da função que você irá
usar no seu Programa VB.
Como exemplo desta diferença podemos citar a função _lopen que esta presente na DLL Kernel32. O nome _lopen não é um nome válido que possa ser usado como nome de uma função no Visual Basic . Neste caso a declaração fica assim: Declare Function lopen Lib "kernel32" Alias "_lopen" (ByVal lpPathName As String, ByVal iReadWrite As Long) As Long. O VB enxerga a função com o nome lopen mas sabe , através do parâmetro Alias na declaração da API que deve passar a chamada para a função _lopen presente na Kernel32. |
Antes que você fique assustado com a aparente complexidade do código envolvido e isto o desanime a utilizar as API´s , fique sabendo que tudo é uma questão de seguir determinadas regras , logo você estará acostumado com a estrutura de uma declaração e terá um verdadeiro arsenal a sua disposição.
Existem mais ou menos umas 1000 funções API !!! Cada uma com sua declaração e parâmetros. Sentiu o drama ? Mesmo se você for separar as mais usadas ainda terá que ter uma boa memória para se recordar da declaração de cada uma . Ainda bem que existem ferramentas para facilitar este trabalho , uma dessas ferramentas você encontra no Visual Basic e o API Viewer . Vamos ver como usá-la...
Inicie o Visual Basic e no menu Add-Ins selecione API Viewer ( se não a opção não estiver no menu Add-Ins você deverá incluí-la).
Após executar o API Viewer selecione na opção File do menu o item - Load Text File - ou Load Database File se você converteu o arquivo texto para mdb . A seguir selecione o arquivo - Win32Api.txt ou Win32Api.mdb - desta forma serão carregadas todas as declarações disponíveis para as funções API. Veja abaixo a janela API Viewer exibindo o resultado :
Na combo Api Type você pode escolher o que quer pesquisar:
Na combo seguinte você digita as primeiras palavras da sua pesquisa.
Ao clicar no botão Add a declaração irá ser exibida na caixa - Selected Items. Dai se você clicar no botão Copy irá copiar a declaração para a área de transferência e depois poderá colar a declaração no seu projeto. As opções Public e Private alteram o escopo da declaração.
O botão Insert irá inserir a declaração no formulário atual. O botão Clear irá limpar a caixa Selected Items e o botão Remove irá remover a declaração que você selecionou.
Percebeu que com o API Viewer fica mais fácil declarar uma API , mas ele não é a única ferramenta que você pode usar , a Win32 SDK - (Software Development Kit) - é uma referência compreensiva das funções API disponíveis além da MSDN que você pode encontrar em http://msdn.microsoft.com.
E Agora qual o próximo passo ???
Declarar uma API é apenas o primeiro passo , para efetivamente você obter resultados você deve chamar a função declarada e para isto vai precisar passar os parâmetros corretos e tratar o resultado da função , o retorno da função. Vamos dar um exemplo prático...
Vamos usar a função API GetDiskFreeSpace que nos dá o espaço disponível na unidade de disco indicada.
Abaixo a declaração no formulário:
Private Declare Function GetDiskFreeSpace Lib "kernel32" Alias "GetDiskFreeSpaceA" (ByVal _ lpRootPathName As String, lpSectorsPerCluster As Long, lpBytesPerSector As Long, _ lpNumberOfFreeClusters As Long, lpTtoalNumberOfClusters As Long) As Long |
Já temos a declaração disponível no formulário , agora podemos escrever o código que chama a função API . Insira um botão de comando no formulário e digite o código abaixo no evento Click do botão :
Private Sub Command1_Click() Dim lSecPerClust As Long Dim lBytesPerSec As Long Dim lFreeClust As Long Dim lTotalClust As Long Dim lRetorno As Long lRetorno = GetDiskFreeSpace("C:\", lSecPerClust, lBytesPerSec, lFreeClust, lTotalClust) MsgBox "Espaço livre no drive C em Clusters = " & lFreeClust & vbCrLf & "Total de Clusters " & lTotalClust End Sub |
Você deve passar cinco parâmetros para a função GetDiskFreeSpace :
Para isto deverá declarar 5 variáveis do tipo Long e fazer a chamada da função . O retorno da função é armazenado na variável lRetorno (perceba que não fazemos nada com essa variável) ; além disto a função devolve quatro tipos diferentes de informação , mas não exatamente o tipo de informação que você precisa. Afinal você quer saber o espaço em bytes livres da unidade e não em clusters.
Para contornar este problema você deve criar uma função que trate as informações e as exiba no formato adequado. Abaixo temos uma possível solução para o problema:
Function EspacoLivre(sPath As String) As Double Dim sDrive As String Dim lRetorno As Long Dim lsetoresporcluster As Long Dim lbytesporsetor As Long Dim lclusterlivres As Long Dim ltotaldeclusters As Long sDrive = Left$(sPath, 1) & ":\" lRetorno = GetDiskFreeSpace(sDrive, lsetoresporcluster, lbytesporsetor,lclusterlivres, ltotaldeclusters) EspacoLivre = (lsetoresporcluster * lbytesporsetor * lclusterlivres) End Function |
Agora para chamar a função basta informar o drive desejado :
MsgBox " Espaco livre " & Format(EspacoLivre("c:\"), "###,###,###,###") & " bytes "
Simples , não ? Acho que até agora não deve ter havido nenhum problema quanto ao entendimento em como declarar e usar uma função API. Vamos mostrar outro exemplo onde as coisas não serão tão óbvias.
Quando usamos parâmetros que retornam dados do tipo String devemos ter mente que uma API esta tratando com strings C (linguagem C) (basicamente ponteiros de bytes). Neste caso a API irá requerer que você prepare melhor as variáveis de retorno antes de fazer a chamada a API.
As funções API nunca retornam os valores strings diretamente , e , se um procedimento precisa retornar um valor string ele irá esperar que você forneça uma string na lista de parâmetros e que você obtenha o resultado da variável string que você forneceu. Vejamos como exemplo a API GetComputerName que retorna o nome dado ao computador.
A declaração obtida na API Viewer é a seguinte:
Public Declare Function GetComputerName Lib "kernel32" Alias "GetComputerNameA" (ByVal lpBuffer As String, nSize As Long) As Long |
A função toma dois parâmetros :
Ambos os parâmetros estão sendo passados como ponteiros.
Vejamos o código usado para chamar a função:
Private Sub Form_Load() Dim lretorno as Long 'Cria a variavel strstring 'Obtem o nome do computador 'remove nulos chr$(0) 'exibe o nome do computador |
Observe que declaramos uma variável string strNome para receber o nome do computador retornado pela função . A seguir :
A variável lretorno pode assumir dois valores : 0 se houve algum erro e 1 se tudo deu certo.
Sem estes procedimentos , ao executar a chamada da função teríamos um erro em tempo de execução.
Os tipos de dados dos parâmetros das API
Os tipos de dados dos parâmetros retornados por uma função API podem ser de diversos tipos , e , se você conhecer a linguagem C , vai estar familiarizado com esses tipos. Abaixo damos como converter os tipos de dados para o Visual Basic:
Tipos de dados em C | Declarar no VB como | Chamar como |
ATOM | ByVal variable As Integer | Uma expressão que define um valor n Int. |
BOOL | ByVal variable As Long | Uma expressão que define um valor Long |
BYTE | ByVal variable As Byte | Uma expressão que define um valor Byte |
CHAR | ByVal variable As Byte | Uma expressão que define um valor Byte |
COLORREF | ByVal variable As Long | Uma expressão que define um valor Long |
DWORD | ByVal variable As Long | Uma expressão que define um valor Long |
HWND, HDC, HMENU, etc. | ByVal variable As Long | Uma expressão que define um valor Long |
INT, UINT | ByVal variable As Long | Uma expressão que define um valor Long |
LONG | ByVal variable As Long | Uma expressão que define um valor Long |
LPARAM | ByVal variable As Long | Uma expressão que define um valor Long |
LPDWORD | variable As Long | Uma expressão que define um valor Long |
LPINT, LPUINT | variable As Long | Uma expressão que define um valor Long |
LPRECT | variable As type | Qualquer variável do tipo definido pelo usuário |
LPSTR, LPCSTR | ByVal variable As String | Uma expressão que define um valor de String |
LPVOID | variable As Any | Qualquer (use ByVal quando passar uma string) |
LPWORD | variable As Integer | Uma expressão que define um valor n Int. |
LRESULT | ByVal variable As Long | Uma expressão que define um valor Long |
NULL | As Any or |
ByVal Nothing ou ByVal 0& ou vbNullString |
SHORT | ByVal variable As Integer | Uma expressão que define um valor n Int. |
VOID | Sub procedure | Não aplicável |
WORD | ByVal variable As Integer | Uma expressão que define um valor de n Int. |
WPARAM | ByVal variable As Long | Uma expressão que define um valor Long |
Observe que o tipo Boleano é avaliando como um Long e pode assumir os valores 0 para falso e 1 para verdadeiro e que o tipo NULL pode ser passado por valor ( ByVal) como 0& ou como vbNullString.
Percebeu que ao declarar uma função API usamos , no Visual Basic , basicamente os seguintes tipos de dados
Passando os parâmetros por Valor ou por Referência
O padrão é o Visual Basic passar todos os parâmetros por referência ( ByRef ), ou seja, ao invés de passar o valor atual do argumento ele passa um endereço de 32 bits onde o valor esta armazenado. Desta forma se ocorrer qualquer alteração no valor do parâmetro isto será refletido no valor original do mesmo. Se você passar uma variável chamada minhavar por referência para uma função API ela poderá alterar o conteúdo da variável minhavar.
Para passar um parâmetro por valor usamos a palavra ByVal precedendo o parâmetro , com isto estamos passando uma cópia do valor do parâmetro e não o seu endereço de localização. Assim , se voce passar uma variável chamada minhavar por valor para uma função API , a função não tem a possibilidade de editar o conteúdo da variável minhavar.
Algumas funções esperam que o valor seja passado por valor , ou seja , elas esperam o valor atual e não uma endereço de localização do parâmetro . Não preciso nem dizer que se você passar um valor por referência isto pode acarretar resultados imprevisíveis como por exemplo o travamento do seu computador.
Ao passar uma string por valor você esta passando o endereço do primeiro byte de dados da string . Se passar uma string por referência você estará passando o endereço de memória onde outro endereço esta armazenado , neste caso o primeiro byte de dados da string.
Alguns conceitos adicionais sobre a passagem de parâmetros ByVal ou ByRef
Qual o número da sua janela ? Enviando e recebendo mensagens...
Vamos abordar agora alguns conceitos muito importantes envolvendo as API´s , o Windows e o VB. Quando você executa um projeto , por mais simples que seja , ele geralmente é composto basicamente por formulários , controles e o código associado. O Windows identifica cada formulário e controle atribuindo a cada objeto um número que o identifica. Assim cada janela possui um Handle , ou um número identificador que a identifica de forma única. O VB dispõe de uma propriedade Hwnd para todos os controles que necessitam de um Handle identificador assim você pode usar esta propriedade para identificar cada objeto do seu projeto.
Vamos usar uma API muito simples que ilustra o uso de um Handle (identificador); a função API - FlashWindow. Talvez ela não seja muito útil , mas servirá para os nosso propósitos . Vamos fazer um raio X da função FlashWindow.
- A função inverte as cores do título de uma janela.
- Declarando a função - Para declarar abra o API Viewer ou outro utilitário ( no Super CD VB temos um utilitário com mais de 900 funções API´s com suas declarações , constantes e exemplos ) e selecione a função FlashWindow:
Private Declare Function FlashWindow Lib "user32" Alias "FlashWindow" (ByVal hwnd As Long, ByVal bInvert As Long) As Long |
-Agora inicie um novo projeto no VB e no formulário padrão insira dois botões de comando e um controle Timer definindo a propriedade Interval do Timer para um valor em torno de 500.
Veja abaixo o jeitão do formulário:
- Finalmente inclua o código abaixo no formulário:
Private Declare Function FlashWindow Lib "user32" (ByVal hwnd As Long, ByVal bInvert As Long) As Long Dim lngRet As Long Dim SimNao As Boolean Private Sub Command1_Click() Private Sub Command2_Click() Private Sub Timer1_Timer() |
- Observe a chamada da função : Você passa o identificador da janela atual ( Me.hwnd ) e diz se é para piscar (True) ou não (False) através da variável boolena SimNao. O retorno será True (1) ou False (0). Você pode observar o valor da variável de retorno lngRet.
Você ja ouviu falar nas mensagens do Windows. Não ?? Pois vai ouvir agora...
Para se comunicar com o seu programa e saber qual o tipo de informação foi recebida e qual deve ser processada , o Windows envia mensagens ao seu programa. Uma mensagem é enviada para o seu formulário quando o usuário clica um botão ou movimenta mouse, etc.. (O retorno da mensagem é capturada pelo seu programa VB e processado de maneira transparente). No exemplo acima quando o usuário clica no botão Piscar, o windows envia uma mensagem para processar esta informação.
Todas as mensagens são enviadas usando quatro parâmetros:
Vamos apresentar agora a função API que faz este serviço: SendMessage (nome sugestivo não ? )
SendMessage envia uma mensagem chamando a função do Windows para a janela indicada. O controle não retorna ao programa que a chamou enquanto sua execução não estiver finalizada. Sua declaração é a seguinte:
Public Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long |
Vamos ver uma aplicação prática usando a função SendMessage. Essa você vai gostar...
- Vamos usar a função SendMessagem para enviar uma mensagem ao controle ListBox. Quando você digitar algo no controle TextBox o evento Change do controle irá enviar uma mensagem ao Controle ListBox selecionado o item da Lista .
- Inicie um novo projeto no Visual Basic e no formulário padrão insira um controle label, um controle ListBox e um controle TextBox , como a figura abaixo:
O formulário com os controles | Ao pressionar uma tecla a seleção ocorre na lista |
- Para declarar a função SendMessage use o API Viewer conforme já ensinado. Vamos declarar a função na seção General Declarations do formulário , assim:
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Integer, ByVal lParam As Any) As Long Const LB_FINDSTRING = &H18F |
Notou que declaramos uma constante : Const LB_FINDSTRING = &H18F Fazemos isto usando o API Viewer , assim:
Veja abaixo a figura exibindo a seleção:
O código do formulário é dado a seguir:
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Integer, ByVal lParam As Any) As Long Const LB_FINDSTRING = &H18F Private Sub Form_Load() Private Sub Text1_Change() |
-Como funciona:
- Quando você digitar algo na caixa de texto o evento text1_Change ira invocar a função SendMessage, assim:
O retorno será a posição list1.Listindex na lista de opções do controle ListBox.
Pronto !!! com isso resolvemos um problema com poucas linhas de código usando uma chamada a uma função API .
Além da função SendMessage o temos a função API PostMessage que atua de um modo um pouco diferente. PostMessage envia uma mensagem postando a mensagem na lista de tarefas do Windows , sendo assim , ela somente será processada depois que as outras tarefas forem finalizadas.
A função PostMessage retorna o controle para o programa que a invocou de imediato não retornando nenhum valor. Este valor somente será retornado quando a mensagem for processada pelo Windows. A declaração de PostMessage é:
Private Declare Function PostMessage Lib "user32" Alias "PostMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long |
A seguir vamos mostrar um exemplo usando a função PostMessage. A função é usada para enviar uma mensagem a uma janela ativa . No caso a mensagem será para que a janela seja fechada. Abaixo o formulário padrão com os controles:
Estaremos usando também a função API FindWindow que irá localizar a janela ativa (informada pelo usuário na caixa de texto) , a seguir invocamos a função PostMessage que irá enviar a mensagem para a janela encontrada com o parâmetro para fechar a janela.(WM_CLOSE=&H10).
As declarações serão usadas no formulário padrão do projeto VB e por isso serão declaradas como Private. Abaixo as declarações e a constante usada.
Private Declare Function FindWindow Lib "user32" Alias
"FindWindowA" (ByVal lpClassName As String, _ ByVal lpWindowName As String) As Long Private Declare Function PostMessage Lib "user32" Alias "PostMessageA" (ByVal hWnd As Long, ByVal wMsg As Long, _ ByVal wParam As Long, lParam As Any) As Long Const WM_CLOSE = &H10 |
A constante foi obtida usando o API Viewer como no exemplo anterior.
No botão de comando(cmdFechar) usado no formulário insira o código a seguir:
Private Sub cmdFechar_Click() Dim winHwnd As Long Dim RetVal As Long winHwnd = FindWindow(vbNullString, Text1.Text) Debug.Print winHwnd If winHwnd <> 0 Then RetVal = PostMessage(winHwnd, WM_CLOSE, 0&, 0&) If RetVal = 0 Then MsgBox "Erro ao postar mensagem.", vbCritical, "Usando PostMessage" End If Else MsgBox Text1.Text + " não esta aberto.", vbInformation, "Usando PostMessage" End If End Sub |
Como Funciona:
- O usuário deverá informar o nome do Título da Janela Ativa ( tem que ser exatamente igual ao nome do título da janela. Ex: Controle de Volume , Sem Título - Bloco de Notas , etc... )
- A função FindWindow irá localizar a janela e retornará o Handle da mesma
- O Handle ou identificador da janela será usado na função PostMessage para que a mensagem seja direcionada para a janela identificada pelo Handle . O Parâmetro WM_CLOSE informa que a janela deverá ser fechada. Obs: Os parâmetros : 0& e 0& são equivalentes a NULL.
Gostou ???? O assunto é vastíssimo e por isso vamos ficando por aqui , esperando retornar em breve abordando outros aspectos das API´s. Abaixo alguns endereços relacionados a funções API´s. Tchau...
Veja os
Destaques e novidades do SUPER DVD Visual Basic
(sempre atualizado) : clique e confira !
Quer migrar para o VB .NET ?
Quer aprender C# ??
Quer aprender os conceitos da Programação Orientada a objetos ? Quer aprender o gerar relatórios com o ReportViewer no VS 2013 ? |
Gostou ? Compartilhe no Facebook Compartilhe no Twitter
Referências: