How to send information between C++ applications

July 16, 2018
5 min read

In this snippet, I am going to present you a solution on how to send information between C++ windows type applications.
We came across a situation in which we had to pass a specific information between two applications. In our case, we had to pass the command line arguments from one instance of a window application to another instance of the same application. So, the main instance of the application, the one that was opened first, would know the command line arguments of the second.
In order to send information from one instance to another, one should use the SendMessage function which requires the Windows.h header. 
An example of a call is SendMessage (main_window_handle, WM_ID, 0, LPARAM (“the information you would like to send”));

ParameterExplanation
main_window_handleRepresents the handle to the window to which we would like to send the information.
WM_ID Represents a defined ID that we will later listen to in the WndProc(WndProc is a function constructed by default in a window type application and it processes messages for the main window).
WPARAMCan be used to send information
LPARAM Can be used to send information

In order to get a handle to the window to which we want to send the information, you can use the FindWindow function.

An example of a call is FindWindow (NULL, my_window_title);

  •  The first parameter is NULL because we do not need to pass a class name.
  •  Parameter my_window_title - represents the title of the window we want to find.

  HWND main_window_handle = FindWindow(NULL, my_window_title);

If the function succeeds, the return value is a handle to the window that has the specified window name. If the function fails, the return value is NULL.

So far so good, only that the example above will not work. Because the system does not do marshaling for system messages with ID higher than WM_USER(the value of WM_USER is 0x0400), in order to send the information we need to use a defined ID but all the defined IDs below WM_USER are RESERVED.
In that case, we can use WM_COPYDATA ID which has the value of 0x004A and it's an already defined id.
In order to use WM_COPYDATA, we have to use the  COPYDATASTRUCT structure to construct a message.
We should also know at what time do we need to send this message and for that, we can create a mutex and verify if there is another instance already running. 
This is an example of how to create and use a mutex:
HANDLE unique_mutex;
  unique_mutex = CreateMutex(NULL, FALSE, L"MyTestApp");

  if(unique_mutex == NULL)
  {
	std::cout<< "Mutex was not successfully created!!!";
  }
  else if(GetLastError() == ERROR_ALREADY_EXISTS)  
  {
	g_another_instance_already_running = true;
  }

The CreateMutex function creates a named or unnamed mutex object and gives ownership over it to the first thread that opens it. If the mutex is a named mutex and the thread that tries to open it it’s not its owner, the return value is a handle to the existing object and GetLastError returns ERROR_ALREADY_EXISTS. In that case, we are simply setting the value of a boolean to true.

We are later using this boolean to see if we are allowing our window to show, if the boolean is false we are allowing it and if it is true we are not allowing it and sending the message to the main instance.

This is an example of how to use COPYDATASTRUCT to reference information: 

auto command_line_arguments = ::GetCommandLine();

  //Create a COPYDATASTRUCT to send the information
  COPYDATASTRUCT data_to_send = {0};
  data_to_send.dwData = kCommandLineArgsMessageId;
  data_to_send.cbData = (DWORD)(strlen(command_line_arguments.c_str()) + 1);
  data_to_send.lpData = command_line_arguments;
  • cbData represents the size of the information we want to send.
  •  lpData represents the information we want to send.
  •  dwData is an ID defined by us(this is a type of ID different than WM_COPYDATA). This is how you can declare it:
const UINT kCommandLineArgsMessageId = RegisterWindowMessage(L"SingletonApplication");

The RegisterWindowMessage function simply registers an ID for the specified string.

This is how you can send a message constructed with COPYDATASTRUCT:

SendMessage(main_window_handle, WM_COPYDATA, 0, (LPARAM)&data_to_send);

At this point, the information was sent from the second instance of the application to the first one. Now in the first one, we have to intercept the message and take action.
The SendMessage function calls the window procedure for the specified window, so the only thing we have to do is to add a case inside the WndProc in which we verify if a message has been sent using the WM_COPYDATA id.

This is an example of how to intercept this event:

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
  switch (message)
  {
    case WM_COPYDATA:
    {
      HandleCopyDataEvent(hWnd, lParam);
      break;
    }
  }
} 

The HandleCopyDataEvent function is used to parse the information received, the body of this function looks like this:

void HandleCopyDataEvent(HWND main_window_handle, LPARAM lparam)
{
  //Copy the information sent via lparam param into a structure
  COPYDATASTRUCT* copy_data_structure = {0};
  copy_data_structure = (COPYDATASTRUCT*)lparam;

  if(copy_data_structure->dwData == kCommandLineArgsMessageId)
  {
	//Extract the information from the created structure and forward the information to UI
	LPCWSTR arguments = (LPCWSTR)copy_data_structure->lpData;

	//Set the focus on the main instance
	SetForegroundWindow(main_window_handle);
	ShowWindow(main_window_handle, SW_NORMAL);

	MessageBox(main_window_handle, arguments, NULL, MB_OK);
  }
}

This function basically extracts the information from the LPARAM for further use. It also sets the main instance of the application as the foreground window (what this does is if the window is at that time minimized or hidden will show it in front).

For the purpose of this example, we will only show a message box that contains the information received from the second instance.

If you reached this point in the article, it means that I did not bore you (that much). This functionality can be used to send information or data between different window type applications, not just between instances of the same application, using WinAPI.

Share on:

Want to stay on top of everything?

Get updates on industry developments and the software solutions we can now create for a smooth digital transformation.

* I read and understood the ASSIST Software website's terms of use and privacy policy.

Frequently Asked Questions

ASSIST Software Team Members

See the past, present and future of tech through the eyes of an experienced Romanian custom software company. The ASSIST Insider newsletter highlights your path to digital transformation.

* I read and understood the ASSIST Software website's terms of use and privacy policy.

Follow us

© 2024 ASSIST Software. All rights reserved. Designed with love.