Communication entre processus (avec données)

Quelques explications

La communication entre processus peut se faire à partir d'échange de chaînes de caractères, dans la mesure où il est possible pour un processus de contourner le problème de la frontière de son espace adressable. La fonction SendMessage() pour passer un message de type WM_COPYDATA peut servir à cette fin.

VB ne supporte pas l'utilisation de pointeurs et de conversions explicites de types à la sauce C++. La chaînes de caractère VB doivent d'abord être transformées de leur format Unicode au format ASCII avant d'être envoyées, puis reconverties en réception.

L'exemple ci-après:

  • Convertit une chaîne de caractères en tableau d'octets à l'aide de la fonction CopyMemory();
  • Trouve l'adresse de ce tableau d'octets (nous sommes en VB ici, pas en C++) à l'aide de la fonction VarPtr(), et copie cette adresse (de même que la taille du tableau) dans une structure de type COPYDATASTRUCT;
  • Passe ce COPYDATASTRUCT à une autre application à l'aide du message WM_COPYDATA;
  • Décode le tout en réception à l'aide de la fonction CopyMemory() et reconvertit le tableau d'octets en chaîne Unicode à l'aide de la fonction StrConv().
  • Générer l'application en réception

  • Démarrez un nouveau VB et choisissez un .EXE standard.
  • Ajoutez un Label au formulaire form1.
  • Copiez le code suivant dans la fenetre de code du formulaire form1:

  • 
    Private Sub Form_Load()
      gHW = Me.hWnd
      Hook
      Me.Caption = "Target"
      Me.Show
      Label1.Caption = Hex$(gHW)
    End Sub
    
    Private Sub Form_Unload(Cancel As Integer)
      Unhook
    End Sub
        

  • Ajoutez un module au projet et insérez-y le code suivant:

  • 
    
    Private Type COPYDATASTRUCT
      dwData As Long
      cbData As Long
      lpData As Long
    End Type
    
    Private Const WM_COPYDATA = &H4A
    
    Public Const GWL_WNDPROC = (-4)
    Global lpPrevWndProc As Long
    Global gHW As Long
    
    'Équivalent de memcpy().
    Private 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 "J'ai reçu 1"
        Case 2
          Debug.Print "J'ai reçu 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.Print a$
      End Select
    End Sub
        

  • Sauvegardez le tout et réduisez VB.
  • Générer l'application en envoi

  • Démarrez un nouveau VB et choisissez un .EXE standard.
  • Ajoutez un CommandButton au formulaire form1.
  • Copiez le code suivant dans la fenetre de code du formulaire 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
    
    'Équivalent de memcpy().
    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
    
      'Trouver le hWnd du processus en réception
      ThWnd = FindWindow(vbNullString, "Target")
      a$ = "Ça marche Jean-Marc!"
      'Copier la chaîne dans un tableau 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()
      'Trouve le hWnd du processus en réception, pour
      'l'afficher et montrer que tout va bien
      Me.Caption = Hex$(FindWindow(vbNullString, "Target"))
    End Sub
        

  • Sauvegardez le tout et réduisez VB.
  • Éxécuter le tout

  • Démarrer l'application en réception;
  • Démarrer l'application en envoi (notez bien la valeur du hWnd telle qu'affichée);
  • S'amuser avec le tout.