Click to See Complete Forum and Search --> : Read the string send through PostMessage


MGupta123
March 13th, 2005, 11:42 PM
I have an application which has 2 components. One component is a COM dll (C++). The other is the Dot Net (C#) User Interface. I am Doing a PostMessage in the COM dll and handling this postmessage in the C# User Interface. My problem is that I am not ablr to get the string which I am sending through postmessage LPAram.

Here is the code.
COM code to send the string :

CString sRestoreProg(_T("CHKPT_RESTORE_DEVICE"));
UINT nRestoreDevice = RegisterWindowMessage(sRestoreProg);
CString name = "Kdevice ";
CString * s = new CString(name);
int i = name.GetLength();
PostMessage( hRestHWnd, nRestoreDevice , i+1, (LPARAM)s );

Here is the C# code:

int m_gettext = RegisterWindowMessageA("CHKPT_RESTORE_DEVICE");

public struct MyStruct
{
public string str;
}

In the wndproc()...

if(m.Msg == m_gettext)
{
MyStruct strLPARAM = (MyStruct) m.GetLParam(typeof(MyStruct));
}


Result : strLParam.str gives "K".. which is the first alphabet of the sent string "kdevice".

How to get the whole string put of this IntPtr?

darwen
March 14th, 2005, 02:45 AM
Firstly, PostMessage won't work. You're passing a pointer to memory in the CString which will have been destroyed when your function goes out of scope - probably before the window has time to pick the message up.
Use SendMessage instead.

Secondly have a look at the System.Runtime.InteropServices.Marshal.PtrToStringAnsi method.

Darwen.

MGupta123
March 14th, 2005, 02:53 AM
Hi Darwen,
I cannot use Sendmessage. My application is such that it cannot wait for the sendmessage to return. Alos I analysed the method you are suggesting. It only gives me garbage in this case.

darwen
March 14th, 2005, 03:11 AM
It probably wouldn't if you did


SendMessage( hRestHWnd, nRestoreDevice , i+1, (LPARAM)(LPCSTR)s );


and in your WndProc


string sString = Marshal.PtrToStringAnsi(m.LParam);


This is providing you're not using a unicode build.

Anyway if you can't use SendMessage you'll have to have a list of strings to be 'got' by your .NET class. Whenever it receives the message it needs to call a method on your com object to retrieve all the strings in the list, and clear the list.

Darwen.

MGupta123
March 14th, 2005, 03:20 AM
I tried SendMessage. But still the function returns me an empty string.
I also tried implementing an article about the same. The link is http://www.codeproject.com/string/sendcstring.asp

But that also doesn't help.

darwen
March 14th, 2005, 03:29 AM
I've just noticed that 's' is a pointer to a CString. You shouldn't be doing this, it's going to leak all over the place. Try this instead (remove the CString *s = ... line).


SendMessage( hRestHWnd, nRestoreDevice , i+1, (LPARAM)(LPCSTR)name );


You can't pass a pointer to a CString like this. .NET has no concept of the CString class.

Darwen.

MGupta123
March 14th, 2005, 03:34 AM
It gives the following error:

error C2440: 'type cast' : cannot convert from 'class CString' to 'const char *'

darwen
March 14th, 2005, 03:41 AM
You're using a unicode build aren't you. I said it wouldn't work in unicode builds.

You'll have to do this then instead :


// .cpp
SendMessage( hRestHWnd, nRestoreDevice , i+1, (LPARAM)(LPCWSTR)name );



// C#
string sString = Marshal.PtrToStringUnicode(m.LParam);


Darwen.

darwen
March 14th, 2005, 03:50 AM
Oh and I've come up with a way of using PostMessage. You can use task memory to do this :


WCHAR *pwcText = (WCHAR *)::CoAllocTaskMem((1 + name.GetLength()) * 2);
::wcscpy(pwcText, name);

::PostMessage(hRestHWnd, nRestoreDevice , 0, (LPARAM)pwcText);


and in .NET


string sString = Marshal.PtrToStringUnicode(m.LParam);
Marshal.FreeCoTaskMem(m.LParam);


Darwen.

MGupta123
March 14th, 2005, 03:54 AM
If I do this then I am getting only the first alphabet of the string.
However if I do as follows:

const char * pszMsg = "Likeme";
i=7;
PostMessage( GetRestHWnd(), GetRestMsgId(), 20, (LPARAM)pszMsg );

I am getting the string.

MGupta123
March 14th, 2005, 04:03 AM
How do I use "CoAllocTaskMem"

The compiler does not recognize it.

darwen
March 14th, 2005, 04:48 AM
Are you using a UNICODE build or not ? You have yet to say. I NEED this information to be able to continue.

Have you changed the .NET code to use "PtrToStringUnicode" and not "PtrToStringAnsi".

Oh and sorry it's CoTaskMemAlloc that you need to call in C++.

Darwen.

MGupta123
March 14th, 2005, 04:59 AM
Yes. I am using a Unicode Build.

MGupta123
March 14th, 2005, 05:10 AM
When I use this code I get only the first alphabet of the string and not the string.

darwen
March 14th, 2005, 05:54 AM
The code above should work - please recheck with this :


CString sString = L"Hello"; // note the 'L'
WCHAR *pwcText = (WCHAR *)::CoTaskMemAlloc((1 + sString.GetLength()) * 2);
::wcscpy(pwcText, sString);

::PostMessage(hRestHWnd, nRestoreDevice , 0, (LPARAM)pwcText);



// .NET
// NOTE PtrToStringUni here !
string sString = Marshal.PtrToStringUni(m.LParam);
Marshal.FreeCoTaskMem(m.LParam);
System.Diagnostics.Debug.WriteLine(sString);


Check the output.

I know you didn't change the .NET PtrToStringAnsi because if you had then it wouldn't have worked. The above is the correct function.

I must apologise - I'm writing all of this without compiling it assuming that you can work out what I mean.

Darwen.

MGupta123
March 14th, 2005, 07:48 AM
Thanks a lot Darwen!

It works perfectly. I did not forget to change to PtrToStringUni().

MGupta123
March 15th, 2005, 12:44 AM
Hi Darwen,

I am using the above code. If I use the Post message a number of times say 10-12. Then my application is terminating with an error message which says:

The instruction at "0x77fcc2c0" refernced memory at "0x004d0041". The memory could not be "written".


What could be the reason.

darwen
March 16th, 2005, 04:13 AM
Which part of the app is GPF-ing ? The .NET side or the C++ side ? If it's the C++
side if you run the dll in the debugger it should tell you which line it's GPF-ing on.

Darwen.