如何通过在C#列表创建C ++ DLL对象的地址? [英] How to pass address of objects created in a C# List to C++ dll?

查看:126
本文介绍了如何通过在C#列表创建C ++ DLL对象的地址?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在寻找所有谷歌找到一些答案我的问题,但不太明白我已经找到。我有使用System.IO读一些文本文件后,创建并存储在C#中列出的一些对象。在那之后,我想送引用(使用const的指针)到每个对象在C ++ DLL中的内部类,以便它可以使用它们的一些算法计算。

I have been looking all over google to find some answers to my questions but do not quite understand what I have found. I have some objects which are created and stored in C# List after using System.IO to read some text files. After that, I want to send references (using const pointers) to each of these objects to the internal classes in C++ dll so that it can use them for computation of some algorithms.

下面是一些简单的例子,我在做什么的(而不是实际的代码):

Here are some simple example (not actual code) of what I am doing:

在C#类:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class SimpleClass
{
    [MarshalAs(UnmanagedType.LPStr)]
    public string           Name;
    public float            Length;
}



与相应的C结构:

with corresponding C struct:

struct SimpleClass
{
    const char* Name;
    float Length;
};



存储

stored in

List<SimpleClass> ItemList;



解析一些文本文件后。

after parsing some text files.

然后调用下面的DLL函数:

Then calling the following dll function:

C#:

[DllImport("SimpleDLL")]
public static extern void AddSimpleReference(SimpleClass inSimple);



C:

C:

void AddSimpleReference(const SimpleClass* inSimple)
{
   g_Vector.push_back(inSimple); // g_Vector is a std::vector<const SimpleClass* > type
}



我曾尝试为:

What I have tried is:

for(int i=0; i<ItemList.Count;++i)
{
    SimpleClass theSimpleItem = ItemList[i];
    AddSimpleReference(theSimpleItem);
}



起初,我认为这将是很容易得到一个实际参考/地址只是通过使用赋值运算符,因为在C#类通过按参考,但事实证明,C ++类总是推着相同的地址值(临时参考的地址值)放入容器,而不是实际的地址。我如何得到实际的对象地址,并将其发送到C ++ DLL,以便它可以具有只读到C#对象的访问?

Initially, I thought it would be easy to get a actual reference/address just by using the assignment operator since classes in C# are passed-by-reference but it turns out that the C++ class is always pushing the same address value (the address value of the temp reference) into the container instead of the actual address. How do I get the actual object addresses and send it to C++ DLL so that it can have read-only access to the C# objects?

更新:对不起那些谁贴有不安全的代码的答案。我忘了提及的是,C#代码实际上是作为在Unity游戏引擎的脚本不允许使用不安全的代码。

UPDATE: Sorry to those who posted answers with unsafe codes. I forgot to mention that the C# code is actually used as a script in Unity game engine which does not allow the use of unsafe codes.

推荐答案

首先,你需要改变你的互操作签名采取指针(从而使其不安全)。

First you need to change your interop signature to take a pointer (and thus making it unsafe).

[DllImport("SimpleDLL")]
public unsafe static extern void AddSimpleReference(SimpleClass* inSimple);



然后,因为GC可以自由地在内存中移动对象,因为它为所欲为,你将需要钉住对象在内存中的全部的时候就需要你对非托管方地址。对于您所需要的固定语句:

Then, because the GC is free to move objects around in memory as it pleases, you will need to pin the object in memory for the entire time you will need its address on the unmanaged side. For that you need the fixed statement:

SimpleClass theSimpleItem = ItemList[i];
unsafe
{
    fixed(SimpleClass* ptr = &theSimpleItem)
    {
        AddSimpleReference(ptr);
    }
}

这会工作,如果 AddSimpleReference 使用的指针,然后丢弃它。但是你存储在的std ::矢量供以后的指针。一旦执行离开固定块这是行不通的,因为该指针将可能变得无效由于GC移动原始项其他地方。

This would work if AddSimpleReference used the pointer and then discarded it. But you're storing the pointer in a std::vector for later. That won't work, because the pointer will probably become invalid due to the GC moving the original item somewhere else once execution leaves the fixed block.

要解决这个问题,你需要针的物品,直到你与他们完成。要做到这一点,你可能需要求助于 的GCHandle 类型。

To solve this, you need to pin the items until you are done with them. To do this you may need to resort to the GCHandle type.

// Change the interop signature, use IntPtr instead (no "unsafe" modifier)
[DllImport("SimpleDLL")]
public static extern void AddSimpleReference(IntPtr inSimple);

// ----
for(int i=0; i<ItemList.Count;++i)
{
    SimpleClass theSimpleItem = ItemList[i];
    // take a pinned handle before passing the item down.
    GCHandle handle = GCHandle.Alloc(theSimpleItem, GCHandleType.Pinned);
    AddSimpleReference(GCHandle.ToIntPtr(handle));
    // probably a good idea save this handle somewhere for later release
}

// ----
// when you're done, don't forget to ensure the handle is freed
// probably in a Dispose method, or a finally block somewhere appropriate
GCHandle.Free(handle);

在做这样的事情,请记住,寄托在内存中的对象很长一段时间是一个坏的想法,因为它可以防止垃圾回收器高效地做其工作。

When doing something like this, keep in mind that pinning objects in memory for a long time is a bad idea, because it prevents the garbage collector from doing its job efficiently.

这篇关于如何通过在C#列表创建C ++ DLL对象的地址?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆