1

I had problems to send a double array from one application to another (both c#).

I try format the CopyData Struct like this:

    [StructLayout(LayoutKind.Sequential)]
    public struct CopyDataStruct
    {
        public IntPtr dwData;
        public int cbData;
        [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.R8)]
        public double[] lpData;
    }

In Sender Application I fill the struct like this:

            double[] a = new double[2] { 1.0, 2.0 };
            int size = Marshal.SizeOf(typeof(double)) * a.Count();

            CopyDataStruct copyDataStruct;
            copyDataStruct.dwData = IntPtr.Zero;
            copyDataStruct.lpData = a;
            copyDataStruct.cbData = size;

            int result = SendMessage(hWnd, WM_COPYDATA, 0, ref copyDataStruct);

In Receiver Application, I try this:

    private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
    {
        switch (msg)
        {
            case (int)WINMESSAGES.WM_COPYDATA:
                CopyDataStruct cp = (CopyDataStruct)Marshal.PtrToStructure(lParam, typeof(CopyDataStruct));

                break;
        }

        return IntPtr.Zero;
    }

but in cp.lpData value comes null. I don't know if I sent wrong or if I received wrong. Please help, thanks.

m59
  • 43,214
  • 14
  • 119
  • 136
Jeferson Preti
  • 57
  • 2
  • 12
  • Getting null is hard to explain, but it can't work as declared. PtrToStructure() cannot figure out how big the array is. Add `SizeConst = 2` to the [MarshalAs] attribute and try again. – Hans Passant Dec 13 '13 at 18:43
  • Thank you Hans. I tried this and in Receiver I get a double array with a very low number in index 0 (cp.lpData[0] = 2.0760134663004284E-305) and a very high number in index 1 (cp.lpData[1] = 6.6028210135419114E+260). – Jeferson Preti Dec 13 '13 at 19:10
  • Your declaration for SendMessage() is wrong, the 3rd argument is IntPtr, not int. – Hans Passant Dec 13 '13 at 19:20
  • [DllImport("User32.dll", EntryPoint = "SendMessage")] public static extern int SendMessage(int hWnd, int Msg, int wParam, ref CopyDataStruct lParam); This works for individual values ​​(strings, doubles). I can not make it work only for arrays. Thank you again Hans. – Jeferson Preti Dec 13 '13 at 19:22

1 Answers1

0

You need to use native memory. Passing C# double[] like that wont work. It will be garbage collected(heck, it's not even allocated in C# - it's just in stack). You can either pin the object with unsafe/fixed keywords or use AllocHGlobal.

This is some code I ripped from Internets. Demonstrates sending part:

    // Marshal the managed struct to a native block of memory.
    var myStruct = new double[2] { 1.0, 2.0 };
    int myStructSize = Marshal.SizeOf(myStruct); 
    IntPtr pMyStruct = Marshal.AllocHGlobal(myStructSize);
    try
    {
        Marshal.StructureToPtr(myStruct, pMyStruct, true);

        COPYDATASTRUCT cds = new COPYDATASTRUCT();
        cds.cbData = myStructSize;
        cds.lpData = pMyStruct;

        // Send the COPYDATASTRUCT struct through the WM_COPYDATA message to 
        // the receiving window. (The application must use SendMessage, 
        // instead of PostMessage to send WM_COPYDATA because the receiving 
        // application must accept while it is guaranteed to be valid.)
        NativeMethod.SendMessage(hTargetWnd, WM_COPYDATA, this.Handle, 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);
    }

Taken: http://code.msdn.microsoft.com/windowsdesktop/CSReceiveWMCOPYDATA-dbbc7ed7

m59
  • 43,214
  • 14
  • 119
  • 136
Erti-Chris Eelmaa
  • 25,338
  • 6
  • 61
  • 78
  • Thank you for answer. In "Marshal.StructureToPtr(myStruct, pMyStruct, true);" I had the error "The specified structure must be blittable or have layout information." Any ideas? – Jeferson Preti Dec 13 '13 at 18:48