views:

296

answers:

2

I have a C++ function that produces a list of rectangles that are interesting. I want to be able to get that list out of the C++ library and back into the C# application that is calling it.

So far, I'm encoding the rectangles like so:

struct ImagePatch{ 
   int xmin, xmax, ymin, ymax;
}

and then encoding some vectors:

void MyFunc(..., std::vector<int>& rectanglePoints){
   std::vector<ImagePatch> patches; //this is filled with rectangles
   for(i = 0; i < patches.size(); i++){
       rectanglePoints.push_back(patches[i].xmin);
       rectanglePoints.push_back(patches[i].xmax);
       rectanglePoints.push_back(patches[i].ymin);
       rectanglePoints.push_back(patches[i].ymax);
   }
}

The header for interacting with C# looks like (and works for a bunch of other functions):

extern "C" {
    __declspec(dllexport) void __cdecl MyFunc(..., std::vector<int>& rectanglePoints);
}

Are there some keywords or other things I can do to get that set of rectangles out? I found this article for marshalling objects in C#, but it seems way too complicated and way too underexplained. Is a vector of integers the right way to do this, or is there some other trick or approach?

+1  A: 

I'm pretty sure you can't do this. You have to be able to translate the C++ code directly to a C# class, so you would at least have to replicate the internals of the vector class to marshall it correctly. I'm also pretty sure you won't be able to move references across the boundary, you'll have to use IntPtr (raw pointers). The approach that i know works is to marshall a raw array of the structs.

Steve
mmr
Also note that C++ objects like vector should not cross a module boundary - there is no guarantee that different DLL's or exe's use the exact same version of the STL.
Michael
Then how do I get a bunch of ints (the exact amount of which I don't know) back into C#?
mmr
+1  A: 

The STL is a C++ specific library, so you cant directly get it across as one object to C#.

The one thing that is guaranteed about std::vector is that &v[0] points to the first element and all the elements lie linearly in memory (in other words, its just like a C array in terms of memory layout)

So marshal as array of int... which shouldn't be hard - There are lot of examples on the web.

Added

Assuming you only pass the data from C++ to C# :

C# cannot handle a C++ vector object, so do not try passing it by reference : Instead your C++ code must return a pointer to an array of ints...

If you are not going to be using this function from multiple threads, you can use static storage :

int *getRects(bool bClear)
{
    static vector<int> v; // This variable persists across invocations
    if(bClear)
    {
        v.swap(vector<int>());
    }
    else
    {
        v.clear();
        // Fill v with data as you wish
    }

    return v.size() ? &v[0] : NULL;
}

call getRects(true) if the returned data is significant in size, so you release the memory in v.

For simplicity, instead of passing out the size of the vector data too, just put a sentinel value at the end (like say -1) so the C# code can detect where the data ends.

rep_movsd
But how would that work? If I marshal as an array, how does the array grow on the C++ side by push-back? That memory hasn't been allocated, so any element beyond the first one fails. If I preallocate the array on the C# side, then I might as well use an array rather than a vector, and could be bad if I have lots of rectangles.
mmr
See edit and code above...
rep_movsd