在C#和C之间传递对象

时间:2010-02-21 07:41:30

标签: c# c dll struct unmanaged

我的应用程序包含带有非托管C dll调用的C#代码。 在我的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 个答案:

答案 0 :(得分:6)

尝试:

How to: Marshal Structures Using PInvoke

我认为您取得进步的最简单方法是修改本机代码,使其能够使用CLR类型。

现在,您几乎肯定会使用Visual Studio,并且希望它是VS2005或更高版本。这意味着虽然您现有的本机代码在C中,但您可以选择深入研究一点C ++。不仅如此 - 您还拥有C ++ / CLI。

因此,我将创建一个新的C ++ / CLI DLL,并将您的C库链接到它,以便它可以调用C代码。然后在C ++ / CLI库中编写一个精简的转换层:它将公开真正的CLR类(用ref class编写)并将调用本机C代码。

e.g。在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);

答案 1 :(得分:2)

当我这样做时,我只使用了Marshal。这与本机代码的标准C一致。我不想将我的C代码转换为“托管C ++”或他们称之为: - )

困难和乏味的部分是您必须手动将数据结构编组为直接映射到接收C函数的内容。就我而言,我必须为每个带有C#的数据创建单独的结构 - 我要发送的类。本质上,您应该将您的C#对象层次结构转换为更基本的形式,然后将结构组织成一个内存块,然后然后将其用作本机调用中的参数。

您应该使用方法Marshal.AllocHGlobal来分配内存,使用Marshal.StructureToPtr将C#结构复制到该内存,然后使用Marshal.FreeHGlobal来释放它。

一旦你有了IntPtr(来自StructureToPtr),你应该能够简单地用你的指针作为参数调用你的C-dll。请注意,要发送到C函数的结构必须与本机C结构具有相同的布局,否则会得到非常奇怪的结果。

返回数据几乎是一回事,但你正在使用相反的函数(PtrToStructure等)。

无论如何都是它的基础。

答案 2 :(得分:0)

你的模型看起来很复杂,不完整:Tuple.m_parameters是一个ArrayList,所以它几乎可以包含任何内容,而且这里没有定义Globals.PAS类型。

也许您应该考虑一个不同的策略:在您的DLL中,创建一个包含C代码中所需内容的小模型,并使其尽可能简单(但不是更简单!)。

然后,学习从托管代码编组C模型所需的任何内容,并从Graph.cs类中填写模型。最好,Graph.cs不应该对此负责,您的编组代码应该是。