【问题标题】:Passing objects between C# and C在 C# 和 C 之间传递对象
【发布时间】:2010-02-21 07:41:29
【问题描述】:

我的应用程序由带有非托管 C dll 调用的 C# 代码组成。 在我的 C# 代码中,我有一个对象/类,其中它的属性都是系统类型,例如字符串和 int 以及我定义的其他对象。

我想将这个复杂的 (Graph.cs) 对象传递给我的 C (dll) 代码,你会在这里建议什么实现?

我尝试过移动结构,但除了字符串和 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;

}

【问题讨论】:

  • 您需要提供您的代码,以便人们可以提供建议。
  • 我已经添加了代码,是否可以将 Graph 对象发送到 C dll?

标签: c# c dll struct unmanaged


【解决方案1】:

试试:

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 代码。

例如在 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);

【讨论】:

  • 谢谢,在这个例子中,他们只使用简单的数据类型,比如我可以处理的 int,C# List 数据类型怎么样?或 ListArray。
  • 您无法处理来自非托管代码的托管结构。您需要将这些结构转换为非托管结构并传递它们。这个答案是我在这里看到的最有效的答案。
  • 是的,这会起作用,但请记住,您仍然必须在某处将对象转换为普通的旧 C 结构。你的例子很简单,但在一个不平凡的情况下,我真的可以说它在 C++ 中是否比直接在 C# 中更容易。不过,这两种情况下的摆弄似乎差不多,但您不必在 C#->C 方法中涉及另一种语言。
  • 在 C#->C 中,您实际上必须用另一种语言编写:互操作属性。我发现 C++/CLI 层的主要优点是您可以在调试器中单步执行它,因此您可以从字面上看到正在发生的转换并立即找出问题所在。使用互操作,如果你知道要写什么,它很简短,但问题是要弄清楚要写什么。
【解决方案2】:

当我这样做时,我只使用了Marshal。这是本机代码的标准 C 语言。我不想将我的 C 代码转换为“托管 C++”或他们所说的任何东西:-)

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

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

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

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

这就是它的基本原理。

【讨论】:

  • +1 不确定我在实践中是否真的喜欢这种声音,但它仍然很有趣。
  • 嘿,谢谢。但除非您想移植现有的本机代码或编写 C++ 包装器,否则就 所知,这是唯一的出路。
  • 纯 C、纯 C++、混合 C 和 C++ 对我来说都可以。我只是不喜欢 C++ 的托管版本。
【解决方案3】:

您的模型看起来相当复杂且不完整:Tuple.m_parameters 是一个 ArrayList,因此它几乎可以包含任何内容,并且此处未定义 Globals.PAS 类型。

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

然后,从托管代码中了解编组该 C 模型所需的任何内容,并从 Graph.cs 类中填写模型。最好,Graph.cs 不应该负责执行此操作,您的编组代码应该负责。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-04-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多