[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

microsoft.public.dotnet.framework.interop

Passing String to Unmanaged Code

dzar

5/29/2007 7:23:00 PM

I'm new to .NET but am trying to pass a string pointer as the lParam of
a SendMessage call from some managed code to my DLL written in unmanaged
C++. What I've done so far is this (in VB.NET as that's what my
colleague wants to use, but if you want to give me a solution in C# that
would be fine, too).

Private Declare Function SendMessageStr Lib "USER32" _
Alias "SendMessageA" ( _
ByVal hWnd As Integer, ByVal Msg As Integer, _
ByVal wParam As Integer, ByVal lParam As String) As Long

(I am trying to use SendMessage and some other functions I wrote in a
similar way...)

Then to call it I do something like this:

Dim MyString as String = "Testing"
SendMessageStr(hwndTarget, MY_MESSAGE, 0, MyString)

While this appears to work, the pointer I receive in my code that
accepts MY_MESSAGE points to memory that is all "??" in the debugger and
posts an error about the stack being corrupted when debugging the VB.NET
code.

So, I'm sure this is simple and I'm doing something terrible, but what?

Thanks in advance...
Dave
8 Answers

Phil Wilson

5/29/2007 8:49:00 PM

0

Might be a pinning issue due to GC during the P/Invoke call:

http://msdn.microsoft.com/msdnmag/issues/...
--
Phil Wilson
[MVP Windows Installer]

"dzar" <dzar@nospam.nospam> wrote in message
news:eWPhRbioHHA.3264@TK2MSFTNGP04.phx.gbl...
> I'm new to .NET but am trying to pass a string pointer as the lParam of a
> SendMessage call from some managed code to my DLL written in unmanaged
> C++. What I've done so far is this (in VB.NET as that's what my colleague
> wants to use, but if you want to give me a solution in C# that would be
> fine, too).
>
> Private Declare Function SendMessageStr Lib "USER32" _
> Alias "SendMessageA" ( _
> ByVal hWnd As Integer, ByVal Msg As Integer, _
> ByVal wParam As Integer, ByVal lParam As String) As Long
>
> (I am trying to use SendMessage and some other functions I wrote in a
> similar way...)
>
> Then to call it I do something like this:
>
> Dim MyString as String = "Testing"
> SendMessageStr(hwndTarget, MY_MESSAGE, 0, MyString)
>
> While this appears to work, the pointer I receive in my code that accepts
> MY_MESSAGE points to memory that is all "??" in the debugger and posts an
> error about the stack being corrupted when debugging the VB.NET code.
>
> So, I'm sure this is simple and I'm doing something terrible, but what?
>
> Thanks in advance...
> Dave


dzar

5/30/2007 1:00:00 AM

0

Phil Wilson wrote:
> Might be a pinning issue due to GC during the P/Invoke call:
>
> http://msdn.microsoft.com/msdnmag/issues/...

This doesn't seem to make any difference. Here's what I did (maybe this
is wrong):

pinHandle = GCHandle.Alloc(MyString, GCHandleType.Pinned)
SendMessage(WindowHandle, MY_MESSAGE, 0, MyString)

and, as a test, never freed the handle. Still I get a pointer in my DLL
that is bogus. Then I remembered doing something like this in the past
where I needed to use the StringBuilder class. So I defined SendMessage
to take a StringBulder by value and it didn't fix things, either. Same
behavior.

In my DLL I set a breakpoint where I get the lParam and then just look
at memory that it's point to. I see all ?? when I do.

Any other ideas? I cannot imagine why posting to a message queue would
be so hard... fundamental Windows stuff (or at least it was before .NET).

Thanks,
Dave

(Mattias Sjögren)

5/30/2007 4:10:00 AM

0

> Private Declare Function SendMessageStr Lib "USER32" _
> Alias "SendMessageA" ( _
> ByVal hWnd As Integer, ByVal Msg As Integer, _
> ByVal wParam As Integer, ByVal lParam As String) As Long

The return type should be IntPtr (or possibly Integer on Win32).


Mattias

--
Mattias Sjögren [C# MVP] mattias @ mvps.org
http://www.msjogren.n... | http://www.dotneti...
Please reply only to the newsgroup.

wawang

5/30/2007 5:39:00 AM

0

Hi Dave,

The string will not need to manually pinned, the marshaller should take
care of it.

I think it's related to how's your C DLL implemented. Would you please tell
us how is the function exported from your DLL?

Here's some code to demonstrate how to use SendMessage and WM_SETTEXT to
change a Notepad window's caption:

Private Declare Auto Function FindWindow Lib "user32" (ByVal className
As String, ByVal windowName As String) As IntPtr
Private Declare Auto Function SendMessage Lib "user32" (ByVal hwnd As
IntPtr, ByVal msg As Integer, ByVal wParam As Integer, ByVal lParam As
String) As IntPtr
Private Declare Function SendMessageStr Lib "user32" Alias
"SendMessageA" (ByVal hwnd As IntPtr, ByVal msg As Integer, ByVal wParams
As Integer, ByVal lParam As String) As Integer
Const WM_SETTEXT As Integer = &HC

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button1.Click
Dim h As IntPtr = FindWindow("Notepad", Nothing)
If h <> IntPtr.Zero Then
SendMessage(h, WM_SETTEXT, 0, DateTime.Now.ToString())
SendMessageStr(h, WM_SETTEXT, 0, DateTime.Now.ToString)
End If
End Sub


Please note the two declarations, both should work correctly.

Regards,
Walter Wang (wawang@online.microsoft.com, remove 'online.')
Microsoft Online Community Support

==================================================
When responding to posts, please "Reply to Group" via your newsreader so
that others may learn and benefit from your issue.
==================================================

This posting is provided "AS IS" with no warranties, and confers no rights.

dzar

5/30/2007 2:24:00 PM

0

Walter Wang [MSFT] wrote:
> Hi Dave,
>
> The string will not need to manually pinned, the marshaller should take
> care of it.
>
> I think it's related to how's your C DLL implemented. Would you please tell
> us how is the function exported from your DLL?
>

Yes, I think this is where the problem might be. What I've tried, before reading
this, was to use MessageBox from the Windows API to display my string and that
works.

What I am doing in my C code is this:

[in my message loop...]

case MY_MESSAGE :
TCHAR *mystr = (TCHAR *) lParam
do something with mystr...
return 0;

to try and cast the pointer that I believe should be passed in lParam with
SendMessageStr(h, MY_MESSAGE, 0, MyString). I get a bad pointer, however, and
when I look at the memory pointed to by lParam, it's not valid.

So, I guess I'm probably not assuming the right thing in my C code. What should
I be doing to read the string in my C code? Is lParam a pointer in this case as
I believe it should be?

Thanks,
Dave

dzar

5/31/2007 1:22:00 PM

0

dzar wrote:
> I'm new to .NET but am trying to pass a string pointer as the lParam of
> a SendMessage call from some managed code to my DLL written in unmanaged
> C++. What I've done so far is this (in VB.NET as that's what my
> colleague wants to use, but if you want to give me a solution in C# that
> would be fine, too).
>
> Private Declare Function SendMessageStr Lib "USER32" _
> Alias "SendMessageA" ( _
> ByVal hWnd As Integer, ByVal Msg As Integer, _
> ByVal wParam As Integer, ByVal lParam As String) As Long

I've narrowed this problem down to what I believe is a memory issue. The above
lParam is a valid pointer to memory within my VB program (I can see it in the
debugger and it's what I expect it to be). When I pass this same value to
something like the WindowsAPI MessageBox() function, it works just fine. When I
see it in my C DLL, however, it's not allowing me to read the memory.

So what is so magical about what something like MessageBox() does that it can
read the memory pointed to by lParam and my C DLL cannot? I do this (which
should work, it seems, but doesn't):

case MY_MESSAGE :
TCHAR *mystr = (TCHAR *) lParam
do something with mystr...
return 0;

mystr is the correct pointer value but when I try to dereference it, it is
invalid and the data are invalid as far as my DLL is concerned.

Dave

(Mattias Sjögren)

5/31/2007 4:15:00 PM

0

>I've narrowed this problem down to what I believe is a memory issue. The above
>lParam is a valid pointer to memory within my VB program (I can see it in the
>debugger and it's what I expect it to be). When I pass this same value to
>something like the WindowsAPI MessageBox() function, it works just fine. When I
>see it in my C DLL, however, it's not allowing me to read the memory.

Is the DLL loaded into the VB application or another process? Keep in
mind that pointers are only valid within the same process.

Also, since you're using TCHAR in your C code, are you using a Unicode
build or not?


Mattias

--
Mattias Sjögren [C# MVP] mattias @ mvps.org
http://www.msjogren.n... | http://www.dotneti...
Please reply only to the newsgroup.

wawang

6/1/2007 11:30:00 AM

0

Hi Dave,

As Mattias pointed out, the address pointed to by the C# string is not
directly accessible by your C code. It's recommended to use WM_COPYDATA to
pass such data.

Here's an example on how to use it in managed code:

#vbAccelerator - Simple Interprocess Communications using WM_COPYDATA
http://www.vbaccelerator.com/home/NET/Code/Libraries/Windows_Messa...
_Interprocess_Communication/article.asp


For C/C++ side on how to use WM_COPYDATA, please see this example:

#Inter-Process Communication using WM_COPYDATA - The Code Project -
Threads, Processes & IPC
http://www.codeproject.com/threads/ipc_...


Regards,
Walter Wang (wawang@online.microsoft.com, remove 'online.')
Microsoft Online Community Support

==================================================
When responding to posts, please "Reply to Group" via your newsreader so
that others may learn and benefit from your issue.
==================================================

This posting is provided "AS IS" with no warranties, and confers no rights.