COPYDATASTRUCT (Structures)
Last changed: shipr on StackOverflow-76.14.214.109

.
Summary
COPYDATASTRUCT messages may be used to send structured data between processes.

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.

C# Definition:

[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;

VB.NET Definition:

<StructLayout(LayoutKind.Sequential)> _
Structure COPYDATASTRUCT
   Public dwData As IntPtr
   Public cdData As Integer
   Public lpData As IntPtr
End Structure

User-Defined Field Types:

None.

Documentation

C# Structures:

// 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; }
}

C# Global memory allocation

// 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;
}

C# Example 1 - send data:

// 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);
}

C# Example 2 - receive data:

// 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);
}