Because once in a while I write a C++/CLI wrapper around a C library, but since I do it so infrequently I forget everything each time. Here is a list of pointers (haha) for common pitfalls and problems.
Compiling and debugging
You have to wrap the .h into an #ifdef __cplusplus extern “C” :
1 2 3 4 5 6 7 8 9 |
#ifdef __cplusplus extern "C" { #endif // contents of the .h file #ifdef __cplusplus } #endif |
You also need to remove the /clr option for C files.
Right click your C files > Properties > C/C++ > General > Common Language RunTime Support > No CLR Support.
In your managed class, to include an unmanaged C header, use managed(push|pop)
1 2 3 |
#pragma managed(push, off) #include "../../map_packer/packer.h" #pragma managed(pop) |
Because Linux and Windows get along so well, you may also have to redefine a few C methods in your header file.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
// Only for Visual C++ #ifdef _MSC_VER // The Visual C++ compiler doesn't know "inline" but knows "__inline". // see: stackoverflow.com/a/24435157/2354542 #define inline __inline // Visual C++ is not POSIX compliant :'( so I have to code a new random() method // rand() is not safe for security ; see: https://www.securecoding.cert.org/confluence/display/seccode/MSC30-C.+Do+not+use+the+rand%28%29+function+for+generating+pseudorandom+numbers // but there is no security concern in my library, so I don't care much inline long int random() { return rand(); } #endif |
If you wish to create a C# unit test project (using xUnit for instance), with Visual Studio 2012 and later, you will have to do a few things:
- In the C++/CLI project’s properties, in Debugging, choose the Debugger Type “Mixed”
- In the Visual Studio options, Debugging, check “Managed C++ Compatibility Mode” (in VS2012) / “Use Managed Compatibility Mode” (in VS2013).
To build using MSBuild, you may have to change the toolset to VS2012: project properties > General > Platform Toolset = Visual Studio 2012 (v110). And set the Configuration Type to Dynamic Library (.dll) while you’re at it.
Managed and unmanaged objects
gcnew instantiates a managed objects, which will be garbage collected. Always use it for the managed objects.
To easily call the native structures through managed classes, use the internal constructor and ToNative methods.