39

Title explains. I have native C++ dlls that I'm writing C++/CLI wrappers for, which will in turn will be imported in C# as reference.

The problem is that in C# I don't see the classes I have in wrapper (imported from DLL).

What keywords should I use and HOW to re-declare my native C++ objects to become visible in C#?

Haix64
  • 806
  • 1
  • 13
  • 21
  • Are the wrapper classes public? Declaration should be "public ref class { ... };" – Asik Apr 19 '12 at 07:26
  • I know that. What I'm asking is that is such a thing possible: `public ref class wrapper_class = native_class;`? Are such approaches possible? – Haix64 Apr 19 '12 at 07:43
  • It's not that simple. The wrapper class would host a native_class object and create wrapper methods for all the methods of native_class that you want to expose. The wrapper methods just marshal the parameters and delegate the call to the native_class object. – Asik Apr 19 '12 at 07:46
  • Ok, then what's the simplest solution? The one resulting in least overhead or redirected member function calls? – Haix64 Apr 19 '12 at 08:16
  • If you can somehow expose your class functionality as C functions, then you could use P/Invoke. Otherwise, the C++/CLI wrapper is to way to go. See my answer below for an example. – Asik Apr 19 '12 at 08:23

1 Answers1

81

Ok, tutorial. You have a C++ class NativeClass that you want to expose to C#.

class NativeClass { 
public:
    void Method();
};

1) Create a C++/CLI project. Link to your C++ library and headers.

2) Create a wrapper class that exposes the methods you want. Example:

#include "NativeClass.h"

public ref class NativeClassWrapper {
    NativeClass* m_nativeClass;

public:
    NativeClassWrapper() { m_nativeClass = new NativeClass(); }
    ~NativeClassWrapper() { this->!NativeClassWrapper(); }
    !NativeClassWrapper() { delete m_nativeClass; }
    void Method() {
        m_nativeClass->Method();
    }
};

3) Add a reference to your C++/CLI project in your C# project.

4) Use the wrapper type within a using statement:

using (var nativeObject = new NativeClassWrapper()) {
    nativeObject.Method();
}

The using statement ensures Dispose() is called, which immediately runs the destructor and destroys the native object. You will otherwise have memory leaks and probably will die horribly (not you, the program). Note : The Dispose() method is magically created for you.

Asik
  • 21,506
  • 6
  • 72
  • 131
  • I'm being challenged by dll not found error, but anyway, your method works. Thanks so much! – Haix64 Apr 19 '12 at 08:39
  • i followed this instruction but receive such error "type used in a using statement must be implicitly convertible to 'System.IDisposable'" – Oleg Vazhnev Nov 24 '12 at 13:50
  • 3
    To avoid memory leaks from 4) you should additionally implement finalizer !NativeClassWrapper(); which will be called by garbage collector – VladL Jan 23 '13 at 11:53
  • 1
    This wrapper indeed has avoidable memory leaks. I suggest re-using a smart pointer, for example [this one I wrote](http://codereview.stackexchange.com/q/1695/2150) instead of duplicating, potentially wrongly, the deletion logic in each wrapper class. – Ben Voigt Mar 19 '13 at 17:20
  • Implemented finalizer as suggested. – Asik Sep 04 '13 at 17:05
  • Not sure what I'm doing wrong, but the linker throws errors that the native functions cannot be bound by the wrapper. I wrapped all the native function declarations and code in 'extern "C" { }'. I am using VS 2019. Shouldn't that prevent the name mangling? Errors are unresolved token/external symbol ... ?GetDBServerName@DBAsst@@$$FSA?AV?$CStringT@_WV?$StrTraitMFC_DLL@_WV?$ChTraitsCRT@_W@ATL@@@@@ATL@@PEAD@Z) referenced in function "public: class ATL::CStringT > > __clrcall NativeClassWrapper::GetDBServerName(char *) – pwrgreg007 Jan 13 '23 at 17:32
  • @pwrgreg007 post a new question with as much detail as possible. – Asik Jan 13 '23 at 18:14