IPC with WM_COPYDATA

Inter-process communications (IPC) in Windows can be accomplished in a variety of ways. Essentially these different implementations boil down to just 2 types: local and network based IPC. Local implementations like COM and WM_COPYDATA are all just forms of passing data with memory mapped files. Setting up a custom memory mapped file mechanism can be rather involved, and creating COM applications for a simple IPC operation between two applications can result in a bit of code and registration hassles.

This is where WM_COPYDATA can provide a quick IPC link between two applications. It really makes sense when the messages occur between the application windows themselves, but even that isn't a requirement. Here is an example where a request is sent to a server application by first finding the window handle of the server process and sending the data via a WM_COPYDATA message along with a handle to a window that will process any response, which occurs before the original SendMessage returns in this case. The code below would even work from multiple threads.

char result[7];
HWND hwnd = FindWindow(0, _T("MyServerWin"));
if (hwnd)
{
   char data[] = "REQUEST:ACK";
   TCHAR className[] = _T("MyMessageClass");
   static bool registered = false;

   if (!registered)
   {
      WNDCLASSEX wndClass = {0};
      wndClass.lpfnWndProc = (WNDPROC)RespWindowProc;
      wndClass.hInstance = g_hInstance;
      wndClass.lpszClassName = className;
      wndClass.cbSize = sizeof(wndClass);

      RegisterClassEx(&wndClass);
      registered = true;
   }

   HWND hwndResp = CreateWindow(className, _T(""), 0, 0, 0, 0, 0, 0, 0, 0, 0);
   SetWindowLong(hwndResp, GWL_USERDATA, (LONG)result);

   COPYDATASTRUCT request;
   request.dwData = 0;
   request.cbData = strlen(data) + 1;
   request.lpData = data;
   retval = SendMessage(hwnd, WM_COPYDATA, (WPARAM)hwndResp, (LPARAM)&request);

   DestroyWindow(hwndResp);
}

The window procedure processing the response would look something like this:

LRESULT CALLBACK RespWindowProc(HWND HWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
{
   if (nMsg == WM_COPYDATA)
   {
      COPYDATASTRUCT *data = (COPYDATASTRUCT *)lParam;
      char *result = (char *)GetWindowLong(HWnd, GWL_USERDATA);
      strcpy_s(result, 7, (char *)data->lpData);
      return 0;
   }

   return DefWindowProc(HWnd, nMsg, wParam, lParam);
}

(TCHAR and _tcs functions are macros for MBCS/Unicode compatibility)