Delphi_developer
asked on
C# to Delphi WM_COPYDATA
Hi
I'm trying to pass some small data from C# to Delphi and have decided to try to make it work with WM_COPYDATA. I have a C# code that does pass message to Delphi and Delphi that receives it, but I have problem with the message format, content.
I send
from C# : "Test message"
and I get in Delphi: #1#0#0#0'T'...
See screenshot of sText value in Delphi:
I'm sure I'm very close, but don't know where I'm failing.
Here is C# code:
And Delphi:
Any help would be appreciated!
Thank you!
I'm trying to pass some small data from C# to Delphi and have decided to try to make it work with WM_COPYDATA. I have a C# code that does pass message to Delphi and Delphi that receives it, but I have problem with the message format, content.
I send
from C# : "Test message"
and I get in Delphi: #1#0#0#0'T'...
See screenshot of sText value in Delphi:
I'm sure I'm very close, but don't know where I'm failing.
Here is C# code:
using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Security;
class Program
{
public const int WM_COPYDATA = 0x004A;
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("user32.dll")]
public static extern bool PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll")]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[System.Runtime.InteropServices.DllImport("user32.dll",CharSet = CharSet.Auto)]
public static extern IntPtr SendMessage(IntPtr hwnd, int msg,IntPtr wparam, IntPtr lparam);
[DllImport("user32.dll", EntryPoint = "FindWindow")]
public static extern IntPtr FindWindowByCaption(IntPtr ZeroOnly, string lpWindowName);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct MyStruct
{
public int Number;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string Message;
}
public static IntPtr IntPtrAlloc<T>(T param)
{
IntPtr retval = Marshal.AllocHGlobal(Marshal.SizeOf(param));
Marshal.StructureToPtr(param, retval, false);
return (retval);
}
public static void IntPtrFree(IntPtr preAllocated)
{
if (IntPtr.Zero == preAllocated) throw (new Exception("Go Home"));
Marshal.FreeHGlobal(preAllocated); preAllocated = IntPtr.Zero;
}
[StructLayout(LayoutKind.Sequential)]
public struct COPYDATASTRUCT
{
public IntPtr dwData; // Specifies data to be passed
public int cbData; // Specifies the data size in bytes
public IntPtr lpData; // Pointer to data to be passed
}
[SuppressUnmanagedCodeSecurity]
public class NativeMethod
{
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr SendMessage(IntPtr hWnd, int Msg,
IntPtr wParam, ref COPYDATASTRUCT lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
}
}
public static class MyCalss
{
public static System.String MyFunc()
{
// Find the target window handle.
IntPtr hTargetWnd = Program.NativeMethod.FindWindow(null, "ReceiverMainForm");
if (hTargetWnd == IntPtr.Zero)
{
MessageBox.Show("Unable to find the \"ReceiverMainForm\" window",
"Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
// Prepare the COPYDATASTRUCT struct with the data to be sent.
Program.MyStruct myStruct;
myStruct.Number = 1;
myStruct.Message = "Test message";
myStruct.Message = myStruct.Message;
// Marshal the managed struct to a native block of memory.
int myStructSize = Marshal.SizeOf(myStruct)+1;
IntPtr pMyStruct = Marshal.AllocHGlobal(myStructSize);
try
{
Marshal.StructureToPtr(myStruct, pMyStruct, true);
Program.COPYDATASTRUCT cds = new Program.COPYDATASTRUCT();
cds.dwData = (IntPtr)1;
cds.cbData = myStructSize;
cds.lpData = pMyStruct;
MessageBox.Show("myStructSize"+(int)myStructSize,
"Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
Program.NativeMethod.SendMessage(hTargetWnd, Program.WM_COPYDATA, IntPtr.Zero, ref cds);
int result = Marshal.GetLastWin32Error();
if (result != 0)
{
MessageBox.Show(String.Format(
"SendMessage(WM_COPYDATA) failed w/err 0x{0:X}", result));
}
}
finally
{
Marshal.FreeHGlobal(pMyStruct);
}
return "done";
}
}
And Delphi:
procedure TForm1.WMCOPYDATA(var Msg: TWMCopyData);
var
sText: String;
begin
Msg.Result:=0;
if Msg.CopyDataStruct.cbData>0 then
begin
SetLength(sText, Msg.CopyDataStruct.cbData);
CopyMemory(PChar(sText), Msg.CopyDataStruct.lpData, Msg.CopyDataStruct.cbData);
Msg.Result:=1;
end;
ShowMessage(sText);
end;
Any help would be appreciated!
Thank you!
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
What delphi version are you using?
ASKER
I use Delphi 2006. What is easiest to convert for future expansion.. convert to Ansi in C# or in Delphi?
If you are planning to migrate Delphi to a unicode version (2007 and above) it's easiest on Delphi side, otherwise you should do it on C# side.
ASKER
I'm planning to migrate to XE7/8, but not for months and I need solution now.
I'm new to C# and even though I tried to figure out what to do, from user chaau suggestion, I don't know how to do it, Since nobody posted a suggestion, yet, I assume is not a simple convert function...
I'm new to C# and even though I tried to figure out what to do, from user chaau suggestion, I don't know how to do it, Since nobody posted a suggestion, yet, I assume is not a simple convert function...
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Thank you, Sinisa, it works!
I changed Delphi to:
And it seems to be working without text limit, I sent 8.000 characters and it works like a charm! :)
I will make a note for XExx versions.
Now it works, I just hope I don't get to any surprises when using it.
Just a quick sub question:
Is this structure fixed (dwData,cbData and lpData)?
All examples I found online are the same structure. So, I can send 1 Number and 1 Text. Or is it possible to set custom structure, like 10x Number and 10 x Text?
The question is because, ideally, I would like to send more data... and it this case I would just include everything in a single text:
'PARAM_NAMES=Param1;Param2 ;param3;Pa ram4;Param 5...;PARAM _VALUES=Va lue1;Value 2;Value3;V alue4;Valu e5;...' - to pass 5 parameters (name and value).
It is possible with different structure, but don't know where to go.
Thank you!
I changed Delphi to:
s:=Pchar(msg.CopyDataStruct.lpData);
Number := msg.CopyDataStruct.dwData;
ShowMessage('Msg: ' + s + ' Number: ' + IntToStr(Number));
And it seems to be working without text limit, I sent 8.000 characters and it works like a charm! :)
I will make a note for XExx versions.
Now it works, I just hope I don't get to any surprises when using it.
Just a quick sub question:
Is this structure fixed (dwData,cbData and lpData)?
All examples I found online are the same structure. So, I can send 1 Number and 1 Text. Or is it possible to set custom structure, like 10x Number and 10 x Text?
The question is because, ideally, I would like to send more data... and it this case I would just include everything in a single text:
'PARAM_NAMES=Param1;Param2
It is possible with different structure, but don't know where to go.
Thank you!
There is two ways as I can see. One is to use record/structure as you do before - but same must be implemented in revers order in Delphi. Second is to use aka xml text which you can send as you do now.
text to send:
<IPCText><Param1>12</Param 1><Param2> 5</Param2> <Text1></T ext1></IPC Text>
... with crlf+tabs if you like. Use some parser and voilà...
text to send:
<IPCText><Param1>12</Param
... with crlf+tabs if you like. Use some parser and voilà...
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Thank you, very much appreciated the solution and all the comments!