c# – How to drag and drop from C ++ / MFC to C # / WPF

Question: Question:

How can I drag and drop data from a C ++ / MFC program to a C # / WPF program? Currently, with the following code, I was able to confirm that the data was stored in DragEventArgs on the C # side, but I can not retrieve it well. Since the C ++ side is existing code, I would like to support it on the C # side. Should I use C ++ / CLI to create a DLL just for converting values?

C ++ code

typedef struct {
    bool isBar;
    int val;
    WCHAR name[100];
} Bar;

typedef struct {
    int val;
    TCHAR name[100];
    Bar bar[1];
} Foo;

void StartDrag(Foo foo) {
    STGMEDIUM   data;
    data.tymed = TYMED_HGLOBAL;
    data.hGlobal = (HGLOBAL)foo;
    data.pUnkForRelease = NULL;

    CLIPFORMAT f;
    f = RegisterClipboardFormat(TEXT("FOO"));

    COleDataSource *DataSource = new COleDataSource();
    DataSource->CacheData(f, &data);
    DataSource->DoDragDrop(DROPEFFECT_COPY|DROPEFFECT_MOVE);
}

C # code

[StructLayout(LayoutKind.Sequential)]
public struct Bar
{
    [MarshalAs(UnmanagedType.Bool)]
    public bool IsText;
    public int value;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]
    public string name;
}

[StructLayout(LayoutKind.Sequential)]
public struct Foo
{
    public int value;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]
    public string name;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
    public Bar[] bar;
}

void OnDrop(object sender, DragEventArgs e)
{
    if (e.Data.GetDataPresent("FOO"))
    {
        var fooStream = e.Data.GetData("FOO");
        // fooStreamはMemoryStream、BinaryReaderで見ると
        // C++側で設定した値が入っているのが見える

        var foo = e.Data.GetData(typeof(Foo)); // fooはnull
    }
}

Answer: Answer:

I think that System.Runtime.InteropServices.Marshal can be realized only with C #.
(Unconfirmed until operation)

MemoryStream ms = //...
Foo obj;

byte[] data = ms.ToArray();
if (data.Length != Marshal.SizeOf(Foo)) {
  // 受信サイズがFoo型サイズと一致しないためマーシャリング不可
  // 適切なエラー処理...
}
IntPtr rawmem = Marshall.AllocCoTaskMem(data.Length);
try {
  Marshal.Copy(data, 0, rawmem, data.Length)
  obj = (Foo)Marshal.PtrToStructure(rawmem, typeof(Foo));
} finally {
  Marshal.FreeCoTaskMem(rawmem);
}

Since the C ++ side struct Bar and Foo contain string type WCHAR and TCHAR members, respectively, it is better to specify the appropriate CharSet value in the StructLayout attribute of the C # side struct.

Scroll to Top