Solved

Passing a string using SendMessage

Posted on 2001-06-12
20
1,257 Views
Last Modified: 2013-11-20
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
0
Comment
Question by:sri_darr
  • 11
  • 6
  • 2
  • +1
20 Comments
 
LVL 32

Expert Comment

by:jhance
ID: 6183429
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.
0
 
LVL 32

Expert Comment

by:jhance
ID: 6183435
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.
0
 
LVL 3

Expert Comment

by:qocarlos
ID: 6183847
I'd suggest to use memory mapped files. Have a look at
CreateFileMapping and MapViewOfFile functions

Carlos
0
 
LVL 32

Expert Comment

by:jhance
ID: 6183870
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.
0
 
LVL 3

Expert Comment

by:qocarlos
ID: 6183878
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
0
 
LVL 32

Expert Comment

by:jhance
ID: 6183889
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
0
 
LVL 2

Expert Comment

by:MadYugoslav
ID: 6184952
Also You can replace:
CString csUser = "User1";
with this:
static char csUser[] = "User1";
0
 
LVL 32

Expert Comment

by:jhance
ID: 6185531
>>Also You can replace:

Sure you can do that, but what does that have to do with this situation?
0
 
LVL 4

Author Comment

by:sri_darr
ID: 6186194
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 ..
0
 
LVL 32

Expert Comment

by:jhance
ID: 6186263
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.
0
Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

 
LVL 4

Author Comment

by:sri_darr
ID: 6186427
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 !
0
 
LVL 32

Expert Comment

by:jhance
ID: 6186914
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);
}
0
 
LVL 4

Author Comment

by:sri_darr
ID: 6187182
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.
0
 
LVL 32

Expert Comment

by:jhance
ID: 6187198
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...
0
 
LVL 32

Expert Comment

by:jhance
ID: 6187214
Hey, I see what you're saying on Win2000.  Let me look a bit closer....
0
 
LVL 4

Author Comment

by:sri_darr
ID: 6187305
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.
0
 
LVL 32

Accepted Solution

by:
jhance earned 50 total points
ID: 6187385
There is some more information at:

http://msdn.microsoft.com/library/psdk/winbase/ipc_2mw1.htm

See where it says:

"The receiving application should consider the data read-only. The lParam parameter is valid only during the processing of the message. The receiving application should not free the memory referenced by lParam. If the receiving application must access the data after SendMessage returns, it must copy the data into a local buffer."

I think this is the heart of the matter.  I changed my code to that shown below.  It may be overly conservative but I'm not sure I know EXACTLY when Windows grabs the data out of mSendData.  If it's AFTER the function has returned the data may be gone or damaged.

The following seems to work reliably on Win98 and Win2000.  No NT4 system handy....

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

     TCHAR *pRcvData = _tcsdup((TCHAR *)(pCopyDataStruct->lpData));

     SetDlgItemText(IDC_RCVDATA, pRcvData);

     free (pRcvData);

     return TRUE;

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

void CCopyDataTestDlg::OnSendbutton()
{
     // TODO: Add your control notification handler code here
     static COPYDATASTRUCT cd;
     static CString mSendData;

     GetDlgItemText(IDC_SENDDATA, mSendData);
     
     cd.cbData = mSendData.GetLength() + 1;
     cd.dwData = 0;
     cd.lpData = (LPVOID)((LPCTSTR)mSendData);

     ::SendMessage(HWND_BROADCAST, WM_COPYDATA, (WPARAM)this->m_hWnd, (LPARAM)&cd);
}
0
 
LVL 4

Author Comment

by:sri_darr
ID: 6202454
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
0
 
LVL 32

Expert Comment

by:jhance
ID: 6203491
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...
0
 
LVL 4

Author Comment

by:sri_darr
ID: 6203585
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.
0

Featured Post

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
Decoding 32 bit binary streams 6 37
ODBC Connection Logging, ADO.NET 6 56
isEverywhere  challenge 19 72
twoTwo  challenge 35 93
Introduction: Dialogs (1) modal - maintaining the database. Continuing from the ninth article about sudoku.   You might have heard of modal and modeless dialogs.  Here with this Sudoku application will we use one of each type: a modal dialog …
Have you tried to learn about Unicode, UTF-8, and multibyte text encoding and all the articles are just too "academic" or too technical? This article aims to make the whole topic easy for just about anyone to understand.
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
Internet Business Fax to Email Made Easy - With  eFax Corporate (http://www.enterprise.efax.com), you'll receive a dedicated online fax number, which is used the same way as a typical analog fax number. You'll receive secure faxes in your email, f…

911 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

18 Experts available now in Live!

Get 1:1 Help Now