如何从C#中的非托管内存中读取?

时间:2012-08-30 17:30:00

标签: c# c++ interop unmanaged

我想用C ++中创建的Foo结构的非托管数组在C#中创建Foo个对象。 这就是我认为应该如何运作的方式:

在C ++方面:

extern "C" __declspec(dllexport) void* createFooDetector()
{
    return new FooDetector();
}

extern "C" __declspec(dllexport) void releaseFooDetector(void* fooDetector)
{
    FooDetector *fd = (FooDetector*)fooDetector;
    delete fd;
}

extern "C" __declspec(dllexport) int detectFoo(void* fooDetector, Foo **detectedFoos)
{
    FooDetector *fd = (FooDetector*)fooDetector;
    vector<Foo> foos;
    fd->detect(foos);

    int numDetectedFoos = foos.size();
    Foo *fooArr = new Foo[numDetectedFoos];
    for (int i=0; i<numDetectedFoos; ++i)
    {
        fooArr[i] = foos[i];
    }

    detectedFoos = &fooArr;

    return numDetectedFoos;
}

extern "C" __declspec(dllexport) void releaseFooObjects(Foo* fooObjects)
{
    delete [] fooObjects;
}

在C#方面: (我省略了一些花哨的代码,可以在C#中调用C ++函数以提高可读性;)

List<Foo> detectFooObjects()
{
    IntPtr fooDetector = createFooDetector();

    IntPtr detectedFoos = IntPtr.Zero;
    detectFoo(fooDetector, ref detectedFoos);

    // How do I get Foo objects from my IntPtr pointing to an unmanaged array of Foo structs?

    releaseFooObjects(detectedFoos);

    releaseFooDetector(fooDetector);
}

但我不知道如何从IntPtr detectedFoos中检索对象。应该有可能...... 任何提示?

更新

我们假设,Foo是一个简单的检测矩形。

C ++:

struct Foo
{
    int x;
    int y;
    int w;
    int h;
};

C#:

[StructLayout(LayoutKind.Sequential)]
public struct Foo
{
    public int x;
    public int y;
    public int width;
    public int height;
}

是否可以在释放非托管内存之前从非托管内存中读取并从中创建新的托管对象?

我不知道如何检测Foo个对象,所以我不知道,在调用detectFoo()之前,要在C#中分配多少内存。这就是为什么我在C ++中分配/释放内存并只是传递一个指向它的指针。但不知怎的,我无法在C#下检索detectedFoo指针地址。我该怎么做?

3 个答案:

答案 0 :(得分:2)

您必须在C#项目中重新声明Foo。假设您知道Foo的数量和sizeof(Foo)的值,您应该能够使用System.Runtime.Interopservices.Marshal.PtrToStructure()一次检索Foo个结构。

答案 1 :(得分:0)

你必须在C#中再次定义你的结构,这取决于你的结构。您的结构必须是可滑动的(C#struct ave的内存布局与C结构相同)

看看“编组结构”

或发布您真正的“Foo”结构,我可以向您展示C#版本

<强>更新

因为你的struct似乎是blitable,你可以简单地将指向非托管内存的指针转换为指向c#中定义的struct的指针:

如果你的应用程序可以使用不安全的代码,你可以写:

unsafe List<Foo> detectFooObjects()
{
 List<Foo> res = new List<Foo>()
IntPtr fooDetector = createFooDetector();

IntPtr detectedFoos = IntPtr.Zero;
int nNumFoos = detectFoo(fooDetector, ref detectedFoos );
for(int i=0;i<nNumFoos;i++)
{
   Foo** ppDetectedFoos = detectedFoos.ToPointer();

   Foo* pFoo = *ppDetectedFoos
   res.Add(*pFoo); //copies the struct because is a struct
   ppDetectedFoos++:
}

releaseFooObjects(detectedFoos);

releaseFooDetector(fooDetector);
return res;
}

答案 2 :(得分:0)

我最终通过使用C ++ / CLI包装器类解决了我的问题。