Как передать структуру из неуправляемой программы C ++ в программу C #? - PullRequest
0 голосов
/ 09 августа 2009

Это мой второй пост.

Вот что я пытаюсь сделать: вызвать неуправляемую программу c ++ из c #, передать массив структур из программы c # и вернуть обновленную версию массива структур из программы c ++.

Вот вызывающая программа c #:

using System;
using System.Runtime.InteropServices;

namespace TestCallingC
{
    class Program
    {
        [DllImport(@"..\..\..\Debug\TestCProgram.dll")]
        public static extern void testfunc(teststruc[] ts);

        static void Main(string[] args)
        {
            teststruc[] teststructs = new teststruc[6];
            for (int i = 0; i < teststructs.Length; i++)
            {
                teststructs[i].int1 = (i + 1) * 100;
                teststructs[i].int2 = (i + 1) * 100;
            }

            testfunc(teststructs);
            for (int i = 0; i < teststructs.Length; i++)
            {
                Console.WriteLine("Int1 = {0}", teststructs[i].int1);
                Console.WriteLine("Int2 = {0}", teststructs[i].int2);
            }
        }
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct teststruc
    {
        [MarshalAs(UnmanagedType.I4)]
        public int int1;
        [MarshalAs(UnmanagedType.I4)]
        public int int2;
    }
}

Вот возвращающаяся программа на С ++:

extern "C" __declspec(dllexport) void testfunc (teststruc* ts)
{
    int i;

    for (i = 0; i < 6; i++)
    {

        ts[i].int1 = i;
        ts[i].int2 = i;
    }

    for (i = 0; i < 6; i++)
    {
        printf("ts[%d].int1 = %d\n", i, ts[i].int1);
        printf("ts[%d].int2 = %d\n", i, ts[i].int2);
    }

    return;
}

Версия, которую я представил выше, позволяет программе на С ++ видеть и распечатывать входящую структуру, переданную из программы на С #. Когда управление передается обратно в программу c #, данные остаются такими же, как они были изначально установлены. Это позволяет обновлять структуру вызываемой программой c ++. Вот вывод консоли. Первая часть показывает обновленные поля из программы c ++; вторая часть - это то, что изначально было установлено c # Вызывающий:

ts[0].int1 = 0
ts[0].int2 = 0
ts[1].int1 = 1
ts[1].int2 = 1    
ts[2].int1 = 2
ts[2].int2 = 2    
ts[3].int1 = 3
ts[3].int2 = 3    
ts[4].int1 = 4
ts[4].int2 = 4
ts[5].int1 = 5
ts[5].int2 = 5

Int1 = 100
Int2 = 100
Int1 = 200
Int2 = 200
Int1 = 300
Int2 = 300
Int1 = 400
Int2 = 400
Int1 = 500
Int2 = 500
Int1 = 600
Int2 = 600

Если я добавлю тег ref к сигнатуре вызова c #, структура, возвращаемая обратно из программы c ++, будет иметь значение null:

[DllImport(@"..\..\..\Debug\TestCProgram.dll")]
        public static extern void testfunc(ref teststruc[] ts);

testfunc(ref teststructs);

Вопрос: Какие обновления интерфейсов в программе на c ++ и c # необходимо выполнить, чтобы структура должным образом обновлялась в программе на c ++ и возвращалась в программу на c #?

Я обнаружил много информации о похожих вещах, но ничто не дало мне правильную комбинацию, чтобы это произошло. Любые советы приветствуются.

Спасибо. * 1021 Грег *

Ответы [ 2 ]

1 голос
/ 09 августа 2009

Случайная дикая догадка:

[DllImport(@"..\..\..\Debug\TestCProgram.dll")]
public static extern void testfunc([In, Out] teststruc[] ts);

С MSDN :

Комбинация InAttribute и OutAttribute особенно полезна при применении к массивам и отформатированным неблизким типам. Вызывающие абоненты видят изменения, которые вызываемый абонент вносит в эти типы, только когда вы применяете оба атрибута. [...]

0 голосов
/ 10 августа 2009

Окончательное решение:

C ++ (без изменений по сравнению с первоначальной версией).

C # код:

using System;
using System.Runtime.InteropServices;

namespace TestCallingC
{
    class Program
    {
        [DllImport(@"..\..\..\Debug\TestCProgram.dll")]
        public static extern void testfunc([In, Out] teststruc[] ts);

        static void Main(string[] args)
        {
            teststruc[] teststructs = new teststruc[6];
            for (int i = 0; i < teststructs.Length; i++)
            {
                teststructs[i].int1 = (i + 1) * 100;
                teststructs[i].int2 = (i + 1) * 100;
            }

            testfunc(teststructs);
            for (int i = 0; i < teststructs.Length; i++)
            {
                Console.WriteLine("Int1 = {0}", teststructs[i].int1);
                Console.WriteLine("Int2 = {0}", teststructs[i].int2);
            }
        }
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct teststruc
    {
        [MarshalAs(UnmanagedType.I4)]
        public int int1;
        [MarshalAs(UnmanagedType.I4)]
        public int int2;
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...