Передача объектов между C # и C - PullRequest
2 голосов
/ 21 февраля 2010

Мое приложение состоит из кода C # с неуправляемыми вызовами C dll. В моем коде C # у меня есть объект / класс, в котором его свойства являются системными типами, такими как string и int, и другими объектами, которые я определил.

Я хотел бы передать этот сложный объект (Graph.cs) в мой код C (dll), какую реализацию вы бы предложили здесь?

Я пробовал перемещать структуры, но у меня ничего не получается, кроме string и int.

Спасибо.

Код:

public Class Grpah {

    TupleCollection m_TupleCollection;
    int m_nGeneralIndex;       
    bool m_bPrintWRF;
    string m_sLink;  
}

public Class TupleCollection {

    IList<Tuple> _collection;

}     

public Class Tuple {

    Globals.TupleType m_ToppleType;        
    ArrayList m_Parameters;

}

public class TupleArgs {

    public string Value { get; set; }       
    public Globals.PAS PAS;
    public RefCollection RefCollection { get; set; }
    public int Time{ get; set; }      

}

public class RefCollection {

    public List<int> SynSet{ get; set; } 
    public Globals.PAS PAS;

}

Ответы [ 3 ]

6 голосов
/ 21 февраля 2010

Попробуйте:

Как: маршал структуры с помощью PInvoke

Я думаю, что самый простой способ добиться прогресса - это изменить нативный код, давая ему возможность работать с типами CLR.

Теперь вы почти наверняка используете Visual Studio, и, надеюсь, это VS2005 или более поздняя версия. Это означает, что, хотя ваш существующий нативный код находится в C, у вас есть возможность углубиться в немного C ++. И не только это - у вас также есть C ++ / CLI.

Так что я бы сделал новую C ++ / CLI DLL и связал бы с ней вашу C-библиотеку, чтобы она могла вызывать C-код. Затем напишите тонкий слой перевода в библиотеке C ++ / CLI: он предоставит истинные классы CLR (написанные с помощью ref class) и вызовет собственный код C.

например. в заголовке C:

void do_something_with_foo_data(int a, int b, int c);

В C ++ / CLI:

public ref class FooWrapper
{
    static void DoSomethingWithFoo(Foo ^foo)
    {
        // pick apart the Foo class and pass the pieces on to the C function

        do_something_with_foo_data(foo->A, foo->B, foo->C);
    }
};

В C #:

public class Foo
{
    public int A { get; set; }
    public int B { get; set; }
    public int C { get; set; }
}

...

var foo = new Foo { A = 1, B = 2, C = 3 };
FooWrapper.DoSomethingWithFoo(foo);
2 голосов
/ 25 февраля 2010

Когда я сделал это, я использовал исключительно Маршал . Это было со стандартным C для нативного кода. Я не хотел конвертировать свой код C в «управляемый C ++» или как там его называют: -)

Трудная и утомительная часть заключается в том, что вам нужно вручную упорядочить структуру данных во что-то, что отображается непосредственно в принимающую функцию C. В моем случае я должен был создать отдельные структуры для каждого класса данных C #, который я хотел отправить. По сути, вы должны преобразовать вашу красивую иерархию объектов C # в более простую форму, состоящую из структур, которые вы затем объединяете в блок памяти, который вы затем используете в качестве аргумента в вашем собственном вызове.

Вам следует использовать метод Marshal.AllocHGlobal для выделения памяти и Marshal.StructureToPtr для копирования структуры C # в эту память, а затем Marshal.FreeHGlobal для ее освобождения.

Получив IntPtr (из StructureToPtr), вы сможете просто вызвать C-dll с указателем в качестве аргумента. Обратите внимание, что структура, которую вы отправляете в свою функцию C, должна иметь ту же структуру, что и собственная структура C, иначе вы получите очень странные результаты.

Возврат данных - это почти то же самое, но вы используете противоположные функции (PtrToStructure и т. Д.).

В любом случае, это основное.

0 голосов
/ 25 февраля 2010

Ваша модель выглядит довольно сложной и неполной: Tuple.m_parameters - это ArrayList, поэтому он может содержать что угодно, а тип Globals.PAS здесь не определен.

Возможно, вам следует подумать о другой стратегии: в вашей DLL создайте небольшую модель, которая содержит все, что вам нужно, в вашем коде C, и сделайте ее максимально простой (но не более простой!).

Затем изучите все, что вам нужно, чтобы упорядочить эту модель C из своего управляемого кода, и заполните модель из своего класса Graph.cs. Предпочтительно, Graph.cs не должен нести ответственность за это, ваш код должен быть.

...