Views

Important:

Quaisquer necessidades de soluções e/ou desenvolvimento de aplicações pessoais/profissionais, que não constem neste Blog podem ser tratados como consultoria freelance à parte.

...

15 de março de 2013

VBA Advanced - Declarando Funções API - Declaring API Functions





Aprendermos a declarar funções API (Application Program Interface) pode ser muito útil no nosso dia a dia. API é um conjunto de funções predefinidas utilizadas para controlar a aparência e o comportamento de cada elemento do Windows. O único trabalho que teremos será o de aprender a definir as funções dentro do nosso código VBA, e conhecer as suas propriedades, e nos beneficiarmos amplamente das suas facilidades.

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 como o VBA.

As DLLs 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 todos os códigos necessários para criar diversas janelas de diálogos padrões no Windows - A janela Abrir, Salvar, Imprimir, etc... 

Então as DLLs são arquivos externos que podem ser usados na sua aplicação VBA e se a DLL que for usar estiver presente no Windows bastará criar um link para ela no seu projeto (fazemos isto declarando a API) além de indicar qual função deseja usar. 

As nossas aplicações ficarão menores pois não precisaremos distribuir este arquivo. Se a DLL não estiver presente no Windows precisaremos incluir a DLL no nosso KIT de distribuição. Abaixo segue uma esquematização deste processo:

Os principais arquivos DLLs do Windows são:

Arquivo DLLDescrição
KERNEL32Gerencia a memória ; multitarefa... 
USER32Gerencia mensagens , menus, cursores, comunicações, etc...
GID32 Graphics Device Interface - Recursos de desenho , telas e objetos , redimensionamentos...
COMDL32Janelas comuns : impressão , salvar , abrir, ...
WINMMRecursos multimídia, som , video, ...
Lz32Rotinas de compressão e compactação

Como usar uma API ?

Bem, já sei onde estão as funções API, como posso usá-las no VBA?

Use-a como qualquer função: Fazendo a declaração da função e dos parâmetros, depois fazendo a chamada à função que declarou. 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 

Public/Private  - Determina se o procedimento estará disponível para toda aplicação ou somente pelo módulo na qual foi declarado. (As declarações em formulários ou módulos de classes não podem ser Publicas)

Declare Function / Declare Sub - Indica se o procedimento retorna ou não um valor.

NomedaFunção - É o nome da função como será usado no seu projeto VBA.

Lib NomedaDLL - É o nome da livraria DLL onde a função esta localizada.

Alias "NomedaFunçãoAPI" - É o nome da função API como disponibilizada pela DLL onde ela reside.

(Argumentos) - Indica quais parâmetros serão esperados pelo procedimento , o tipo de dados dos parâmetros e se eles serão passados por valor ( ByVal ) ou por referência ( ByRef ).

As TipodeDados - Indica o tipo de dados que sera retornado. Usado somente por funções. 

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

A função é declarada como - Private

O procedimento irá retornar um valor - Function FindWindow 

Lib "User32" Alias "FindWindowA" - A função será exportada do arquivo User32.dll , onde será localizada como "FindWindowA"  (a letra A indica que estamos usando a versão ANSI da função pois temos também a versão UNICODE)

ByVal lpClassName As String e ByVal lpWindowsName As String - A função usa dois parâmetros do tipo String passados por Valor

AS Long - A função retornará um valor Inteiro Longo

Nota:

O parâmetro Alias (apelido em inglês) 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 irá usar na sua aplicação VBA.

Como exemplo desta diferença podemos citar a função _lopen presente na DLL Kernel32. O nome _lopen até pode ser usado como nome de um função no VBA, mas nã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 VBA 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 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 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. Mesmo que separe as mais usadas, ainda precisará de uma boa memória para se recordar da declaração de cada uma. Ainda bem que existem ferramentas para facilitar este trabalho, uma dessas está disponível no Visual Basic e o API Viewer

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:

  1. Constants
  2. Declares
  3. Types

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.

Passando os parâmetros para a API

Declarar uma API é apenas o primeiro passo, para que efetivamente obtenha resultados. Para evocar a função declarada precisar passar os parâmetros corretos, tratando o resultado da função (seu retorno). Veja o exemplo prático:

Usaremos a função API GetDiskFreeSpace que nos dá o espaço disponível na unidade de disco indicada. 

  1. Inicie um novo projeto no VBA 
  2. Ative o API Viewer e digite os primeiros caracteres da função desejada , quando a função surgir na janela Available Items clique no botão Add . Veja abaixo

  1. Como vamos inserir a declaração no formulário padrão , deveremos alterar o escopo da declaração para Private e a seguir clicar no botão Insert para inserir a declaração no formulário do projeto. 

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

Let 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 : 

  1. lpRootPathName As String  - o nome da unidade a qual desejamos conhecer o espaço
  2. lpSectorsPerCluster As Long - o número de setores por clusters
  3. lpBytesPerSector As Long - o número de bytes por setor
  4. pNumberOfFreeClusters As Long - o número livre de clusters
  5. lpTtoalNumberOfClusters As Long - o número total de clusters

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:

sDrive = Left$(sPath, 1) & ":\"
lRetorno = GetDiskFreeSpace(sDrive, lsetoresporcluster, lbytesporsetor,lclusterlivres, ltotaldeclusters)EspacoLivre = (lsetoresporcluster * lbytesporsetor * lclusterlivres)
End Function
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


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 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 forneça uma string na lista de parâmetros e que você obtenha o resultado da variável string que 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 :

  1. lpBuffer - uma string passada por valor ( ByVal ) que irá receber o nome do computador da API
  2. nSize - usado para fornecer para a API o tamanho da string lpBuffer quando a função for chamada e também receber o tamanho da string retornada em lpBuffer pela função. 

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 strNome As String

   Dim lretorno as Long

   'Cria a variavel strstring
   strNome = String(255, Chr$(0))

   'Obtem o nome do computador
   lretorno= GetComputerName(strNome, 255)

   'remove nulos chr$(0)
   strNome = Left$(strNome, InStr(1, strNome, Chr$(0)) - 1)

   'exibe o nome do computador
   MsgBox strNome
End Sub

Observe que declaramos uma variável string strNome para receber o nome do computador retornado pela função . A seguir :

  1. Inicializamos a varíavel  -  strNome = String(255, Chr$(0)) 
  2. e após receber a o retorno da função  -  lretorno= GetComputerName(strNome, 255)
  3. precisamos extrair da variável - strNome = Left$(strNome, InStr(1, strNome, Chr$(0)) - 1)  o nome do computador. 

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  Declarar no VB como Chamar como
ATOMByVal variable As Integer Uma expressão que define um valor  n Int.
BOOL ByVal variable As LongUma expressão que define um valor   Long
BYTEByVal variable As Byte Uma expressão que define um valor   Byte
CHAR ByVal variable As ByteUma expressão que define um valor   Byte
COLORREFByVal variable As Long Uma expressão que define um valor   Long
DWORD ByVal variable As LongUma 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 LongUma expressão que define um valor   Long
LONGByVal variable As Long Uma expressão que define um valor   Long
LPARAM ByVal variable As LongUma expressão que define um valor   Long
LPDWORDvariable As Long Uma expressão que define um valor   Long
LPINT, LPUINT variable As LongUma expressão que define um valor   Long
LPRECTvariable As type Qualquer variável do tipo definido pelo usuário
LPSTR, LPCSTR ByVal variable As StringUma expressão que define um valor de  String
LPVOIDvariable As Any Qualquer (use ByVal quando passar uma string)
LPWORD variable As IntegerUma expressão que define um valor  n Int.
LRESULTByVal variable As Long Uma expressão que define um valor   Long
NULL As Any or ByVal variable As LongByVal Nothing ou ByVal 0& ou vbNullString
SHORTByVal variable As Integer Uma expressão que define um valor  n Int.
VOID Sub procedureNão aplicável
WORDByVal variable As Integer Uma expressão que define um valor de n Int.
WPARAMByVal 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 

  • Byte - um inteiro de 8 bits
  • Integer - um inteiro de 16 bits
  • Long - um inteiro de 32 bits
  • String - uma variável string de comprimento variável
  • Any - suporta qualquer um dos outros tipos

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ávelminhavar. 

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 

  1. As strings sempre são passadas por Valor ( ByVal ). Porém a função API poderá alterar o conteúdo da variável string.
  2. As estruturas definidas pelo usuário são sempre passadas por referência ( ByRef )
  3. Os Vetores ( Arrays ) sempre são passados ByRef quando passados por inteiro para a função API.
  4. Os valores numéricos podem ser passados por Valor ou por Referência dependendo da função

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çãoFlashWindow.

- 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çãoFlashWindow:

Private Declare Function FlashWindow Lib "user32" Alias "FlashWindow" (ByVal hwnd As Long, ByVal bInvert As Long) As Long
  1. O procedimento será visível somente no formulário - Private
  2. O procedimento irá retornar um Valor - Function 
  3. O nome da função usado no VB será - FlashWindow
  4. Estamos usando a DLL - User32
  5. O nome da função API na DLL é - FlashWindow
  6. A função solicita dois argumentos :
  • Hwnd - o Handle , um número que identifica a janela.
  • bInvert - Informa se o título da janela será invertido ou não. True inverte a cor do título e False volta ao estado original
  1. O tipo de dados retornado será do tipo Long : Verdadeiro( 1 ) ou Falso ( 0 )

-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()
  Me.Caption = "Olá , Estou piscando para você.."
  SimNao = True        'piscar
End Sub


Private Sub Command2_Click()
   Me.Caption = "Olá, cansei de piscar..."
   SimNao = False       ' parar de piscar
End Sub


Private Sub Timer1_Timer()
   lngRet = FlashWindow(Me.hwnd, SimNao)
End Sub

- 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: 

  1. O identificador do objeto ( janela, formulário, controle) para onde a mensagem será enviada.
  2. O identificador da mensagem 
  3. Dois parâmetros que vão depender da mensagem.

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:

  • Inicie o API Viewer e selecione na opção File do Menu o item - Load Text File
  • A seguir selecione o arquivo - Win32Api.txt
  • Na Combo - API Type - Selecione Constants
  • Na caixa de texto a seguir digite as letras lb_f
  • Em Available Items , selecione LB_FINDSTRING=&H18F
  • Clique  no botão Add e a seguir no botão Copy 

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()
   With List1
        .AddItem "Computador"
        .AddItem "Monitor"
        .AddItem "Modem"
        .AddItem "Impressora"
        .AddItem "Scanner"
        .AddItem "Placa de Som"
        .AddItem "Teclado"
        .AddItem "CD-Rom"
        .AddItem "Mouse"
  End With
End Sub


Private Sub Text1_Change()
  'Retorna o item de listindex
  List1.ListIndex = 
SendMessage(List1.hwnd, LB_FINDSTRING, -1, ByVal CStr(Text1.Text))
End Sub

-Como funciona:

- Quando você digitar algo na caixa de texto o evento text1_Change ira invocar a função SendMessage, assim:

  • SendMessage enviará uma mensagem para o controle List1. O controle é identificado pelo seu Handle. List1.hwnd
  • O outro parâmetro - LB_FINDSTRING - indica que o caractere será procurado no controle List1.
  • Cstr(Text1.text) é a string que será procurada.

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 dePostMessage é:

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
  1. hwnd é o número que identifica o objeto para o qual a mensagem é enviada
  2. wMsg é a mensagem a ser enviada
  3. wParam e lParam vão depender da mensagem

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


Estou transcrevendo algumas funções para que possa testar e se familiarizar:

A função CreateProcess criará um novo processo no segmento primário e este executará o arquivo especificado.

Const INFINITE = &HFFFF
Const STARTF_USESHOWWINDOW = &H1
Private Enum enSW
SW_HIDE = 0
SW_NORMAL = 1
SW_MAXIMIZE = 3
SW_MINIMIZE = 6
End Enum

Private Type PROCESS_INFORMATION
hProcess As Long
hThread As Long
dwProcessId As Long
dwThreadId As Long
End Type

Private Type STARTUPINFO
cb As Long
lpReserved As String
lpDesktop As String
lpTitle As String
dwX As Long
dwY As Long
dwXSize As Long
dwYSize As Long
dwXCountChars As Long
dwYCountChars As Long
dwFillAttribute As Long
dwFlags As Long
wShowWindow As Integer
cbReserved2 As Integer
lpReserved2 As Byte
hStdInput As Long
hStdOutput As Long
hStdError As Long
End Type

Private Type SECURITY_ATTRIBUTES
nLength As Long
lpSecurityDescriptor As Long
bInheritHandle As Long
End Type

Private Enum enPriority_Class
NORMAL_PRIORITY_CLASS = &H20
IDLE_PRIORITY_CLASS = &H40
HIGH_PRIORITY_CLASS = &H80
End Enum

Private Declare Function CreateProcess Lib "kernel32" Alias "CreateProcessA" (ByVal lpApplicationName As _ String, ByVal lpCommandLine As String, lpProcessAttributes As SECURITY_ATTRIBUTES, _ lpThreadAttributes As SECURITY_ATTRIBUTES, ByVal bInheritHandles As Long, ByVal dwCreationFlags _ As Long, lpEnvironment As Any, ByVal lpCurrentDriectory As String, lpStartupInfo As STARTUPINFO, _ lpProcessInformation As PROCESS_INFORMATION) As Long

Private Declare Function WaitForSingleObject Lib "kernel32" (ByVal hHandle As Long, ByVal dwMilliseconds _ As Long) As Long

Private Function SuperShell(ByVal App As String, ByVal WorkDir As String, dwMilliseconds As Long, ByVal _ start_size As enSW, ByVal Priority_Class As enPriority_Class) As Boolean
Dim pclass As Long
Dim sinfo As STARTUPINFO
Dim pinfo As PROCESS_INFORMATION
'Not used, but needed
Dim sec1 As SECURITY_ATTRIBUTES
Dim sec2 As SECURITY_ATTRIBUTES
'Set the structure size
sec1.nLength = Len(sec1)
sec2.nLength = Len(sec2)
sinfo.cb = Len(sinfo)
'Set the flags
sinfo.dwFlags = STARTF_USESHOWWINDOW
'Set the window's startup position
sinfo.wShowWindow = start_size
'Set the priority class
pclass = Priority_Class

'Start the program
If CreateProcess(vbNullString, App, sec1, sec2, False, pclass, _
0&, WorkDir, sinfo, pinfo) Then
'Wait
WaitForSingleObject pinfo.hProcess, dwMilliseconds
SuperShell = True
Else
SuperShell = False
End If
End Function

Private Sub Form_Load()
'Set the dialog's title
CDBox.DialogTitle = "Choose an EXEC-File ..."
'Error when canceled
CDBox.CancelError = True
'Set the dialog's filter
CDBox.Filter = "EXEC-Files (*.exe)|*.exe|All files (*.*)|*.*"
'Show the 'Open File'-dialog
CDBox.ShowOpen
'Execute the program
SuperShell CDBox.filename, Left$(CDBox.filename, Len(CDBox.filename) - Len(CDBox.FileTitle)), 0, SW_NORMAL, HIGH_PRIORITY_CLASS
End
End Sub

A função FindWindow (FindWindow) recupera o identificador de uma janela de nível superior. Esta não procura janelas filho e não diferencia letras maiúsculas de minúsculas. Para buscar janelas filho use a função FindWindowEx.

Private Declare Function FindWindow Lib "USER32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long

Private Declare PtrSafe Function FindWindow Lib "USER32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As LongPtr

A função FindWindowEx assim como a anterior, recupera um identificador de uma janela filho. Também não diferencia entre maiúsculas de minúsculas.

Private Declare Function FindWindowEx Lib "USER32" _
                                  Alias "FindWindowExA" (ByVal hWnd1 As Long, ByVal hWnd2 As Long, _
                                  ByVal lpsz1 As String, ByVal lpsz2 As String) As Long

Private Declare PtrSafe Function FindWindowEx Lib "USER32" _
                                  Alias "FindWindowExA" (ByVal hWnd1 As LongPtr, ByVal hWnd2 As LongPtr, _
                                  ByVal lpsz1 As String, ByVal lpsz2 As String) As LongPtr

A GDI+ (Detalhes aqui) expõe uma API simples que consiste em cerca de 600 funções, as quais são implementadas através da biblioteca Gdiplus.dll e declarada no Gdiplusflat.h. As funções do API GDI+ são compostas por uma coleção de cerca de 40 classes C++. Recomenda-se que não as chame diretamente, ao fazer as chamadas deve fazê-lo chamando os métodos e funções fornecidas pelo C++

Private Declare Function GdipCreateBitmapFromFile Lib "GDIPlus" (ByVal filename As Long, bitmap As Long) As Long

Private Declare PtrSafe Function GdipCreateBitmapFromFile Lib "GDIPlus" (ByVal filename As LongPtr, bitmap As LongPtr) As LongPtr

A função OleCreatePictureIndirect (Detalhes) cria um objeto de imagem nova inicializada de acordo com uma estrutura PICTDESC.

Private Declare Function OleCreatePictureIndirect Lib "oleaut32.dll" (PicDesc As PICTDESC, RefIID As GUID, ByVal fPictureOwnsHandle As Long, IPic As IPicture) As Long

Private Type PICTDESC
    Size As Long
    Type As Long
    hPic As Long
    hPal As Long
End Type

Private Declare PtrSafe Function OleCreatePictureIndirect Lib "oleaut32.dll" (PicDesc As PICTDESC, RefIID As GUID, ByVal fPictureOwnsHandle As LongPtr, IPic As IPicture) As LongPtr

Private Type PICTDESC
    Size As Long
    Type As Long
    hPic As LongPtr
    hPal As LongPtr
End Type

A função GetClassName recupera o nome da classe à qual pertence a janela especificada.

(ByVal hWnd As LongPtr, ByVal lpClassName As String, _
Public Declare Function GetClassName Lib "USER32" Alias "GetClassNameA" _
                                     (ByVal hWnd As Long, ByVal lpClassName As String, _
                                      ByVal nMaxCount As Long) As Long

Public Declare PtrSafe Function GetClassName Lib "USER32" Alias "GetClassNameA" ByVal nMaxCount As LongPtr) As Long

A função GetClassName recupera o nome da classe à qual pertence a janela especificada.

Public Declare Function GetClassName Lib "USER32" Alias "GetClassNameA" _
                                     (ByVal hWnd As Long, ByVal lpClassName As String, _
                                      ByVal nMaxCount As Long) As Long

Public Declare PtrSafe Function GetClassName Lib "USER32" Alias "GetClassNameA" _
                                     (ByVal hWnd As LongPtr, ByVal lpClassName As String, _
                                      ByVal nMaxCount As LongPtr) As Long

A função getDC recupera um identificador num contexto de dispositivo (DC) para a área Cliente de uma janela especificada ou em uma tela inteira. Podemos usar o identificador retornado nas funções GDI subseqüentes para desenhar no DC. O contexto de dispositivo será uma estrutura de dados, cujos valores são usados ​​internamente pelo GDI. A função GetDCEx é uma extensão para GetDC, e dá controle a um aplicativo.

Private Declare Function GetDC Lib "USER32" (ByVal hWnd As Long) As Long

Private Declare PtrSafe Function GetDC Lib "USER32" (ByVal hWnd As LongPtr) As LongPtr

GetDesktopWindow
Public Declare Function GetDesktopWindow Lib "USER32" () As Long
Public Declare PtrSafe Function GetDesktopWindow Lib "USER32" () As LongPtr

getDeviceCaps
Private Declare Function GetDeviceCaps Lib "gdi32" (ByVal hDC As Long, ByVal nIndex As Long) As Long
Private Declare PtrSafe Function GetDeviceCaps Lib "gdi32" (ByVal hDC As LongPtr, ByVal nIndex As Long) As Long

GetDriveType
Private Declare Function GetDriveType Lib "kernel32" Alias _
                        "GetDriveTypeA" (ByVal sDrive As String) As Long
Private Declare PtrSafe Function GetDriveType Lib "kernel32" Alias _
                                "GetDriveTypeA" (ByVal sDrive As String) As LongPtr

GetForegroundWindow
Declare Function GetForegroundWindow Lib "user32.dll" () As Long
Declare PtrSafe Function GetForegroundWindow Lib "user32.dll" () As LongPtr

getFrequency
Declare Function getFrequency Lib "kernel32" Alias "QueryPerformanceFrequency" (cyFrequency As Currency) As Long
Private Declare PtrSafe Function getFrequency Lib "kernel32" Alias "QueryPerformanceFrequency" (cyFrequency As Currency) As Long

GetKeyState
Declare Function GetKeyState Lib "USER32" (ByVal vKey As Long) As Integer
Declare PtrSafe Function GetKeyState Lib "USER32" (ByVal vKey As Long) As Integer

GetLastInputInfo
#If VBA7 Then
    Private Type LASTINPUTINFO
        cbSize As LongPtr
        dwTime As LongPtr
    End Type
    Private Declare PtrSafe Sub GetLastInputInfo Lib "USER32" (ByRef plii As LASTINPUTINFO)
#Else
    Private Type LASTINPUTINFO
        cbSize As Long
        dwTime As Long
    End Type
    Private Declare Sub GetLastInputInfo Lib "USER32" (ByRef plii As LASTINPUTINFO)
#End If

GetSystemMetrics
Private Declare Function GetSystemMetrics Lib "USER32" (ByVal nIndex As Long) As Long

Private Declare PtrSafe Function GetSystemMetrics Lib "USER32" (ByVal nIndex As Long) As Long

GetTempPath
Declare Function GetTempPath Lib "kernel32" _
                             Alias "GetTempPathA" (ByVal nBufferLength As Long, _
                                                   ByVal lpbuffer As String) As Long

Declare PtrSafe Function GetTempPath Lib "kernel32" _
                             Alias "GetTempPathA" (ByVal nBufferLength As longptr, _
                                                   ByVal lpbuffer As String) As Long

getTickCount
Private Declare Function getTickCount Lib "kernel32" Alias "QueryPerformanceCounter" (cyTickCount As Currency) As Long

Private Declare PtrSafe Function getTickCount Lib "kernel32" Alias "QueryPerformanceCounter" (cyTickCount As Currency) As Long
    '
getTime
Private Declare Function timeGetTime Lib "winmm.dll" () As Long

Private Declare PtrSafe Function timeGetTime Lib "winmm.dll" () As Long

GetWindow
Public Declare Function GetWindow Lib "USER32" _
                                  (ByVal hWnd As Long, ByVal wCmd As Long) As Long

Public Declare PtrSafe Function GetWindow Lib "USER32" _
                                  (ByVal hWnd As LongPtr, ByVal wCmd As LongPtr) As LongPtr

GetWindowLong
Private Declare Function GetWindowLong Lib "USER32" Alias "GetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long) As Long

Private Declare PtrSafe Function GetWindowLong Lib "USER32" Alias "GetWindowLongA" (ByVal hWnd As LongPtr, ByVal nIndex As Long) As LongPtr

GetWindowsDirectory
Declare Function GetWindowsDirectory& Lib "kernel32" Alias _
                                      "GetWindowsDirectoryA" (ByVal lpbuffer As String, _
                                                              ByVal nSize As Long)

Declare PtrSafe Function GetWindowsDirectory& Lib "kernel32" Alias _
                                      "GetWindowsDirectoryA" (ByVal lpbuffer As String, _
                                                              ByVal nSize As LongPtr)
GetWindowText
Public Declare Function GetWindowText Lib "USER32" Alias "GetWindowTextA" _
                                      (ByVal hWnd As Long, ByVal lpString As String, _
                                       ByVal cch As Long) As Long

Public Declare PtrSafe Function GetWindowText Lib "USER32" Alias "GetWindowTextA" _
                                      (ByVal hWnd As LongPtr, ByVal lpString As String, _
                                       ByVal cch As LongPtr) As Long

InternetGetConnectedState
Public Declare Function InternetGetConnectedState _
        Lib "wininet.dll" (lpdwFlags As Long, _
        ByVal dwReserved As Long) As Boolean

Public Declare PtrSafe Function InternetGetConnectedState _
        Lib "wininet.dll" (lpdwFlags As LongPtr, _
        ByVal dwReserved As long) As Boolean

IsCharAlphaNumericA
Private Declare Function IsCharAlphaNumericA Lib "USER32" (ByVal byChar As Byte) As Long

Private Declare PtrSafe Function IsCharAlphaNumericA Lib "USER32" (ByVal byChar As Byte) As Long

ReleaseDC
Private Declare Function ReleaseDC Lib "USER32" (ByVal hWnd As Long, ByVal hDC As Long) As Long

Private Declare PtrSafe Function ReleaseDC Lib "USER32" (ByVal hWnd As LongPtr, ByVal hDC As LongPtr) As Long

SendMessage
Public Declare Function SendMessageA Lib "user32" (ByVal hWnd As Long, ByVal wMsg As Long, _
                                                   ByVal wParam As Long, lParam As Any) As Long
Public Declare PtrSafe Function SendMessageA Lib "user32" (ByVal hWnd As LongPtr, ByVal wMsg As Long, _
                                                           ByVal wParam As LongPtr, lParam As Any) As LongPtr

SetActiveWindow
Declare Function SetActiveWindow Lib "user32.dll" (ByVal hWnd As Long) As Long

Declare PtrSafe Function SetActiveWindow Lib "user32.dll" (ByVal hWnd As LongPtr) As LongPtr

SetCurrentDirectory
Private Declare Function SetCurrentDirectoryA Lib "kernel32" (ByVal lpPathName As String) As Long

Private Declare PtrSafe Function SetCurrentDirectoryA Lib "kernel32" (ByVal lpPathName As String) As Long

SetWindowLongPtr
Private Declare Function SetWindowLongPtr Lib "USER32" Alias "SetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long

Private Declare PtrSafe Function SetWindowLongPtr Lib "USER32" Alias "SetWindowLongA" (ByVal hWnd As LongPtr, ByVal nIndex As Long, ByVal dwNewLong As LongPtr) As LongPtr

SHBrowseForFolder
#If VBA7 Then
    Private Type BROWSEINFO
        hOwner As LongPtr
        pidlRoot As Longp
        pszDisplayName As String
        lpszTitle As String
        ulFlags As Long
        lpfn As LongPtr
        lParam As LongPtr
        iImage As Long
    End Type
                        
    Private Declare PtrSafe Function SHBrowseForFolder Lib "shell32.dll" Alias "SHBrowseForFolderA" _
        (lpBrowseInfo As BROWSEINFO) As LongPtr
#Else
    Private Type BROWSEINFO
        hOwner As Long
        pidlRoot As Long
        pszDisplayName As String
        lpszTitle As String
        ulFlags As Long
        lpfn As Long
        lParam As Long
        iImage As Long
    End Type
                        
    Private Declare Function SHBrowseForFolder Lib "shell32.dll" Alias "SHBrowseForFolderA" _
        (lpBrowseInfo As BROWSEINFO) As Long
#End If
Private Const BIF_RETURNONLYFSDIRS = &H1

ShellExecute
Private Declare Function ShellExecute Lib "shell32.dll" Alias "ShellExecuteA" ( _
        ByVal hwnd As Long, ByVal lpOperation As String, ByVal lpFile As String, _
        ByVal lpParameters As String, ByVal lpDirectory As String, ByVal nShowCmd As Long) As Long

Private Declare PtrSafe Function ShellExecute Lib "shell32.dll" Alias "ShellExecuteA" ( _
        ByVal hwnd As LongPtr, ByVal lpOperation As String, ByVal lpFile As String, _
        ByVal lpParameters As String, ByVal lpDirectory As String, ByVal nShowCmd As Long) As LongPtr

SHFileOperation
#If VBA7 Then
    Type SHFILEOPSTRUCT
        hWnd As LongPtr
        wFunc As Long
        pFrom As String
        pTo As String
        fFlags As Integer
        fAborted As Boolean
        hNameMaps As Longptr
        sProgress As String
    End Type
    Declare PtrSafe Function SHFileOperation Lib "shell32.dll" Alias "SHFileOperationA" _
                                     (lpFileOp As SHFILEOPSTRUCT) As LongPtr
#Else
    Type SHFILEOPSTRUCT
        hWnd As Long
        wFunc As Long
        pFrom As String
        pTo As String
        fFlags As Integer
        fAborted As Boolean
        hNameMaps As Long
        sProgress As String
    End Type
    Declare Function SHFileOperation Lib "shell32.dll" Alias "SHFileOperationA" _
                                     (lpFileOp As SHFILEOPSTRUCT) As Long
#End If

SHGetPathFromIDList
Private Declare Function SHGetPathFromIDList Lib "shell32.dll" Alias "SHGetPathFromIDListA" _
        (ByVal pidl As Long, ByVal pszPath As String) As Boolean

Private Declare PtrSafe Function SHGetPathFromIDList Lib "shell32.dll" Alias "SHGetPathFromIDListA" _
        (ByVal pidl As LongPtr, ByVal pszPath As String) As Boolean

timeGetTime
Private Declare Function timeGetTime Lib "winmm.dll" () As Long

Private Declare PtrSafe Function timeGetTime Lib "winmm.dll" () As Long

Tags: Excel, VBA, API, GDI+, GetClassName, OleCreatePictureIndirect, FindWindowEx, FindWindow,CreateProcess



Nenhum comentário:

Postar um comentário

eBooks VBA na AMAZOM.com.br

Vitrine