How can I derive a vector <int> from a C ++ dll in a C # application?

I have a C ++ function that creates a list of rectangles of interest. I want to get this list from the C ++ library and back to the C # application that calls it.

So far I am coding rectangles as follows:

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

and then coding 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 (and works for many other functions):

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

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

+6
c ++ c # stl marshalling
source share
3 answers

STL is a special library in C ++, so you cannot directly pass it as a single object in C #.

The only thing guaranteed with respect to std :: vector is that & v [0] points to the first element, and all elements lie linearly in memory (in other words, its exactly the same as an array C in terms of memory)

So, a marshal is like an int array ... which doesn't have to be hard - there are many examples on the Internet.

Added

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

C # cannot process a C ++ vector object, so don't try to pass it by reference: instead, your C ++ code should return a pointer to an ints array ...

If you are not going to use this function from several flows, 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, so you are freeing memory in the version.

For simplicity, instead of passing the size of the vector data, just put a sentinel value (for example, say -1) so that the C # code can determine where the data ends.

+3
source share

I am sure you cannot do this. You should be able to translate C ++ code directly to the C # class, so at least you will need to replicate the internal elements of a vector class in order to arrange it correctly. I am also sure that you will not be able to move links across the border, you will have to use IntPtr (raw pointers). The approach that I know works is to march an raw array of structures.

0
source share

Yes. You can. In fact, not only std::vector , std::string , std::wstring , any standard C ++ class or your own classes can be marshaled or created and called from C # /. NET

Wrapping a std::vector<any_type> in C # is really possible with the usual P / Invoke Interop, however it's complicated. even a std::map any type can be made in C # /. NET

 public class SampleClass : IDisposable { [DllImport("YourDll.dll", EntryPoint="ConstructorOfYourClass", CharSet=CharSet.Ansi, CallingConvention=CallingConvention.ThisCall)] public extern static void SampleClassConstructor(IntPtr thisObject); [DllImport("YourDll.dll", EntryPoint="DestructorOfYourClass", CharSet=CharSet.Ansi, CallingConvention=CallingConvention.ThisCall)] public extern static void SampleClassDestructor(IntPtr thisObject); [DllImport("YourDll.dll", EntryPoint="DoSomething", CharSet=CharSet.Ansi, CallingConvention=CallingConvention.ThisCall)] public extern static void DoSomething(IntPtr thisObject); [DllImport("YourDll.dll", EntryPoint="DoSomethingElse", CharSet=CharSet.Ansi, CallingConvention=CallingConvention.ThisCall)] public extern static void DoSomething(IntPtr thisObject, int x); IntPtr ptr; public SampleClass(int sizeOfYourCppClass) { this.ptr = Marshal.AllocHGlobal(sizeOfYourCppClass); SampleClassConstructor(this.ptr); } public void DoSomething() { DoSomething(this.ptr); } public void DoSomethingElse(int x) { DoSomethingElse(this.ptr, x); } public void Dispose() { if (this.ptr != IntPtr.Zero) { // The following 2 calls equals to "delete object" in C++ // Calling the destructor of the C++ class will free the memory allocated by the native c++ class. SampleClassDestructor(this.ptr); // Free the memory allocated from .NET. Marshal.FreeHGlobal(this.ptr); this.ptr = IntPtr.Zero; } } } 

See link below.

C # /. NET PInvoke Interop SDK

(I am the author of the SDK tool)

Once you have the C # wrapper class for your C ++ class, it is easy to implement ICustomMarshaler so that you can marshal a C ++ object from .NET.

http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.icustommarshaler.aspx

0
source share

All Articles