Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsFree MagazinesWhite PapersSubmit Content
Discussion GroupsASP.NETWindows FormsLanguages.NET FrameworkVisual Studio.NET
Articles.NET FrameworkASP.NETToolsWindows Forms
.NET DirectoryOpen Source ProjectsUser GroupsWeb Resources
Related Topics
Visual Basic 6SQL ServerMS AccessOther DB ProductsMS Server ProductsMore Topics ...

.NET Forum / .NET Framework / Interop / June 2007

Tip: Looking for answers? Try searching our database.

Passing String to Unmanaged Code

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
dzar - 29 May 2007 20:23 GMT
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
Phil Wilson - 29 May 2007 21:48 GMT
Might be a pinning issue due to GC during the P/Invoke call:

http://msdn.microsoft.com/msdnmag/issues/04/10/NET/
Signature

Phil Wilson
[MVP Windows Installer]

> 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
[quoted text clipped - 23 lines]
> Thanks in advance...
> Dave
dzar - 30 May 2007 02:00 GMT
> Might be a pinning issue due to GC during the P/Invoke call:
>
> http://msdn.microsoft.com/msdnmag/issues/04/10/NET/

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
Walter Wang [MSFT] - 30 May 2007 06:39 GMT
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 - 30 May 2007 15:24 GMT
> Hi Dave,
>
[quoted text clipped - 3 lines]
> 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
Walter Wang [MSFT] - 01 Jun 2007 12:29 GMT
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_Messages/Simple
_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_wmcopy.asp

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.
Mattias Sjögren - 30 May 2007 05:10 GMT
>     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

Signature

Mattias Sjögren [C# MVP]  mattias @ mvps.org
http://www.msjogren.net/dotnet/ | http://www.dotnetinterop.com
Please reply only to the newsgroup.

dzar - 31 May 2007 14:21 GMT
> 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
[quoted text clipped - 6 lines]
>         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 - 31 May 2007 17:14 GMT
>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

Signature

Mattias Sjögren [C# MVP]  mattias @ mvps.org
http://www.msjogren.net/dotnet/ | http://www.dotnetinterop.com
Please reply only to the newsgroup.


Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.