2009-10-29 22 views
3

Je sais que je peux recevoir des messages avec le code ci-dessous dans C#, comment puis-je envoyer à vb6, et recevoir en vb6, et envoyer à partir de vb6?Comment envoyer/recevoir des messages Windows entre VB6 et C#?

[System.Security.Permissions.PermissionSet(System.Security.Permissions.SecurityAction.Demand, Name = "FullTrust")] 
    protected override void WndProc(ref Message m) 
    { 

     int _iWParam = (int)m.WParam; 
     int _iLParam = (int)m.LParam; 
     switch ((ECGCardioCard.APIMessage)m.WParam) 
     { 
      // handling code goes here 
     } 
     base.WndProc(ref m); 
    } 

Répondre

5

Avant de commencer, je voudrais dire que je suis d'accord avec MarkJ. COM Interop vous facilitera la vie et ne vous demandera pas de faire autant de travail.

SendMessage est le moyen préféré d'appeler un côté ou l'autre via les gestionnaires de messages Windows. PostMessage est difficile à utiliser avec des types complexes, car la durée de vie des données associées à un message Windows dans .NET et VB6 est difficile à gérer pendant la mise en file d'attente du message et la fin du message est inconnue sauf si vous implémentez un mécanisme de rappel . De toute façon, l'envoi de messages Windows de n'importe où à une fenêtre C# nécessite simplement que vous connaissiez le HWND de la fenêtre C# qui doit recevoir le message. Votre extrait semble correct en tant que gestionnaire, sauf que l'instruction switch doit d'abord vérifier le paramètre Msg.

protected override void WndProc(ref Message m) 
{ 

    int _iWParam = (int)m.WParam; 
    int _iLParam = (int)m.LParam; 
    switch ((ECGCardioCard.APIMessage)m.Msg) 
    { 
      // handling code goes here 
    } 
    base.WndProc(ref m); 
} 

Récupération peut être fait une poignée de fenêtre à partir d'un formulaire C#, Fenêtre ou contrôle via la propriété .Handle.

Control.Handle Property @ MSDN

Nous supposerons ici que vous avez une façon de transférer la poignée de fenêtre de C# pour VB6.

De VB6, la signature de la fenêtre SendMessage est la suivante:

Private Declare Function SendMessage Lib "USER32.DLL" _ 
    (ByVal hWnd As Long, ByVal uMsg As Long, _ 
    ByVal wParam As Long, ByVal lParam As Long) As Long 

Pour appeler, vous feriez quelque chose comme ce qui suit. Par souci de concision, uMsg est WM_APP (32768), wParam/lParam sont 0:

Dim retval As Long 
retval = SendMessage(hWnd, 32768, 0, 0) 

De même, l'envoi d'un message de C# est similaire. Pour obtenir le HWND d'une fenêtre dans VB6, utilisez la propriété .hWnd de la fenêtre dans VB6 qui devrait recevoir le message.

Comme il semble que vous utilisez votre propre ensemble d'identifiants de message, il existe des étapes supplémentaires pour gérer les identifiants de message personnalisés dans VB6. La plupart des personnes gèrent cela en sous-classant une fenêtre de formulaire et en utilisant la procédure de sous-classe pour filtrer ces messages. J'ai inclus un exemple de code pour démontrer C# à VB6, car la gestion des messages personnalisés est plus compliquée dans VB6.

Voici le code source de la paire de programmes de test, une bibliothèque C# et un projet de formulaires VB6. La bibliothèque C# doit être configurée avec "Register for COM Interop" et "Make Assembly COM-Visible" dans les paramètres du projet.

D'abord, la bibliothèque C#. Cette bibliothèque contient un seul composant COM qui sera visible à VB6 sous le type 'CSMessageLibrary.TestSenderSimple'. Notez que vous devez inclure une signature P/Invoke (comme la méthode VB6) pour SendMessage.Maintenant, du côté VB6, vous aurez besoin d'ajouter un support pour sous-classer une fenêtre. Mis à part de meilleures solutions qui peuvent être appliquées par fenêtre, nous allons juste aller avec quelque chose qui montre comment configurer une seule fenêtre. Tout d'abord, pour exécuter cet exemple, assurez-vous que vous avez construit l'application C# et que vous l'avez correctement enregistré avec COM. Ajoutez ensuite une référence de VB6 au fichier .tlb qui se trouve à côté de la sortie C#. Vous le trouverez dans le répertoire bin/Debug ou bin/Release sous le projet C#.

Le code suivant doit être placé dans un module. Dans mon projet de test j'ai utilisé un module appelé 'Module1'. Les définitions suivantes doivent être notées dans ce module. WM_APP - Utilisé comme un identificateur de message personnalisé qui sera sans interférence.
GWL_WNDPROC - Constante utilisée pour SetWindowLong pour demander une modification du gestionnaire de fenêtre.
SetWindowLong - Fonction Win32 qui peut modifier les attributs spéciaux sur les fenêtres.
CallWindowProc - Fonction Win32 qui peut transmettre des messages Windows à un gestionnaire de fenêtre désigné (fonction).
SubclassWindow - Fonction de module pour configurer le sous-classement pour une fenêtre désignée. UnsubclassWindow - Fonction de module pour démonter le sous-classement pour une fenêtre désignée.

SubWndProc - Fonction du module qui sera insérée via le sous-classement, pour nous permettre d'intercepter les messages Windows personnalisés.

Public Const WM_APP As Long = 32768 
Private Const GWL_WNDPROC = (-4) 
Private procOld As Long 

Private Declare Function CallWindowProc Lib "USER32.DLL" Alias "CallWindowProcA" _ 
    (ByVal lpPrevWndFunc As Long, ByVal hWnd As Long, ByVal uMsg As Long, _ 
    ByVal wParam As Long, ByVal lParam As Long) As Long 

Private Declare Function SetWindowLong Lib "USER32.DLL" Alias "SetWindowLongA" _ 
    (ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long 

Public Sub SubclassWindow(ByVal hWnd As Long) 
    procOld = SetWindowLong(hWnd, GWL_WNDPROC, AddressOf SubWndProc) 
End Sub 

Public Sub UnsubclassWindow(ByVal hWnd As Long) 
    procOld = SetWindowLong(hWnd, GWL_WNDPROC, procOld) 
End Sub 

Private Function SubWndProc(_ 
     ByVal hWnd As Long, _ 
     ByVal iMsg As Long, _ 
     ByVal wParam As Long, _ 
     ByVal lParam As Long) As Long 

    If hWnd = Form1.hWnd Then 
     If iMsg = WM_APP Then 
      Dim strInfo As String 
      strInfo = "wParam: " & CStr(wParam) & vbCrLf & "lParam: " & CStr(lParam) 

      Call MsgBox(strInfo, vbOKOnly, "WM_APP Received!") 

      SubWndProc = True 
      Exit Function 
     End If 
    End If 

    SubWndProc = CallWindowProc(procOld, hWnd, iMsg, wParam, lParam) 
End Function 

Dans le formulaire de test, j'ai câblé une instance de l'objet C# de test en tant que membre du formulaire. Le formulaire inclut un bouton dont l'ID est 'Command1'. La sous-classe est configurée lorsque le formulaire est chargé, puis supprimée lorsque le formulaire est fermé.

Dim CSharpClient As New CSMessageLibrary.TestSenderSimple 

Private Sub Command1_Click() 
    CSharpClient.DoTest (42) 
End Sub 

Private Sub Form_Load() 
    CSharpClient.hostwindow = Form1.hWnd 
    Module1.SubclassWindow (Form1.hWnd) 
End Sub 

Private Sub Form_Unload(Cancel As Integer) 
    CSharpClient.hostwindow = 0 
    Module1.UnsubclassWindow (Form1.hWnd) 
End Sub 

Envoi d'arguments numériques qui correspondent à 4 octets est trivial, soit en tant que wParam ou lParam. Cependant, l'envoi de types complexes et de chaînes est beaucoup plus difficile. Je vois que vous avez créé une question distincte pour cela, alors je vais fournir des réponses là-dessus.

REF: How do I send a struct from C# to VB6, and from VB6 to C#?

+1

+1. Il y a une façon plus "objecty" de faire le sous-classement VB6 si http://visualstudiomagazine.com/articles/2009/07/16/subclassing-the-xp-way.aspx – MarkJ

+0

Je suis allé avec cette méthode juste pour garder l'échantillon plus court. La technique à ce lien est définitivement supérieure, cependant. – meklarian

+0

Quel super article !! +1 – used2could

3

Pour envoyer en VB6, vous devez utiliser un appel API (SendMessage ou PostMessage). Pour recevoir en VB6 vous devez utiliser le sous-classement (compliqué - voici le best way I know).

Avez-vous envisagé d'utiliser COM Interop à la place? C'est un moyen beaucoup plus facile de communiquer entre VB6 et C# que les messages Windows.

+0

+1 COM et VB sont comme les pois et les carottes. – kenny

1

Utilisez la fonction API PostMessage de Windows.

Au début de votre classe:

[DllImport("User32.dll", EntryPoint="PostMessage")] 
private static extern int PostMessage(int hWnd, int Msg, int wParam, int lParam); 

const int WM_USER = 0x0400; 
const int CM_MARK = WM_USER + 1; 

poignée Ensuite, le message en remplaçant WndProc de la classe.

protected override void WndProc(ref Message m) 
{ 
    if (m.Msg == CM_MARK) { 
    if (this.ActiveControl is TextBox) { 
     ((TextBox)this.ActiveControl).SelectAll(); 
    } 
    } 
    base.WndProc(ref m); 
} // end sub. 

Ensuite, dans votre événement Entrée:

private void txtMedia_Enter(object sender, EventArgs e) 
{ 
    PostMessage(Handle.ToInt32(), CM_MARK, 0, 0); 
} // end sub. 

Cela fonctionne parce que vous forcez votre traitement personnalisé à se produire après que Windows fait son traitement par défaut Entrée événement et il est associé de manipulation de la souris. Vous placez votre requête dans la file d'attente des messages et elle est gérée à tour de rôle dans l'événement WndProc. Lorsque votre événement est appelé, assurez-vous que la fenêtre actuelle est une zone de texte et sélectionnez-la si c'est le cas.