Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Interop SendMessage : How to pass Structure to be filled by SendMessage

140 views
Skip to first unread message

michelqa

unread,
Jul 24, 2008, 6:30:34 PM7/24/08
to
Hi,

I already post a similar question last week without success.

Ok I want to get the current text selection in a RICHEDIT control..
This can be easily done in C++ with EM_EXGETSEL message. I really
need to do the same thing in C#.

How can I put the structure in memory to be able to call SendMessage
and get the expected results in the structure.

Im playing with the following code but the target application always
crash.
For using the following example you need to start WordPad.exe (not
notepad), manually get the handle of the RichEdit control with Spy++
and replace the handle parameter in the sendmessage

initial condition : Type and select some text in WordPad

The following code must return Starting and ending position of
selected text in WordPad.

using System;
using System.Collections;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Diagnostics;

//..
[DllImport("user32.dll")]
public static extern IntPtr SendMessage(IntPtr hwnd, int msg, IntPtr
wparam, IntPtr lparam);


private const int WM_USER = 1024;
private const int EM_EXGETSEL = WM_USER + 52;

[StructLayout(LayoutKind.Sequential)]
public struct CharRange
{
public int From;
public int To;
public CharRange(int from, int to)
{
this.From = from;
this.To = to;
}
}
//..
CharRange ChrRange= new CharRange();
IntPtr ChrRangePtr = Marshal.AllocCoTaskMem(Marshal.SizeOf(ChrRange));
Marshal.StructureToPtr(ChrRange,ChrRangePtr, false);
SendMessage(Handle,EM_EXGETSEL,IntPtr.Zero,ChrRangePtr);
Marshal.PtrToStructure(ChrRangePtr,ChrRange);
MessageBox.Show("From="+ChrRange.From.ToString()+",
to="+ChrRange.To.ToString());

Is anybody know how to correctly code the structure pointer marshaling
part??? How to make this simple example working?

Please help me if you can.. :(

Pavel Minaev

unread,
Jul 25, 2008, 2:42:35 AM7/25/08
to

At the first glance your declarations are okay. The problem seems to
be this:

Marshal.PtrToStructure(ChrRangePtr,ChrRange);

It doesn't work like that. The signature of this method is:

public static void PtrToStructure(
IntPtr ptr,
Object structure
);

It is actually quite misleading, but the second argument named
"structure" actually is of type object - so when you pass a struct
(i.e. a value type) to it, it gets boxed first, and the method
operates on that boxed copy. In fact, this method tries to detect
this, as described in MSDN:

"Exceptions: ArgumentException when structure layout is not
sequential or explicit or structure is a boxed value type."

What you need to do is to use the second overload, like this:

ChrRange = (CharRange)PtrToStructure(ChrRangePtr,
typeof(CharRanger));

See if that helps.

Also, don't forget to free the memory block you've allocated - GC
won't do it for you.

michelqa

unread,
Jul 25, 2008, 2:46:30 PM7/25/08
to
CharRange ChrRange= new CharRange();
IntPtr ChrRangePtr =
Marshal.AllocCoTaskMem(Marshal.SizeOf(ChrRange));
Marshal.StructureToPtr(ChrRange,ChrRangePtr, false);
Win32.SendMessage(Handle,
(int)Win32.WindowsMessages.EM_EXGETSEL,IntPtr.Zero,ChrRangePtr);
ChrRange =
(CharRange)Marshal.PtrToStructure(ChrRangePtr,typeof(CharRange));

MessageBox.Show("From="+ChrRange.From.ToString()+",
to="+ChrRange.To.ToString());
Marshal.FreeCoTaskMem(ChrRangePtr);

the target application is still crashing when executing SendMessage :
The memory could not be 'written'

What is wrong with my ChrRangePtr???

Note: In my test the target application is WordPad.exe and Handle is
the RichEdit Handle

Stephen Martin

unread,
Jul 26, 2008, 2:00:13 PM7/26/08
to
The problem has nothing to do with C# or marshalling. You would have the
same problem in C++. You are allocating a structure in your process's memory
space and then passing the address of that structure to another process
(WordPad in this case). Unfortunately, in that other process you have no
idea what that address is pointing to but it certainly isn't your structure.
The other process is trying to write to this unallocated (or otherwise
protected) memory and crashing.

You cannot pass pointers via SendMessage to another process!!

In order to do this you would need to allocate memory in the other process's
space, send that via SendMessage and then read it back to your process. But
you should have a very good reason before you start messing around with
another process's memory.


"michelqa" <mich...@yahoo.ca> wrote in message
news:be603115-8e3c-4207...@v26g2000prm.googlegroups.com...

Pavel Minaev

unread,
Jul 28, 2008, 3:28:22 AM7/28/08
to
On Jul 26, 10:00 pm, "Stephen Martin"

<smar...@removethis.emsoft.andthis.ca> wrote:
> The problem has nothing to do with C# or marshalling. You would have the
> same problem in C++. You are allocating a structure in your process's memory
> space and then passing the address of that structure to another process
> (WordPad in this case). Unfortunately, in that other process you have no
> idea what that address is pointing to but it certainly isn't your structure.
> The other process is trying to write to this unallocated (or otherwise
> protected) memory and crashing.
>
> You cannot pass pointers via SendMessage to another process!!
>
> In order to do this you would need to allocate memory in the other process's
> space, send that via SendMessage and then read it back to your process. But
> you should have a very good reason before you start messing around with
> another process's memory.

This is not entirely true, since SendMessage does perform pointer
marshalling for cross-process sends, but only for message types that
it knows - and those are all messages with codes smaller than WM_USER.
To quote MSDN:

"The system only does marshalling for system messages (those in the
range 0 to (WM_USER-1)). To send other messages (those >= WM_USER) to
another process, you must do custom marshalling."

Which is just the case here, considering this declaration:

Stephen Martin

unread,
Jul 28, 2008, 8:59:23 AM7/28/08
to
"Pavel Minaev" <int...@gmail.com> wrote in message
news:060780fd-0b01-47cc...@m44g2000hsc.googlegroups.com...


Thanks, that's an important correction. When I edited my post I accidentally
dropped a bit about non-system messages. But, in particular, there are a
number of useful common control messages where the marshalling is done for
you.


michelqa

unread,
Aug 10, 2008, 4:16:50 AM8/10/08
to
On Jul 26, 2:00 pm, "Stephen Martin"

<smar...@removethis.emsoft.andthis.ca> wrote:
> In order to do this you would need to allocate memory in the other process's
> space, send that via SendMessage and then read it back to your process. But
> you should have a very good reason before you start messing around with
> another process's memory.

Any example about how to allocate memory into the other process
memory? I really need to do that for several similar messages :
( ...for now I'm trying to get LVM_GETCOLUMN

michelqa

unread,
Aug 11, 2008, 3:31:28 AM8/11/08
to
0 new messages