Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I read from unmanaged memory in C#?

I'd like to create Foo objects in C# from an unmanaged array of Foo structs created in C++. This is how I think it should work:

On the C++ side:

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

On C# side: (I ommitted some fancy code making it possible to call the C++ functions from within C# for better readability);

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

But I don't know how to retrieve the objects from the IntPtr detectedFoos. It should be possible somehow... Any hints?

UPDATE

Let's assume, Foo is a simple detection rectangle.

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

Is it possible to read from unmanaged memory and create new managed objects from it before releasing the unmanaged memory?

I don't know how may Foo objects will be detected, so I don't know, how much memory to allocate in C# before calling detectFoo(). That's why I alloc/free memory in C++ and just pass a pointer to it. But somehow I can't retrieve the detectedFoos pointer address under C#. How do I do that?

like image 715
Ben Avatar asked Nov 04 '22 17:11

Ben


1 Answers

You must re-declare Foo in your C# project. Assuming you know the count of Foos and the value of sizeof(Foo) you should be able to use System.Runtime.Interopservices.Marshal.PtrToStructure() to retrieve your Foo structures one at a time.

like image 186
pdriegen Avatar answered Nov 09 '22 21:11

pdriegen