5

I have a native C++ Visual Studio 2010 solution and I would like to send data to a .NET app (C# WPF) Is there any way to do this with a few line of C/C++ code? I do not want to use external dependencies on C/C++ side. Is there any sample code out there about this?

More info: The C/C++ native app is really an npapi dll which loads into chrome.exe process. I don't think this is important, pls confirm.

Soner Gönül
  • 97,193
  • 102
  • 206
  • 364
g.pickardou
  • 32,346
  • 36
  • 123
  • 268
  • 1
    `I do not want to use external dependencies on C/C++ side` -- This doesn't seem possible; it's a .NET app, so you're going to be dependent on .NET, unless you're planning on communicating with the app using SendKeys or Windows messages. – Robert Harvey Jan 15 '13 at 21:36
  • What does this data look like? A simple string message? – Science_Fiction Jan 15 '13 at 21:42

2 Answers2

5

I'd recommend Named Pipes; here is a good example of a named pipe implementation between C# & C++. You could also implement COM Interop. Another alternative would be using WM_COPYDATA messages (to catch them you need to override WndProc), which are, however, very restricted:

public static class CopyDataHelper
{
    [StructLayout(LayoutKind.Sequential, Pack=1)]
    public struct COPYDATASTRUCT
    {
        private Int32 _dwData;
        private Int32 _cbData;
        private IntPtr _lpData;

        public Int32 DataId
        {
            get { return _dwData; }
            set { _dwData = value; }
        }

        public Int32 DataSize
        {
            get { return _cbData; }
        }

        public IntPtr Data
        {
            get { return _lpData; }
        }

        public T GetData<T>() where T : struct
        {
            return (T)Marshal.PtrToStructure(_lpData, typeof(T));
        }

        public void SetData<T>(T data) where T : struct
        {
            Int32 size = Marshal.SizeOf(typeof(T));
            IntPtr ptr = Marshal.AllocHGlobal(size);
            Marshal.StructureToPtr(data, ptr, true);

            _cbData = size;
            _lpData = ptr;
        }
    }

    [DllImport("User32.dll", CharSet=CharSet.Unicode, ExactSpelling=true, SetLastError=true)]
    [return:  MarshalAs(UnmanagedType.Bool)]
    internal static extern Boolean SendMessage([In] IntPtr hWnd, [In] UInt32 msg, [In] IntPtr wParam, [In, Out] ref COPYDATASTRUCT lParam);

    public const Int32 WM_COPYDATA = 0x004A;

    public static Boolean Send<T>(IntPtr fromHwnd, IntPtr toHwnd, Int32 dataId, T data) where T : struct
    {
        IntPtr ptr = IntPtr.Zero;

        try
        {
            COPYDATASTRUCT cds = new COPYDATASTRUCT();
            cds.DataId = dataId;
            cds.SetData(data);
            return SendMessage(toHwnd, WM_COPYDATA, fromHwnd, ref cds);
        }
        finally
        {
            if (ptr != IntPtr.Zero)
                Marshal.FreeHGlobal(ptr);
        }
    }

    public static COPYDATASTRUCT Receive(Message msg)
    {
        if (msg.Msg != WM_COPYDATA)
            throw new ArgumentException("This is not a WM_COPYDATA message!");

        return (COPYDATASTRUCT)msg.GetLParam(typeof(COPYDATASTRUCT));
    }   
}

// Override

protected override void WndProc(ref Message msg)
{
    if (msg.Msg == CopyDataHelper.WM_COPYDATA)
    {
        CopyDataHelper.COPYDATASTRUCT cds = CopyDataHelper.Receive(msg);

        if (cds.DataId == myDataId)
        {
            MyData data = cds.GetData<MyData>();
            msg.Result = DoSomething(data);
            return;
        }
    }

    base.WndProc(ref msg);
}

The last chance is to use Google's Protocol Buffers: the original implementation supports only C++, Java & Python... but for .NET there is protobuf-net.

Tommaso Belluzzo
  • 23,232
  • 8
  • 74
  • 98
4

It sounds like you could use named pipes to communicate between the processes.

This question should help to point you in the right direction.

Community
  • 1
  • 1
Adam Maras
  • 26,269
  • 6
  • 65
  • 91