2010-11-02 121 views
0

我试图使用Windows消息的两个C#/。NET 3.5应用程序之间的通信,但我发送消息似乎得到了一些时间(但不是所有的时间) - 为什么这是否正在发生,以及如何确保消息在所有时间都得到妥善处理。我有个客户对象如下:WM_COPYDATA消息没有被处理

[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); 
    } 
    } 
} 

我的测试应用的主要形式拥有类型WMTCPBridge的目的,通过调用GetTargetHandle开始通信,并通过调用SendNumericMessage方法发送单独的消息。服务器是一个测试工具,可以代替现有的应用程序,我希望避免不必要的更改。这是现有的应用程序驱动选择接口(我必须使用WM_COPYDATA,我必须通过wparam发送消息类型代码,如果我想发送一个整数,我应该通过lparam而不是一个Copydatastruct发送整数)。服务器应用程序的主要形式已WndProc方法重写如下:

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); 
    } 

当我运行服务器和客户端一起,客户端报告它正在发送的消息来处理,我可以看到通过Winspector是服务器窗口的句柄,sendMessage函数返回0,应用程序错误为0.通常,服务器不会报告获取任何消息,并且Winspector不会显示任何正在发送到服务器的WM_COPYDATA消息。但是,如果我不断发送来自客户端的消息,服务器会收到一些消息 - 我通常会在所有消息都通过或没有消息通过的情况下出现条带。当我修改客户端发送WM_CLOSE消息时,服务器将不可避免地收到它们并关闭 - 即使当我尝试使用WndProc方法捕获WM_CLOSE消息时(如上所示)。

发生了什么事我的消息?我特别困惑,因为MSDN表示SendMessage函数只有在处理完消息后才会返回。

回答

1

您不能忽视Windows希望LPARAM指向COPYDATASTRUCT结构的事实。但是,只能分配4个字节,远不足以存储该结构。接下来发生的事情是不可预知的,Windows将读取您分配的内存,查找COPYDATASTRUCT.cbData和lpData的值。你可能会很幸运,它读取cbData = 0。或者不那么幸运,并读取一个非零值。这将使其解除引用lpData,并且几乎总是会生成AccessViolation异常。你可以知道发生这种情况时,SendMessage()返回一个值。你没有检查,所以你不知道什么时候出错。

只要你想继续使用WM_COPYDATA,你的就有为它提供正确的参数。更好的方法是使用命名管道或套接字。这也避免了必须使用FindWindow(),这是一种非常不可靠的方法来查找窗口句柄。

+0

我刚刚尝试了一个实际的COPYDATASTRUCT,它工作 - 谢谢。 – Andrew 2010-11-02 15:55:21