2010-12-02 5 views
2

J'ai deux applications mdi, qui récupèrent toutes deux leurs données de la même base de données. Les deux applications doivent pouvoir envoyer des messages les unes aux autres pour rester synchronisées. Les messages transmis ne contiennent qu'une chaîne indiquant à l'application destinataire la partie de la base de données à consulter (un numéro de travail et d'autres informations connexes). Les deux applications ont un gestionnaire de message, instancié lorsque chaque programme démarre. Lorsqu'un message est envoyé de l'application VB6 à l'application C#, il voit le message et agit de manière appropriée, mais lorsque j'envoie le même type de message de l'application C# à l'application VB6, il semble voir le message événement, mais lors du déballage, ne voit qu'une partie des données, puis ignore le message.Messagerie interopérabilité entre applications C# et VB6 mdi

Je pense que je peux être en train de formater quelque chose de faux sur la fin de C#. Voici la méthode qui envoie le message suivant:

namespace InterProcessMessaging 
{ 
[StructLayout(LayoutKind.Sequential)] 
    public struct COPYDATASTRUCT 
    { 
     public IntPtr dwData;//a pointer to a number use this to identify your message 
     public IntPtr lpData;//a pointer to the address of the data 
     public IntPtr cbData;//a pointer to the number of bytes to be transferred 

    } 
public class clsMessaging : System.Windows.Forms.NativeWindow, IDisposable 
{ 
//API function to send async. message to target application 
     [DllImport("user32.dll", CharSet = CharSet.Ansi)] 
     public static extern IntPtr SendMessageA(IntPtr hwnd, Int32 wMsg, Int32 wParam, COPYDATASTRUCT lParam); 

    public void SendMessageToVB6(string sendMsg, string WindowsAppTitle) 
    { 
      try 
      { 

       IntPtr hwndTarget = FindWindow(null, WindowsAppTitle); 

       IntPtr pDWData = Marshal.AllocHGlobal(sizeof(Int32));//a pointer to a number used this to identify your message 
       Marshal.StructureToPtr(3, pDWData, true);//place the value 3 at this location 

       IntPtr pLPData = Marshal.StringToHGlobalAnsi(sendMsg.Trim());//a pointer to the address of the data 

       IntPtr pCBData = Marshal.AllocHGlobal(sizeof(Int32));//a pointer to the number of bytes to be transferred 
       Marshal.StructureToPtr(sendMsg.Trim().Length+1, pCBData, true);//place the size of the string at this location 

       COPYDATASTRUCT cds;//a structure containing the three pointers above 
       cds.dwData = pDWData;//a pointer to a number used this to identify your message (3) 
       cds.lpData = pLPData;//a pointer to the address of the data 
       cds.cbData = pCBData;//a pointer to the number of bytes to be transferred 

       if (!System.IntPtr.Zero.Equals(hwndTarget)) 
       { 
        SendMessageA(hwndTarget, 74, 0, cds); 
       } 
      } 
      catch (Exception ex) 
      { 
       Debug.Print(ex.InnerException.ToString()); 
      } 
    } 
} 
} 

Répondre

1

Cela fonctionne:

public struct COPYDATASTRUCT 
{ 
    public IntPtr dwData; 
    public UInt32 cbData; 
    [MarshalAs(UnmanagedType.LPStr)] 
    public string lpData; 
} 

[DllImport("User32.dll", EntryPoint = "SendMessage")] 
     public static extern IntPtr SendMessage(IntPtr hWnd, int Msg, int wParam, ref COPYDATASTRUCT lParam); 

IntPtr result; 

      byte[] sarr = System.Text.Encoding.Default.GetBytes(sendMsg); 
      int len = sarr.Length; 
      COPYDATASTRUCT cds; 

      cds.dwData = (IntPtr)3; 
      cds.lpData = sendMsg; 
      cds.cbData = (UInt32)len + 1; 
      result = SendMessage(hwndTarget, WM_COPYDATA, 0, ref cds); 

crédit pour cette solution va à Jim Kemp ... qui n'est pas encore membre. Merci Jim!

1

Je recommande de regarder dans les canaux nommés. Dans .NET, vous pouvez utiliser System.IO.Pipes à cette fin. En VB6 vous pouvez facilement l'implémenter avec Win32API. Named Pipes est une meilleure façon de rendre IPC que la messagerie Windows. IPC via SendMessage a également des limitations sur Vista et Win7.

+0

Je suis d'accord, et ont eu des suggestions similaires au niveau local. La plupart de ceci est hérité. –

+0

Je me demande si vous pourriez expliquer un peu plus, sur les limitations de la messagerie Windows sur Windows 7. Toute cette situation est survenue, lorsqu'une application héritée a été déplacée vers un environnement Windows 7 - 64 bits. Ce que j'essaie de faire à ce stade, c'est simplement de le faire fonctionner de sorte que je puisse prendre le temps de le remplacer, probablement en tant qu'application Web. –

+0

Il s'agit de limitations de sécurité. J'ai fait face aux problèmes de la messagerie Windows entre les applications sur Vista quand il est sorti. Sur Vista (et Win7 je pense), il semble qu'il n'y ait aucun moyen d'envoyer un message à partir d'une application plus basse. Mais pour les tuyaux nommés, vous pouvez le faire. – DReJ

1

Vous avez vraiment tort. Seul COPYDATASTRUCT.lpData est un pointeur. dwData indique le numéro de message. Vous choisissez le vôtre, utilisez 0 si vous n'en avez qu'un. cbData est la taille des données pointées.

Plus de problèmes, vous fuyez la mémoire. La quantité de mémoire allouée ne correspond pas à la taille que vous passez. La conversion de chaîne est avec perte et peut ne pas produire autant d'octets que string.Length(). FindWindow est notoirement peu fiable. Utilisez un socket ou un tube nommé pour cela, donc vous n'avez pas besoin de deviner un nom, WCF est le meilleur.

  COPYDATASTRUCT cds; 
      cds.dwData = (IntPtr)3; 
      cds.lpData = Marshal.StringToHGlobalUni(sendMsg); 
      cds.cbData = 2 * (sendMsg.Length + 1); 
      SendMessageA(hwndTarget, 74, 0, cds); 
      Marshal.FreeHGlobal(cds.lpData); 
+0

Bonnes idées à tous, merci. Modifier le code pour regarder comme ci-dessus ne semble pas déclencher le gestionnaire de messages dans l'application vb6. –

+0

Il n'y avait rien que j'ai fait dans l'extrait qui empêcherait le message d'être envoyé. Utilisez le débogueur. –