1

I have this structure:

typedef struct tagCOPY_PACKET
{
    TCHAR szFile[_MAX_PATH];
    GUID guidSignature;

} S_COPY_PACKET;

I prepare to send data with WM_COPYDATA like this:

CString strFile = GetFileToOpenFromFileExplorerPath();

S_COPY_PACKET sCopyDataPacket;
_tcscpy_s(sCopyDataPacket.szFile, _MAX_PATH, strFile);
sCopyDataPacket.guidSignature = CopyData_Signature;
COPYDATASTRUCT cds;
cds.dwData = COPYDATA_TYPE_MSA;
cds.cbData = sizeof(sCopyDataPacket);
cds.lpData = &sCopyDataPacket;

DWORD_PTR dwResult;
if (SendMessageTimeout(hOtherInstance, WM_COPYDATA,
                NULL, (LPARAM)(LPVOID)&cds, SMTO_BLOCK, 2000, &dwResult) != 0)
{
}

And at the other end:

BOOL CMeetingScheduleAssistantDlg::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct)
{
    if (pCopyDataStruct->dwData == COPYDATA_TYPE_MSA)
    {
        S_COPY_PACKET* pCopyPacket = (S_COPY_PACKET*)(pCopyDataStruct->lpData);
        if (pCopyPacket->guidSignature != CopyData_Signature)
        {
            // Bad GUID
            return FALSE;
        }

        if (GetLastActivePopup() != this) // Popup windows!
        {
            // TODO: Tell user?
            return FALSE;
        }

        theApp.SetFileToOpenFromFileExplorer(pCopyPacket->szFile);

        OpenFileFromFileExplorer();

        return TRUE;
    }

    return FALSE;
}

It works fine. I just wanted to know if it would be acceptable to change my structure like this:

typedef struct tagCOPY_PACKET
{
    LPCTSTR lpszFile;
    GUID guidSignature;

} S_COPY_PACKET;

And then use:

S_COPY_PACKET sCopyDataPacket;
sCopyDataPacket.lpszFile = strFile.GetBufferSetLength(_MAX_PATH);
sCopyDataPacket.guidSignature = CopyData_Signature;
COPYDATASTRUCT cds;
cds.dwData = COPYDATA_TYPE_MSA;
cds.cbData = sizeof(sCopyDataPacket);
cds.lpData = &sCopyDataPacket;
...

And, once the message has been posted and processed:

strFile.ReleaseBuffer();

Is it safe to use the LPCTSTR approach with WM_COPYDATA and if so, why?

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
Andrew Truckle
  • 17,769
  • 16
  • 66
  • 164
  • From the receiving app point of view there is absolutely no difference between these two: `cds.lpData = &sCopyDataPacket;` and `cds.lpData = strFile.GetString();`. They both point to the *local* data copy. So yes, it's absolutely acceptable, unless you're not trying to use `cds.lpData` pointer in the receiving app **after** `SendMessage` returns. – Jovibor May 11 '20 at 09:58
  • @Jovibor I get what you are saying. But I need to send this structure that contains the `GUID` and the `CString` contents. – Andrew Truckle May 11 '20 at 10:21
  • Your `S_COPY_PACKET sCopyDataPacket;` and `CString strFile` are both *local* data objects, right? So, what's the difference what pointer you provide in `cds.lpData = ` to? Well, here the suggestion - try both cases and see result yourself. – Jovibor May 11 '20 at 10:30
  • @Jovibor The receiving application cannot read data from the memory of the sending application. The rest does not matter. – Martin Prikryl May 11 '20 at 10:31
  • @MartinPrikryl But it can read `S_COPY_PACKET sCopyDataPacket;` ? – Jovibor May 11 '20 at 10:33
  • @Jovibor I assume that the Windows system makes a copy of the data in the memory of the receiving application. Though it's not really relevant how it is implemented in the OS. All that matters is that only the `sCopyDataPacket` is made accessible to the receiving application. Nothing more. – Martin Prikryl May 11 '20 at 10:45
  • @MartinPrikryl There is nothing saying about *copying* in the official `WM_COPYDATA` documentation, so i won't argue about that. – Jovibor May 11 '20 at 10:45
  • Technically you can pass a pointer via `WM_COPYDATA` if it points to memory you have allocated in the other address space (via `VirtualAllocEx`). In this case though it would be a waste of time. – Jonathan Potter May 11 '20 at 11:59

2 Answers2

2

The documentation of WM_COPYDATA says:

The data being passed must not contain pointers or other references to objects not accessible to the application receiving the data.

Therefore, when CMeetingScheduleAssistantDlg lives in a different executable, you cannot pass an LPCTSTR value. If it is in the same executable, chances are that it works.

j6t
  • 9,150
  • 1
  • 15
  • 35
1

No. LPCTSTR is a pointer. So the recipient application will receive a pointer to a memory location of the sender application. It would cause the recipient application to crash due to a memory violation, had it tried to access the data.

Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992