在 C# 和 C 之间传递对象

发布于 2024-08-21 23:32:46 字数 867 浏览 2 评论 0原文

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

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

我尝试过移动结构,但无法使用除字符串和整数之外的任何其他结构。

谢谢。

代码:

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;

}

My application consist of C# code with unmanaged C dll calls.
In my C# code I have an object/class where its properties are both system types such as string and int and other objects I have defined.

I would like to pass this complex (Graph.cs) object to my C (dll) code, what implementation would you suggest here?

I have tried moving structs but I fail to do so with anything other then string and int.

Thanks.

Code:

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;

}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

失而复得 2024-08-28 23:32:46

尝试:

如何:使用 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);

Try:

How to: Marshal Structures Using PInvoke

I think the easiest way for you to make progress is to modify the native code, giving it the ability to work with CLR types.

Now, you're almost certainly using Visual Studio, and hopefully it's VS2005 or later. This means that although your existing native code is in C, you have the option to delve into a little C++. And not only that - you also have C++/CLI.

So I would make a new C++/CLI DLL, and link your C library to it, so that it can call into the C code. Then write a thin translation layer in the C++/CLI library: it will expose true CLR classes (written with ref class) and will call onto the native C code.

e.g. in a C header:

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

In 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);
    }
};

In 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);
漫漫岁月 2024-08-28 23:32:46

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

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

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

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

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

无论如何,这就是它的基本原理。

When I did this I used Marshal exclusively. This was with standard C for the native code. I did not want to convert my C code to "managed C++" or whatever they call it :-)

The hard and tedious part is that you have to manually marshal your data structure into something that maps directly to the receiving C function. In my case, I had to create separate structs for each data bearing C#-class I wanted to send. In essence, you should convert your nice C# object hierarchy into a more basic form consisting of structs which you then marshal into a memory chunk which you then use as an argument in your native call.

You should use the method Marshal.AllocHGlobal for allocing memory and Marshal.StructureToPtr for copying your C# struct to that memory and then Marshal.FreeHGlobal to free it.

Once you have your IntPtr (from StructureToPtr), you should be able to simply call your C-dll with that pointer as argument. Note that the struct you are sending to your C function must have the same layout as the native C struct, or you will get very odd results.

Returning data is pretty much the same thing, but you are using the opposite functions (PtrToStructure etc) instead.

Thats the basic of it anyway.

南风几经秋 2024-08-28 23:32:46

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

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

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

Your model looks pretty complicated, and incomplete: Tuple.m_parameters is an ArrayList, so it can contain just about anything, and the Globals.PAS type is not defined here.

Perhaps you should think of a different strategy: in your DLL, make a small model that contains whatever you need in your C code, and make it as simple as possible (but not simpler!).

Then, learn whatever you need to marshal that C model from your managed code, and fill in the model from your Graph.cs class. Preferably, Graph.cs shouldn't be responsible to do this, your marshalling code should be.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文