Visual Basic, VB .NET, ASP, Active X, Access, SQL Server

Passando Strings Entre Aplicações no VB Usando a API SendMessage

Há muitas maneiras de se conseguir comunicações entre processos usando o Visual Basic. A menos que você estabeleça um relacionamento usando OLE do tipo cliente/servidor entre duas aplicações, dados em strings são difíceis de serem trocados. A principal razão é que, em 32-bits, cada aplicação roda no seu próprio espaço de endereçamento de memória e o endereço de uma variável num processo nada significa para os outros processos. Usando a API SendMessage para passar uma mensagem WM_COPYDATA, no entanto, podemos contornar este problema.

Este artigo demonstra como passar um string de uma aplicação para outra usando SendMessage com a mensagem WM_COPYDATA.

Exemplo Passo-a-Passo

  1. Convertendo a string para uma matriz de bytes usando a API CopyMemory().

  2. Obtendo o endereço da matriz usando VarPtr e copiando o endereço e o comprimento da matriz para uma  estrutura COPYDATASTRUCT.

  3. Passando a estrutura COPYDATASTRUCT para outra aplicação usando a mensagem WM_COPYDATA, configurando a outra aplicação para receber a mensagem.

  4. Obtendo os dados da estrutura na aplicação de destino com CopyMemory() e convertendo a matriz de bytes de volta para uma string usando StrConv.
A próxima seção mostra como você pode criar um programa de exemplo que demonstra como passar strings de uma aplicação para outra.

Passos Para Criar o Exemplo

Para criar este exemplo, você cria dois projetos em separado: um projeto remetente e outro destinatário. Por razões de simplicidade, remova a opção Option Explicit dos módulos de código e de formulários que criar para os exemplos abaixo.

Criando a aplicação destinatária:

  1. Inicie um novo projeto no VB. Este será a sua aplicação destinatária.
  2. Adicione um controle Label ao Form1
  3. Cope o código a seguir para a janela de código de Form1:


          Private Sub Form_Load()
              gHW = Me.hWnd
              Hook
              Me.Caption = "Destino"
              Me.Show
              Label1.Caption = Hex$(gHW)
          End Sub

          Private Sub Form_Unload(Cancel As Integer)
              Unhook
          End Sub 
  4. Adicione um módulo ao projeto e cole o seguinte código na janela de código do módulo:

         Type COPYDATASTRUCT
                  dwData As Long
                  cbData As Long
                  lpData As Long
          End Type

          Public Const GWL_WNDPROC = (-4)
          Public Const WM_COPYDATA = &H4A
          Global lpPrevWndProc As Long
          Global gHW As Long

          'Copia um bloco de memória de um local para o outro

          Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" _
             (hpvDest As Any, hpvSource As Any, ByVal cbCopy As Long)

          Declare Function CallWindowProc Lib "user32" Alias _
             "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hwnd As _
             Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As _
             Long) As Long

          Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" _
             (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As _
             Long) As Long

          Public Sub Hook()
              lpPrevWndProc = SetWindowLong(gHW, GWL_WNDPROC, _
              AddressOf WindowProc)
              Debug.Print lpPrevWndProc
          End Sub

          Public Sub Unhook()
              Dim temp As Long
              temp = SetWindowLong(gHW, GWL_WNDPROC, lpPrevWndProc)
          End Sub

          Function WindowProc(ByVal hw As Long, ByVal uMsg As Long, _
             ByVal wParam As Long, ByVal lParam As Long) As Long
              If uMsg = WM_COPYDATA Then
                  Call mySub(lParam)
              End If
              WindowProc = CallWindowProc(lpPrevWndProc, hw, uMsg, wParam, _
                 lParam)
          End Function

          Sub mySub(lParam As Long)
              Dim cds As COPYDATASTRUCT
              Dim buf(1 To 255) As Byte

              Call CopyMemory(cds, ByVal lParam, Len(cds))

              Select Case cds.dwData
               Case 1
                  Debug.Print "pegueu um 1"
               Case 2
                  Debug.Print "pegui um 2"
               Case 3
                  Call CopyMemory(buf(1), ByVal cds.lpData, cds.cbData)
                  a$ = StrConv(buf, vbUnicode)
                  a$ = Left$(a$, InStr(1, a$, Chr$(0)) - 1)
                  Form1.Label1.Caption = a$
              End Select
          End Sub
  5. Salve o projeto e minimize o VB.

Criando a Aplicação Remetente

  1. Inicie uma segunda instância do Visual Basic e crie um novo projeto no VB.

  2. Adicione um botão ao Form1.

  3. Copie o código seguinte para a janela de código do Form1:

    Private Type COPYDATASTRUCT
          dwData As Long
          cbData As Long
          lpData As Long
    End Type
    Private Const WM_COPYDATA = &H4A

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

          Private Declare Function SendMessage Lib "user32" Alias _
             "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal _
             wParam As Long, lParam As Any) As Long

          'Copies a block of memory from one location to another.
          Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" _
             (hpvDest As Any, hpvSource As Any, ByVal cbCopy As Long)

          Private Sub Command1_Click()
              Dim cds As COPYDATASTRUCT
              Dim ThWnd As Long
              Dim buf(1 To 255) As Byte

          ' Obtém o hWnd da aplicação de destino
              ThWnd = FindWindow(vbNullString, "Destino")
              a$ = "Isto funciona!"
          ' Copia a string em uma matriz de bytes, convertendo-a para ASCII
              Call CopyMemory(buf(1), ByVal a$, Len(a$))
              cds.dwData = 3
              cds.cbData = Len(a$) + 1
              cds.lpData = VarPtr(buf(1))
              i = SendMessage(ThWnd, WM_COPYDATA, Me.hwnd, cds)
          End Sub

          Private Sub Form_Load()
          ' Isto lhe dá a visão de que a aplicaçãoo de destino está rodando
          ' e você está endereçando para a janela correta
              Me.Caption = Hex$(FindWindow(vbNullString, "Destino"))
          End Sub
  4. Salve o projeto

Executando o Exemplo

  1. Rode a aplicação de destino pressionando F5. Note que o valor de hWnd é exibido no label.

  2. Rode a aplicação remetente pressionando F5. Verifique que o hWnd no título do formulário bate com o hWnd exibido no label da aplicação de destino. Clique no botão e a mensagem de texto "Isto funciona!" será exibida no label do  formulário da aplicação de destino.