Link to home
Start Free TrialLog in
Avatar of sri_darr
sri_darr

asked on

Passing a string using SendMessage

I want to send a String from one Application to another. I'm using SendMessage to do this and am passing the string in the wParam. But for some reason, I'm not able to "get" that string in the receiving application. Any clues guys ?
I have registered a window message say APP_MY_MSG. Then I'm doing a

CString csUser = "User1";
lRet = ::SendMessage((HWND)-1, APP_MY_MSG, (WPARAM)csUserID, APP_ISUSERVALID);

In my other Application, I get the message fine and can even switch with the lParam (as APP_ISUSERVALID), but I'm not able to get the value that I pass from here. Cd u tell me whatzz wrong
Avatar of jhance
jhance

Nope, can't do it unless the string you want to send fits in an LPARAM.  So that gives you 4 characters.

Use the WM_COPYDATA message instead to pass small amounts of data to your other application.
By the way, the problem with your original approach is that your two process DO NOT SHARE their memory spaces.  So a string pointer in one process is inaccessible to the other.  Remember that all WIN32 processes are protected from each other.
I'd suggest to use memory mapped files. Have a look at
CreateFileMapping and MapViewOfFile functions

Carlos
gocarlos,

A memory mapped file is a viable option but it's probably overkill for sending a simple string.  I'm not sure at what size the data needs to be for it to make more sense to do a mapped file but my guess is that the WM_COPYDATA is the best choice for this application.
jhance,

I totally agree with you. Actually I use memory mapped files to share complex data structures between applications, but for this simple case WM_COPYDATA should be just fine.

Carlos
By the way, here is a Microsoft article that outlines the various methods of copying data between processes:

http://support.microsoft.com/support/kb/articles/q95/9/00.ASP
Also You can replace:
CString csUser = "User1";
with this:
static char csUser[] = "User1";
>>Also You can replace:

Sure you can do that, but what does that have to do with this situation?
Avatar of sri_darr

ASKER

Thx jhance (and Carlos) for pointing me in the right direction. I used WM_COPYDATA ... and it almost works OK .,.. except that I get some junk along with the actual string that I pass ... Here's the code .. Am Idoing something wrong ?

// The Applilcation that sends the String

     const char szUserID[] = ("Test");
     int nLen = strlen(szUserID);

     COPYDATASTRUCT     stData;
     stData.dwData     = 0;
     stData.cbData     = strlen(szUserID);
     stData.lpData     = (void *)szUserID;

     lRet = ::SendMessage( (HWND) -1, WM_COPYDATA, (WPARAM)m_hWnd, (LPARAM) &stData);

// The Application that receives the string
    LPCSTR pszUserID = (LPCSTR)pCopyDataStruct->lpData;
           
     if (lstrcmpi(pszUserID, "Test") == 0)
     {
              m_bValidUser = TRUE;
     }
     else
     {
             m_bValidUser = FALSE;
     }
---\
The Problem is that in the receiving application I get the string as "Test|'cw|hA" .. Basically some junk along with the actual data. Why is this ?
Or shd I use the pCopyDataStruct->cbData in the receiving Appln to extract only that many characters out of the string and then check it ? That seems weird ..
Do one of two things:

1) In your send, send the terminating NULL of the string:

stData.cbData     = strlen(szUserID) + 1;

2) In your receiver, be sure the data is NULL terminated before using it.  So take the length of the string passed and stuff a NULL into the buffer.  Remember that WM_COPYDATA ONLY passes the exact number of bytes you tell it to.  No more.

I'd suggest #1.
I'd like to use #1 too ... rather than #2. But it doesnt seem to work. I set the cbData in the sending appln. to stData.cbData     = strlen(szUserID) + 1;
as youd told me ... But I still get some junk past the string's length in the receiving appln. So for now, I use the cbData member in the receiving appln. to extract only that many from the data (Left()) and it works OK. I'll just wait for some more time.... to see if someone has an idea !
I put together a quick sample and tested it out.  I found no problems with doing it as below...


BOOL CCopyDataTestDlg::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct)
{
     // TODO: Add your message handler code here and/or call default
     ::Beep(500, 500);

     TCHAR *pRcvData = (TCHAR *)(pCopyDataStruct->lpData);
     SetDlgItemText(IDC_RCVDATA, pRcvData);

     return CDialog::OnCopyData(pWnd, pCopyDataStruct);
}

void CCopyDataTestDlg::OnSendbutton()
{
     // TODO: Add your control notification handler code here
     COPYDATASTRUCT cd;
     CString mSendData;
     GetDlgItemText(IDC_SENDDATA, mSendData);
     
     cd.cbData = mSendData.GetLength();
     cd.dwData = 0;
     cd.lpData = (LPVOID)((LPCTSTR)mSendData);

     ::SendMessage(HWND_BROADCAST, WM_COPYDATA, (WPARAM)this->m_hWnd, (LPARAM)&cd);
}
Beats me jhance...
I put the exact same code as youd given here ... but it still doesnt get the exact string. It gets somethign like "User1c|1nW|aW" etc... ie. Some junk after the valid string.
Can you run it in the debugger and view the received block of data?  I inspected mine and see the string followed by a "00" (i.e. a NULL).

What Windows are you running this on?  It shouldn't matter but who knows??

I tested on Win98 SE.  I'll run it on Win2000 and see what happens...
Hey, I see what you're saying on Win2000.  Let me look a bit closer....
I have Win NT 4.0 here.... And all the while I was only debugging it. At the stage where I'm passing it, the NULL termination is fine ... the string has '\0' at the end. It's only the receiving end where the problem occurs.
ASKER CERTIFIED SOLUTION
Avatar of jhance
jhance

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
jhance, it still isnt' working the way you've said and so I'm using the LEFT() method to extract the string. But anyway since you pointed me in the right direction to get this done, I owe this to you.
Thanks
It would really help if you posted the exact code you are using.  I know that this works and so I really think you are doing something not quite right...
Here's it :
In my first dialog app where I'm sending the information:
//FirstDlg.cpp
BOOL CFirstDlg::OnInitDialog()
{
     CDialog::OnInitDialog();
...
...
     CString csUserID = "Test";

     COPYDATASTRUCT     stData;
     stData.dwData     = 0;
     stData.cbData     = csUserID.GetLength();
     stData.lpData     = (LPVOID)(LPCTSTR)csUserID;

     lRet = ::SendMessage( (HWND) -1, WM_COPYDATA, (WPARAM)m_hWnd, (LPARAM) &stData);

...
...
}

and in the sedond dlg app where I'm receiving this string
//SecondDlg.cpp

BOOL CSecondDlg::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct)
{
CString     csLauncherUserID;
LPCSTR     pszUserID = (LPCSTR)pCopyDataStruct->lpData;
int     nLength   =  pCopyDataStruct->cbData;
CString csUserID  = pszUserID;

GetDlgItemText(IDC_TXT_USERID, csLauncherUserID);

if (csUserID.Left(nLength) == csLauncherUserID)
{
        AfxMessageBox(USER_VALID);
}
else
{
     AfxMessageBox(USER_INVALID);
}

return CDialog::OnCopyData(pWnd, pCopyDataStruct);
}


// I then changed it to TCHAR* as youd given in my SecondDlg. But it didnt change anything.