C# - WM_COPY_DATA

참고 글

  • http://www.codeproject.com/KB/cs/ipc_wmcopy.aspx
  • http://www.codeproject.com/KB/threads/InterprocessCommunicator.aspx
  • http://www.codeproject.com/KB/cs/wm_copydata_use.aspx
  • MessageWindow http://www.codeproject.com/KB/threads/IPCBetManagdUnmanagd.aspx

예제 코드

const int WM_COPYDATA = 0x4A;
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr SendMessage(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam);
................
//Process[] AppServerProcess = Process.GetProcessesByName("LoginServer");
//.................
//SendMessage(AppServerProcess[0].MainWindowHandle, WM_COPYDATA, IntPtr.Zero, iPtrForCdsMsg);

COPYDATASTRUCT cds;
cds.dwData = srcHandle;
str = str + '\0';
cds.cbData = str.Length + 1;
cds.lpData = Marshal.AllocCoTaskMem(str.Length);
cds.lpData = Marshal.StringToCoTaskMemAnsi(str);
IntPtr iPtr = Marshal.AllocCoTaskMem(Marshal.SizeOf(cds));
Marshal.StructureToPtr(cds, iPtr, true);

// send to the MFC app
SendMessage(destHandle, WM_COPYDATA, IntPtr.Zero, iPtr);

// Don't forget to free the allocated memory 
Marshal.FreeCoTaskMem(cds.lpData);
Marshal.FreeCoTaskMem(iPtr);


//위 방식의 경우 보낼 때 마다 동적 할당을 하므로 메모리가 심하게 조각 날 수도 있다. 그러므로 한번 할당한 것을 계속 사용 하도록 한다.
public struct COPYDATASTRUCT
{
   public IntPtr dwData;
   public int cbData;
   public IntPtr lpData;
}

COPYDATASTRUCT  CdsMsg;
IntPtr iPtrForCdsMsg;


public ServerCommunication()
{
  CdsMsg.dwData = (IntPtr)12;
  CdsMsg.lpData = Marshal.AllocCoTaskMem(1024);
  iPtrForCdsMsg = Marshal.AllocCoTaskMem(Marshal.SizeOf(CdsMsg));
}

~ServerCommunication()
{
   Marshal.FreeCoTaskMem(CdsMsg.lpData);
   Marshal.FreeCoTaskMem(iPtrForCdsMsg);
}

public void ReceiveMsg(System.Windows.Forms.Message m)
{
   COPYDATASTRUCT cds = new COPYDATASTRUCT();
   cds = (COPYDATASTRUCT)Marshal.PtrToStructure(m.LParam, typeof(COPYDATASTRUCT));
   if (cds.cbData > 0)
   {
      byte[] data = new byte[cds.cbData];
      Marshal.Copy(cds.lpData, data, 0, cds.cbData);
      Encoding unicodeStr = Encoding.ASCII;
      char[] myString = unicodeStr.GetChars(data);
      string returnText = new string(myString);
      int iMsgIndex = (int)cds.dwData;
      System.Windows.Forms.MessageBox.Show("ACK Received: " + returnText + iMsgIndex.ToString());
      m.Result = (IntPtr)1;
   }
}

public void SendMsg()
{
   Process[] AppServerProcess = Process.GetProcessesByName("LoginServer");

   if (AppServerProcess.Length < 1)
   {
      return;
   }

   string str = "Hello" + "\0";

   CdsMsg.dwData = AppServerProcess[0].MainWindowHandle;
   CdsMsg.cbData = str.Length;
   CdsMsg.lpData = Marshal.StringToCoTaskMemAnsi(str);
   Marshal.StructureToPtr(CdsMsg, iPtrForCdsMsg, true);
   SendMessage(AppServerProcess[0].MainWindowHandle, WM_COPYDATA, IntPtr.Zero, iPtrForCdsMsg);
}

protected override void WndProc(ref Message m)
{
   switch (m.Msg)
   {
   case WM_COPYDATA:
      ServerComm.ReceiveMsg(m);
      break;

   default:
      // let the base class deal with it
      base.WndProc(ref m);
      break;
   }
}

이 글은 2019-04-02에 작성되었습니다.