2010-11-02 4 views
0

J'essaie de communiquer entre deux applications C#/.NET 3.5 en utilisant Windows Messages, mais les messages que j'envoie semblent être reçus parfois (mais pas toujours) - pourquoi Est-ce que cela se produit, et comment puis-je m'assurer que les messages sont correctement traités tout le temps. J'ai un objet client comme suit:Les messages WM_COPYDATA ne sont pas traités

[DllImport("User32.dll", EntryPoint = "FindWindow")] 
public static extern Int32 FindWindow(String lpClassName, String lpWindowName); 

[DllImport("User32.dll", EntryPoint = "SendMessage")] 
public static extern IntPtr SendMessage(IntPtr hWindow, int message, IntPtr wParam, IntPtr lParam); 

public class WMTCPBridge 
{ 

    private IntPtr TargetHwnd 

    public void SendNumericMessage(Int32 messageCode, 
    Int32 MessagePayload) 
    { 
    //for some reason String.fomat("blah 0x{0:X}",TargetHwnd) shows the number in decimal 
    string sendNotice = String.Format("Sending to window 0x{0}", TargetHwnd.ToString("X")); 
    myTextOutput.Writeline(sendNotice); 

    sendNotice = String.Format("Sending to window {0}", TargetHwnd); 
    myTextOutput.Writeline(sendNotice); 

    IntPtr unmanagedInt = Marshal.AllocHGlobal(sizeof(Int32)); 
    Marshal.WriteInt32(unmanagedInt,MessagePayload); 
    IntPtr result = IntPtr.Zero; 
    try 
    { 
     result = SendMessage(TargetHwnd, WM_COPYDATA, (IntPtr)messageCode, 
      unmanagedInt); 
    } 
    finally 
    { 
     Marshal.FreeHGlobal(unmanagedInt); 
    } 
    myTextOutput.Writeline("Result is " + result); 
    if ((int)result == 0) 
    { 
     myTextOutput.Writeline("Error code : " + GetThreadError()); 
    } 
    } 

public void GetTargetHandle(string targetName) 
    { 
    TargetHwnd = (IntPtr)FindWindow(null, targetName); 
    if (TargetHwnd == null) 
    { 
     myTextOutput.Writeline("Could not connect to UI"); 
    } 
    else 
    { 
     String outputLine = string.Format("Connected to window number 0x{0}", TargetHwnd.ToString("X")); 
     myTextOutput.Writeline(outputLine); 
     outputLine = string.Format("Connected to window number {0}", TargetHwnd); 
     myTextOutput.Writeline(outputLine); 
    } 
    } 
} 

La principale forme de ma demande de test possède un objet de type WMTCPBridge, commence la communication en appelant GetTargetHandle et envoie des messages individuels en appelant la méthode SendNumericMessage. Le serveur est un harnais de test qui remplace une application existante et que je voudrais éviter d'inutiles changements. C'est cette application existante qui détermine le choix de l'interface (je dois utiliser WM_COPYDATA, je dois envoyer un code de type message via wparam, si je veux envoyer un entier, je devrais envoyer l'entier via lparam au lieu d'une Copydatastruct). La principale forme de l'application serveur a la méthode de wndproc substituée comme suit:

protected override void WndProc(ref Message m) 
    {  
    Int32 messageCode=0; 
    Int32 messagePayload=0; 
    Debug.WriteLine(m); 
    switch (m.Msg) 
    { 
     case WM_COPYDATA: 
      { 
       messageCode = (int)m.WParam; 
       messagePayload = Marshal.ReadInt32(m.LParam); 
       WriteLine("Received message with code " + messageCode + 
       " and payload " + messagePayload); 
       break; 
      } 
     case WM_CLOSE: 
      { 
       WriteLine("Close blocked!"); 
       return; 
       break; 
      } 
    }   
    base.WndProc(ref m); 
    } 

Quand je lance ensemble le serveur et le client, le client signale qu'il envoie les messages à gérer que je peux voir par Winspector est le Le handle de la fenêtre du serveur, la fonction sendMessage renvoie 0 et l'erreur d'application est 0. Souvent, le serveur ne signale aucun message et Winspector n'affiche aucun message WM_COPYDATA envoyé au serveur. Cependant, si je continue à envoyer des messages depuis le client, certains seront reçus par le serveur - j'ai généralement des stries où tous les messages passent ou pas. Lorsque je modifiais le client pour envoyer des messages WM_CLOSE, le serveur les recevait et les fermait inévitablement - même lorsque j'essayais de piéger les messages WM_CLOSE avec la méthode WndProc comme indiqué ci-dessus.

Qu'est-ce qui arrive à mes messages? Je suis particulièrement confus parce que MSDN dit que la fonction SendMessage retourne seulement une fois qu'un message a été traité.

Répondre

1

Vous ne pouvez pas ignorer le fait que Windows souhaite que LPARAM pointe vers une structure COPYDATASTRUCT. Vous n'attribuez cependant que 4 octets, pas assez pour stocker cette structure. Ce qui se passe ensuite est imprévisible, Windows lira la mémoire que vous avez allouée, en recherchant la valeur de COPYDATASTRUCT.cbData et lpData. Vous pourriez avoir de la chance et il lit cbData = 0. Ou pas si chanceux et lire une valeur non nulle. Ce qui le fera déréférencer lpData et cela génère presque toujours une exception AccessViolation. Vous pouvez savoir quand cela arrive, SendMessage() renvoie une valeur. Un que vous n'avez pas vérifié, donc vous ne savez pas quand cela ne va pas.

Tant que vous souhaitez continuer à utiliser WM_COPYDATA, vous avez pour lui fournir des arguments appropriés. La meilleure approche consiste à utiliser des tubes nommés ou une socket. Qui évite également d'avoir à utiliser FindWindow(), un moyen très peu fiable pour trouver un handle de fenêtre.

+0

Je viens de faire un essai avec un COPYDATASTRUCT réel et cela a fonctionné - merci. – Andrew

Questions connexes