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?
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.
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.
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