Inter Process Communication via WM_COPYDATA

This is a series of articles that will cover various techniques supported by Inter Process Communication (IPC) IPC is a mechanism by which the various processes share data among themselves. The application that uses the IPC mechanism can be placed in two categories: client and server application. A client is an application or a process that uses the services of some other application or a process. A server is an application or a process that responds to or processes the client request. The same application can act as both a server and a client.

The WIN32 SDK provides various ways to achieve an IPC. These are the following techniques through which IPC can be achieved:

  • WM_COPYDATA
  • Clipboard
  • FileMapping Objects
  • MailSlots
  • Pipes
  • Sockets
  • COM
  • RPC

This series of articles will cover each technique in detail, along with the source code. We will cover WM_COPYDATA message that an application can use to send data to an another application. In this technique, the client application sends a message to a window that is in the server application.

A client application sends a WM_COPYDATA message to pass the data to the server application. To send this message, the client application calls SendMessage, which has the prototype described in the next section.

The SendMessage Function

The SendMessage function sends the specified message to the specified window. The function doesn't return until the window procedure of that specified window has processed the message.

SendMessage((HWND) hWnd,      // handle to destination window
WM_COPYDATA,                  // message to send
(WPARAM) wParam,              // handle to window
(HWND)  (LPARAM) lParam       // data (PCOPYDATASTRUCT));

SendMessage Parameters

  • hWnd: Handle to destination window that will receive the WM_COPYDATA message.
  • wParam: Handle to Window (passes the hWnd by typecasting it into WPARAM).
  • lParam: Pointer to COPYDATASTRUCT that contains the data to be transferred to another application.

The COPYDATASTRUCT Structure

The COPYDATASTRUCT structure contains the data that is to be passed to another application.

typedef struct tagCOPYDATASTRUCT {
ULONG_PTR dwData;
DWORD     cbData;
PVOID     lpData; } COPYDATASTRUCT, *PCOPYDATASTRUCT

COPYDATASTRUCT Structure Parameters

  • cbData: Specifies the size in bytes.
  • lpData: Pointer to data that is to be passed to another application.

The source code has been divided into two parts—a client application and a server application. In this, the client application takes the string and the operation to be performed on that string from the user. The client application passes the necessary information to the server application so that the server can perform the requested operation on that string. The server application performs the requested operation on the data and displays the results on its console.

The WM_DATASTRUCTURE Structure

typedef struct _WM_DATASTRUCTURE{
DWORD cbSize;         // size of the string entered by user.
DWORD iMessage;       // operation being requested by user.
HWND hClient;         // handle to a client window. It is for
                      // further use. Currently, it is NULL.
_TCHAR Data[_WM_MAXMESSAGE_SIZE - _WM_HEADER_SIZE];
} WM_DATASTRUCTURE, *LPWM_DATASTRUCTURE;

The TransferData function makes a call to the LocalAlloc function to allocate the specified number of bytes from the heap. If the heap doesn't have the sufficient memory to allocate the requested bytes, it returns NULL. The lpData data member of COPYDATASTRUCT points to the WM_DATASTRUCTURE structure, which contains the information to be passed to the server application. After filling the COPYDATASTRUCT structure, the client application makes a call to SendMessage with the address of this structure as a last argument.

The Server Application

The server application registers the window class by calling the RegisterClass function. A window class is a set of properties that the operating system uses to create the window. Each window class has an associated window procedure that processes the messages being sent to the window of that window class. The server application retrieves the message from the message queue by calling GetMessage, and then calls DispatchMessage function, which dispatches the message to the window procedure for the further processing. After registering the window class with the operating system, the application can create many windows of that specific class; all the windows of that class share the same window procedure.

The window procedure WMCOPYWNDPROC performs the specified operation on the data, which is being sent by the client application. The window procedure typecast the lParam parameter to LPWM_DATASTRUCTURE to get the data being sent by the client application.

//Server side code . . . . .
LPWM_DATASTRUCTURE lpMsg;
(LPWM_DATASTRUCTURE)((COPYDATASTRUCT*)lParam)->lpData;

In this, lParam is a pointer to a COPYDATASTRUCT structure that exists in the address space of the receiving process. The lpData of the COPYDATASTRUCTURE is pointing to the _WM_DATASTRUCTURE, so it is telecast to the LPWM_DATASTRUCTURE.

Unicode Support

Unicode is a set of standards for a character-coding system. In Unicode, each character is two bytes, instead of being a single-byte ANSI character. A wide character is a two-byte character. The wide character is of the wchar_t type. Any ASCII character can be represented as a wide character by prefixing the letter L to the character. The L'M' is a wide character. Similarly, the ASCII string can be represented as a wide character string by prefixing the L to the string. The L"Unicode" is a wide character string. The wide characters take much more space than the multi-byte characters, but they are faster to process as compared to multi-byte characters. This is because the wide characters are always of a fixed size.

The wchar_t is defined as follows in stdio.h:

typedef  unsigned short wchar_t;
wchar_t* pStr=L"Hello! I am a wide character literal string."
wchar_t wcsCh= L'A';    //wide character.

Windows 95 and 98 don't support Unicode. An operating system such as Windows NT, 2000, and XP supports Unicode. The application that runs on the NT system should be Unicode. The Window NT provides supports a conversion between ANSI and Unicode. This support can make an ANSI application run on the Windows NT system. The operating system internally converts the ANSI strings to Unicode and vice versa.

The use of two macros, UNICODE and _UNICODE, makes your application Unicode-compatible. The UNICODE header is used in a Windows header file and _UNICODE is used in a C/C++ runtime library. Select the Settings menu item under the Project menu, and then select the C/C++ tab. Type _UNICODE, UNICODE in the Preprocessor definitions edit box.

Generic Macros

The generic macros make the life of a programmer easier because they provide support to write a single source code that can be compatible with both Unicode and the ANSI character set.

We have used two macros that are defined in Tchar.h:

  1. #ifdef UNICODE
    typedef wchar_t _TCHAR;
    #else
    typedef char _TCHAR;
    #endif
    
  2. _T macros expand to L if _UNICODE is defined; otherwise, it is ignored by the preprocessor.

These provide the automatic mapping to the correct character data type depending upon the Preprocessor directive used in project settings.

Notes

  1. The ascending and descending algorithms are meant only for ASCII characters and not for wide characters. In the next article, we will implement these algorithms for the wide characters. I have to explore much more regarding the wide character internals so that I can implement these algorithms on them.
  2. GetModuleHandle is implemented as both a Unicode and an ANSI version on Windows NT/2000, so the use of GetModuleHandle will fail if you try to run it with _UNICODE and UNICODE on Windows 95/98. To make it run on Windows 95/98, change the preprocessor directive to _MBCS or _SBCS.

Downloads

Download demo client project - 13 Kb
Download demo server project - 15 Kb