Two examples are included here.
The first sends an arbitrary structure (called txStruct) to another process.
In the second, a 64-bit C# application receives a message from a 32-bit C++ DLL.
Note that the COPYDATASTRUCT messaging capability shown can work even between differing memory architectures.
[StructLayout(LayoutKind.Sequential)]
struct COPYDATASTRUCT
{
public IntPtr dwData; // Any value the sender chooses. Perhaps its main window handle?
public int cbData; // The count of bytes in the message.
public IntPtr lpData; // The address of the message.
}
const int WM_COPYDATA = 0x004A;
<StructLayout(LayoutKind.Sequential)> _
Structure COPYDATASTRUCT
Public dwData As IntPtr
Public cdData As Integer
Public lpData As IntPtr
End Structure
None.
// The COPYDATASTRUCT describes the data that is passed.
// The message is routed via the receiving process's window handle.
// The first field, dwData, may contain anything the sender wishes; it is the equivalent of System.Object sender in an EventHandler.
// The count of bytes is given in cbData.
// And the data itself is pointed to by lpData.
[StructLayout(LayoutKind.Sequential)]
struct COPYDATASTRUCT
{
public IntPtr dwData;
public int cbData;
public IntPtr lpData;
}
// The data may be of any agreed-upon form.
// The Pack parameter to the structure gives the padding between fields.
// Here Pack = 1 is used because the original data was created in a 32-bit C++ DLL and no padding was used.
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct GEORECT
{
// The string is included inline in the data.
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 11)]
public string Falconview; // "FALCONVIEW"
public MessageType Type { get; set; } // MessageType.FV_RUBBERBAND_GEORECT_MSG (3)
public int MessageId { get; set; }
public double NW_Latitude { get; set; }
public double NW_Longitude { get; set; }
public double SE_Latitude { get; set; }
public double SE_Longitude { get; set; }
}
// Allocate a pointer to an arbitrary structure on the global heap.
public static IntPtr IntPtrAlloc<T>(T param)
{
IntPtr retval = Marshal.AllocHGlobal(Marshal.SizeOf(param));
Marshal.StructureToPtr(param, retval, false);
return retval;
}
// Free a pointer to an arbitrary structure from the global heap.
public static void IntPtrFree(ref IntPtr preAllocated)
{
if (IntPtr.Zero == preAllocated)
throw (new NullReferenceException("Go Home"));
Marshal.FreeHGlobal(preAllocated);
preAllocated = IntPtr.Zero;
}
// An example of sending a message containing a txStruct.
public SendMessage()
{
IntPtr buffer = IntPtrAlloc(txStruct);
COPYDATASTRUCT copyData = new COPYDATASTRUCT();
copyData.dwData = IntPtr.Zero;
copyData.lpData = buffer;
copyData.cbData = Marshal.SizeOf(txStruct);
IntPtr copyDataBuff = IntPtrAlloc(copyData);
SendMessage(hWnd, WM_COPYDATA, IntPtr.Zero, copyDataBuff);
IntPtrFree(ref copyDataBuff);
IntPtrFree(ref buffer);
}
// Receive a COPYDATASTRUCT message from FalconView
// containing a geocoordinate rectangle
protected override void WndProc(ref Message m)
{
switch (m.Msg)
{
//
case (int)WM.COPYDATA:
var msg = Marshal.PtrToStructure<COPYDATASTRUCT>(m.LParam);
var pData = Marshal.PtrToStructure<GEORECT>(msg.lpData);
if (pData.Falconview != FalconShu.FALCONVIEW)
break;
if (MessageType.FV_RUBBERBAND_GEORECT_MSG == pData.Type
&& this.messageId == pData.MessageId)
{
this.Simulation.WeatherArea.N = pData.NW_Latitude;
this.Simulation.WeatherArea.W = pData.NW_Longitude;
this.Simulation.WeatherArea.S = pData.SE_Latitude;
this.Simulation.WeatherArea.E = pData.SE_Longitude;
NativeWindow.SetForegroundWindow(this.Handle);
return;
}
else if (MessageType.FV_RUBBERBAND_GEORECT_CANCELED == pData.Type)
{
// Message overwritten by another attempt to get it
return;
}
break;
}
base.WndProc(ref m);
}