2010-11-02 95 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