By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
459,458 Members | 1,215 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 459,458 IT Pros & Developers. It's quick & easy.

SendMessage WM_COPYDATA

P: n/a
I am trying to send a WM_COPYDATA message to another application in C#,
..NET 2.0.

The other application receives the message, but only seems to see the
first character of the string, does anybody have any ideas?

I have copied the code below.

class WIN32 {

//SendMessage
[System.Runtime.InteropServices.DllImport("user32.d ll")]
public static extern int SendMessage(System.IntPtr hwnd, int
msg, int wparam, int lparam);
//Copy Data Structure
public struct COPYDATASTRUCT
{
public int dwData;
public int cbData;
public int lpData;
}

public static int VarPtr(object e)
{
System.Runtime.InteropServices.GCHandle GC =
System.Runtime.InteropServices.GCHandle.Alloc(e,
System.Runtime.InteropServices.GCHandleType.Pinned );
int gc = GC.AddrOfPinnedObject().ToInt32();
GC.Free();
return gc;
}

}

public class SendTheMessage {

public SendTheMessage(string str, System.IntPtr handle,
System.IntPtr iHandle, System.UInt32 signature) {
Win32.COPYDATASTRUCT cds;

cds.dwData = Convert.ToInt32(signature);
str = str + '\0';
cds.cbData = 3;
cds.lpData = Win32.VarPtr(str);

Win32.SendMessage(handle, Win32.WM_COPYDATA,
0, Win32.VarPtr(cds));
}

}

Jun 3 '06 #1
Share this Question
Share on Google+
4 Replies


P: n/a
> class WIN32 {

Is Win32 {

public class SendTheMessage {

public SendTheMessage(string str, System.IntPtr handle,
System.IntPtr iHandle, System.UInt32 signature) {
Win32.COPYDATASTRUCT cds;

cds.dwData = Convert.ToInt32(signature);
str = str + '\0';
cds.cbData = 3;


is str.Length (and tried str.Length * 2 ). It's only 3 here from
testing!

Jun 3 '06 #2

P: n/a
>The other application receives the message, but only seems to see the
first character of the string, does anybody have any ideas?
How does the recieving code look like?

//SendMessage
[System.Runtime.InteropServices.DllImport("user32.d ll")]
public static extern int SendMessage(System.IntPtr hwnd, int
msg, int wparam, int lparam);
This is better declared as

[System.Runtime.InteropServices.DllImport("user32.d ll",
CharSet=CharSet.Auto)]
public static extern IntPtr SendMessage(System.IntPtr hwnd, int msg,
IntPtr wparam, ref COPYDATASTRUCT lparam);

//Copy Data Structure
public struct COPYDATASTRUCT
{
public int dwData;
public int cbData;
public int lpData;
}
lpData and dwData should be IntPtrs.

public static int VarPtr(object e)
{
System.Runtime.InteropServices.GCHandle GC =
System.Runtime.InteropServices.GCHandle.Alloc(e ,
System.Runtime.InteropServices.GCHandleType.Pinne d);
int gc = GC.AddrOfPinnedObject().ToInt32();
GC.Free();
return gc;
}


This is completely broken. If a garbage collection happens after the
GC.Free call, your pointer is invalid. Use one of the
Marshal.StringTo* methods to copy the string to a native buffer
instead, and assign the result to cds.lpData.
Mattias

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

P: n/a
Mattias Sjögren wrote:
The other application receives the message, but only seems to see the
first character of the string, does anybody have any ideas?
How does the recieving code look like?


I dont know, this is in a closed source application. Applications
written in other languages seem to have no problem communicating with
it, so it must be an error in my C# code.

//Copy Data Structure
public struct COPYDATASTRUCT
{
public int dwData;
public int cbData;
public int lpData;
}


lpData and dwData should be IntPtrs.


Yes, I have changed that. They were originally, but changed a lot to
retry. I have changed the last paramenter of SendMessage to an IntPtr
public static int VarPtr(object e)
{
System.Runtime.InteropServices.GCHandle GC =
System.Runtime.InteropServices.GCHandle.Alloc(e ,
System.Runtime.InteropServices.GCHandleType.Pinne d);
int gc = GC.AddrOfPinnedObject().ToInt32();
GC.Free();
return gc;
}


This is completely broken. If a garbage collection happens after the
GC.Free call, your pointer is invalid. Use one of the
Marshal.StringTo* methods to copy the string to a native buffer
instead, and assign the result to cds.lpData.


Thanks. I copied that somewhere off the internet, which I knew would
be a bad idea.

I have changed that method to look like this now, but the same result
occurs, the receiving application is only receiving the first 1
character.

I also tried:
cds.lpData =
System.Runtime.InteropServices.Marshal.StringToCoT askMemAnsi(str);

Because this is the reverse of what I do in my overridden wndproc:

string str =
System.Runtime.InteropServices.Marshal.PtrToString Ansi(cds.lpData);

this str, in wndproc, always contains the full string the application
sent me.

--- Updated Function Code ---
Win32.COPYDATASTRUCT cds;

cds.dwData = new System.IntPtr(sig);
str = str + '\0';
cds.cbData = str.Length;
cds.lpData =
System.Runtime.InteropServices.Marshal.AllocCoTask Mem(str.Length);

System.Runtime.InteropServices.Marshal.Copy(str.To CharArray(), 0,
cds.lpData, str.Length);

System.IntPtr iPtr =
System.Runtime.InteropServices.Marshal.AllocCoTask Mem(System.Runtime.InteropServices.Marshal.SizeOf( cds));
System.Runtime.InteropServices.Marshal.StructureTo Ptr(cds,
iPtr, true);

Win32.SendMessage(handle, Win32.WM_COPYDATA, iHandle,
iPtr);

//I would add some code here to Free the Memory

Jun 3 '06 #4

P: n/a
> I also tried:
cds.lpData =
System.Runtime.InteropServices.Marshal.StringToCoT askMemAnsi(str);

Because this is the reverse of what I do in my overridden wndproc:

string str =
System.Runtime.InteropServices.Marshal.PtrToString Ansi(cds.lpData);


This actually did work. I forgot to comment the line below it which
was doing what my old code did.

Thanks Mattias your post got me on right track to making it all work.
For anybody that cares, here
is the code:
Win32.COPYDATASTRUCT cds;

cds.dwData = new System.IntPtr(sig);
str = str + '\0';
cds.cbData = str.Length + 1;
cds.lpData =
System.Runtime.InteropServices.Marshal.AllocCoTask Mem(str.Length);

cds.lpData =
System.Runtime.InteropServices.Marshal.StringToCoT askMemAnsi(str);

System.IntPtr iPtr =
System.Runtime.InteropServices.Marshal.AllocCoTask Mem(System.Runtime.InteropServices.Marshal.SizeOf( cds));
System.Runtime.InteropServices.Marshal.StructureTo Ptr(cds,
iPtr, true);

Win32.SendMessage(handle, Win32.WM_COPYDATA, iHandle,
iPtr);
System.Runtime.InteropServices.Marshal.FreeCoTaskM em(cds.lpData);
System.Runtime.InteropServices.Marshal.FreeCoTaskM em(iPtr);

Jun 3 '06 #5

This discussion thread is closed

Replies have been disabled for this discussion.