2010-11-02 4 views
0

Я пытаюсь установить связь между двумя приложениями C#/.NET 3.5 с использованием сообщений Windows, но сообщения, которые я отправляю, появляются некоторое время (но не все время) - почему это происходит, и как я могу гарантировать, что сообщения будут правильно обрабатываться все время. У меня есть объект клиента следующим образом:Сообщения 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, сервер неизбежно получит их и закроет - даже когда я попытался захватить сообщения WM_CLOSE с помощью метода WndProc, как показано выше.

Что происходит с моими сообщениями? Я особенно смущен, потому что MSDN говорит, что функция SendMessage возвращается только после обработки сообщения.

ответ

1

Вы не можете игнорировать тот факт, что Windows хочет, чтобы LPARAM указывал на структуру COPYDATASTRUCT. Однако вы выделяете только 4 байта, а не достаточно, чтобы сохранить эту структуру. Что происходит дальше, непредсказуемо, Windows будет читать мимо выделенной вами памяти, ища значение COPYDATASTRUCT.cbData и lpData. Вам может повезти, и он читает cbData = 0. Или не так повезло и читает ненулевое значение. Это сделает его разыменованием lpData и почти всегда генерирует исключение AccessViolation. Вы можете сказать, когда это произойдет, SendMessage() возвращает значение. Один из них не проверял, чтобы вы не знали, когда это пойдет не так.

Если вы хотите продолжать использовать WM_COPYDATA, у вас есть, чтобы предоставить ему правильные аргументы. Гораздо лучший подход - использовать именованные каналы или сокет. Который также позволяет не использовать FindWindow(), очень ненадежный способ найти дескриптор окна.

+0

Я только что попробовал с фактической COPYDATASTRUCT, и это сработало - спасибо. – Andrew