question

Cesar-0243 avatar image
0 Votes"
Cesar-0243 asked SimpleSamples edited

How to receive a message containing WM_COPYDATA?

I figured out how to send the message with data, but i couldn't understand how to read it in the 'receiver app'

     // Sender
     void Msg(std::string msg) 
     {
         // Remove non utf8 char from string.
         string = sanitize_utf8(string);
        
         COPYDATASTRUCT cds{};
         cds.dwData = 1; 
         cds.lpData = (PVOID) string.c_str();
         cds.cbData = strlen((char*)cds.lpData); 
        
        
         auto response = SendMessage(hwnd, WM_COPYDATA, (WPARAM)w_hwnd, (LPARAM)&cds);
        
     }

While searching I could find some examples, but i still did not understand how to properly write it.
The receiver is a dll lib.

 //Received
 //??


I dont know much about c++, would like to ask if someone could explain me it with most details possible.

c++
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

SimpleSamples avatar image
0 Votes"
SimpleSamples answered SimpleSamples edited

Do you use MFC? I assume not. Do you know how to make a window procedure to receive messages? In your window procedure you need to process the WM_COPYDATA message. Do you know how to do that? In that you can use:

 COPYDATASTRUCT *pcds = (PCOPYDATASTRUCT)lParam;

And then the string would be (char*)pcds ->lpData.

That is a simple sample. Be sure to read the documentation and other materials; there are many details you need to understand.

I have created a sample. The complete sample is in GitHub at SimpleSamples/SampleCopydata: Sample use of the WM_COPYDATA message. It is a single-program sample, created in Visual Studio as a Windows Desktop Applicaiton. It needs to be executed twice. The first execution will be the receiver. The second execution will be the sender of a string. Each time the Send button is pressed a string with the current time is sent to the other instance.

The data is sent using:

 // Format the time into a string
 TCHAR timeString[30];
 time_t secs = time(0);
 struct tm local;
 localtime_s(&local, &secs);
 swprintf(timeString, sizeof(timeString), L"%02d:%02d:%02d", local.tm_hour, local.tm_min, local.tm_sec);
 // Send the string
 COPYDATASTRUCT cds{};
 cds.dwData = 1;
 cds.cbData = (wcslen(timeString)+1)*sizeof(TCHAR);
 cds.lpData = (PVOID)timeString;
 SendMessage(OtherhWnd, WM_COPYDATA, NULL, (LPARAM)&cds);

The data is received using:

 COPYDATASTRUCT *pMessageCDS = (PCOPYDATASTRUCT)lParam;
 // first save the string
 pSavedString = (TCHAR*)malloc(pMessageCDS->cbData);
 memcpy_s(pSavedString, pMessageCDS->cbData, pMessageCDS->lpData, pMessageCDS->cbData);
 // now use it now and later
 SetDlgItemTextW(hWnd, IDC_MESSAGE_EDIT, pSavedString);







5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Castorix31 avatar image
0 Votes"
Castorix31 answered SimpleSamples commented

Just see the sample in the doc : Using Data Copy


· 4
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.


This code is missing something, how do it knows when received the message ?

   // ************ Globals ************
     //
     #define MYDISPLAY 1
     typedef struct tagMYREC
     {
        char  s1[80];
        char  s2[80];
        DWORD n;
     } MYREC;
     PCOPYDATASTRUCT pMyCDS;
     void WINAPI MyDisplay( LPSTR, LPSTR, DWORD );
     //
     // ************ Code fragment ****************
     //
     case WM_COPYDATA:
        pMyCDS = (PCOPYDATASTRUCT) lParam;
        switch( pMyCDS->dwData )
        {
           case MYDISPLAY:
              MyDisplay( (LPSTR) ((MYREC *)(pMyCDS->lpData))->s1,
                         (LPSTR) ((MYREC *)(pMyCDS->lpData))->s2,
                         (DWORD) ((MYREC *)(pMyCDS->lpData))->n );
        }
        break;






0 Votes 0 ·

In "case WM_COPYDATA", as It is explained :
"
The receiving application has a hidden window which receives the information from WM_COPYDATA and displays it to the user.

And you can see a MS sample at :

CppReceiveWM_COPYDATA


0 Votes 0 ·

That is why I asked you if you know how to make a window procedure to receive messages. That is why that sample in the documentation is confusing. The code in that sample is for a window procedure.

0 Votes 0 ·

And your window that receives the data does not need to be hidden.

0 Votes 0 ·
Cesar-0243 avatar image
0 Votes"
Cesar-0243 answered SimpleSamples edited

@SimpleSamples alsmot done, but what i can do about the loop in Step3? I still need the code to execute other things instead of stuck on a endless loop.

 // Step 4: the Window Procedure
 LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
 {
    
  const char* translatedMessage = TrMessage(msg);
    
  std::wstringstream ss;
  ss << L"\nmsg: " << msg << L" " << translatedMessage;
  OutputDebugString(ss.str().c_str());
    
     switch(msg)
     {
  case WM_COPYDATA:
  {
  OutputDebugString(L"\nWM_COPYDATA!");
  PCOPYDATASTRUCT pcds = reinterpret_cast<PCOPYDATASTRUCT>(lParam);
  auto string = (char*)pcds->lpData;
    
  //.......
    
  return 1;
  }
         case WM_CLOSE:
             DestroyWindow(hwnd);
         break;
         case WM_DESTROY:
             PostQuitMessage(0);
         break;
         default:
             return DefWindowProc(hwnd, msg, wParam, lParam);
     }
     return 0;
 }
    
    
 int Main()
 {
     WNDCLASSEX wc;
     HWND hwnd;
     MSG Msg;
    
     //Step 1: Registering the Window Class
     wc.cbSize        = sizeof(WNDCLASSEX);
     wc.style         = 0;
     wc.lpfnWndProc   = WndProc;
     wc.cbClsExtra    = 0;
     wc.cbWndExtra    = 0;
     wc.hInstance     = 0;
     wc.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
     wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
     wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
     wc.lpszMenuName  = NULL;
     wc.lpszClassName = L"myWindowClass";
     wc.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);
    
     if(!RegisterClassEx(&wc))
     {
         MessageBox(NULL, L"Window Registration Failed!", L"Error!",
             MB_ICONEXCLAMATION | MB_OK);
         return 0;
     }
    
  hwnd = CreateWindowEx(WS_EX_LEFT, // this is the default
  L"myWindowClass",  // the name of the class, as passed to the RegisterClass function
  NULL, //  Title
  0,    //  dwFlags, in our case this really doesn't matter
  0,    //  X 
  0,    //  Y 
  0,    //  W 
  0,    //  H 
  HWND_MESSAGE , //the most important flag! Creates a message-only window
  0,    //  hMenu 
  0 ,   //  hInstance this function gets the instance handle of the current app
  0     //  lpParam 
  );
    
     if(hwnd == NULL)
     {
         MessageBox(NULL, L"Window Creation Failed!", L"Error!",
             MB_ICONEXCLAMATION | MB_OK);
         return 0;
     }
    
     ShowWindow(hwnd, SW_SHOW);
     UpdateWindow(hwnd);
    
     // Step 3: The Message Loop
     while(GetMessage(&Msg, NULL, 0, 0) > 0)
     {
         TranslateMessage(&Msg);
         DispatchMessage(&Msg);
     }
    
  return 0; // Msg.wParam;
 }



· 3
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Create a Win32 Desktop app or Dialog based like in the MS sample


0 Votes 0 ·

This code is inside of a dll, I'm creating the window to be able to receive wm_copydata msgs

0 Votes 0 ·

You should have told us from the beginning that it is a DLL. That makes a big difference. You would have saved your time and other people's time if you had told us it is a DLL.

GetMessage returns zero when a WM_QUIT message is received. So try sending a WM_QUIT message with (not with SendMessage):

 PostMessage(h,WM_QUIT,0,0);

If that does not work then one possibility is to just use the dwData field of COPYDATASTRUCT and when it has a value (whatever value you choose) that indicates the end then the receiving program knows to end.


0 Votes 0 ·