2

I have written an C++/Cli wrapper for a native C++ dll, but when I call some method from C# I get an System.AccessViolationException error in my C++/Cli Wrapper dll! It's necessary to marshal the unmanaged types or something else?!

// Wrapper.h

typedef UnmanagedClass* (*Instance)(void);

private:
    UnmanagedClass *m_object; // unmanaged object   

// Wrapper.cpp

Wrapper:Wrapper()
{
    HINSTANCE unmanagedLib;
    unmangedLib = LoadLibrary(SystemStringToLPCSTR(dllPath+dllName));

    // load instance
    Instance _createInstance = (Instance)GetProcAddress(unmangedLib, "GetInstance");
    m_object = (_createInstance)(); 
}

Wrapper::~Wrapper()
{
    m_object->~UnmanagedClass();
}


Uint32 Wrapper::SomeMethod(Uint8 *bytRecvBuffer, int &iRecvLen)
{
    return m_object->SomeMethod(bytRecvBuffer, iRecvLen);
}

// Unmanaged Class

class UnmanagedClass    
{
public:
    /**
    * Default constructor. 
    */
    UnmanagedClass(void);
    /**
    * Default Destructor
    */
    ~UnmanagedClass(void);

    virtual Uint32 Wrapper::SomeMethod(Uint8 *bytRecvBuffer, int &iRecvLen);
};

// export the UnmanagedClass object
extern "C" _declspec(dllexport) UnmanagedClass* GetInstance();

// UnamangedClass.cpp

UnamangedClass::~UnamangedClass(void)
{
    if (UnamangedClassDLL != NULL)
        FreeLibrary(UnamangedClassDLL);

    UnamangedClassDLL = NULL;
}

extern "C" _declspec(dllexport) UnmanagedClass* GetInstance()
{

    return new UnmanagedClass();
}

When I call at example SomeMethod from C# I get the error in C++/Cli dll! (I included the C++/cli dll with add reference in C sharp project and create the Wrapper object)

Thank you for your help!

greets

leon22
  • 5,280
  • 19
  • 62
  • 100
  • `It's necessary to marshal the unmanaged types or something else?` How can we possibly know when you don't show the definitions of `UnmanagedClass` or `Wrapper`? (BTW, `m_object->~UnmanagedClass();` looks absolutely wrong.) – ildjarn May 26 '11 at 08:02
  • I don't think this is wrong (read it here http://ondotnet.com/lpt/a/4731 -> I write the wrapper with this tutorial) – leon22 May 26 '11 at 08:04
  • @leon22 : Again, we can't know that for sure since we can't see the definitions of `UnmanagedClass` and `Wrapper`. – ildjarn May 26 '11 at 08:06
  • You see the definitions of Wrapper class – leon22 May 26 '11 at 08:08
  • @leon22 : What is the implementation of `GetInstance`? Specifically, how does it allocate and construct an `UnmanagedClass` instance in a manner that you would think it appropriate to call its destructor directly and then not actually deallocate any memory? – ildjarn May 26 '11 at 08:12
  • @leon22 : Yes, thank you, but not enough just yet. :-] What is the implementation of `GetInstance`? – ildjarn May 26 '11 at 08:13
  • I thought you will ask (now I added it) ;-) – leon22 May 26 '11 at 08:16
  • Dont this access violetion exception has an InnerException? Is your .dll is in some loadable location? If it is custom dll try to put it to the execution directory. – MajesticRa May 26 '11 at 08:28
  • @MajesticRa: I have checked this (the dll will loaded normally) – leon22 May 26 '11 at 08:44

2 Answers2

2

It is inappropriate to directly call the destructor of an object that was allocated with (non-placement) new. Try changing

m_object->~UnmanagedClass();

to

delete m_object;
m_object = 0;

(m_object = 0; is necessary because unlike a native C++ type's destructor, which may only be called once, an managed type's Dispose implementation may be called repeatedly, and doing so must have defined behavior.)

Or, better yet, in addition to exposing a GetInstance function, also expose a DestroyInstance function and call that instead of using delete so that consuming code does not need to depend on the implementation details of GetInstance (i.e., that it allocates its instance using operator new).

ildjarn
  • 62,044
  • 9
  • 127
  • 211
  • Thank you, but why I will get an System.AccessViolationException exception when calling a method? – leon22 May 26 '11 at 08:23
  • @leon22 : See if making the change helps before I type out the response to that. ;-] – ildjarn May 26 '11 at 08:25
  • I don't think so, because I don't call the destructor: m_object->SomeMethod() (but you are right its a better way to destruct the object) – leon22 May 26 '11 at 08:37
  • OK. As I supposed nothing changed! Any other suggestions?! – leon22 May 26 '11 at 08:42
  • Have nobody an other suggestion?! Thanks – leon22 May 26 '11 at 08:59
  • Ok I have tested it with an easy method (double DoDouble(double number) and it works! At this point I think I must marshal the parameters of SomeMethod (Uint8 *bytRecvBuffer and int &iRecvLen)?! How can I do it in my C++/Cli dll??? Thanks and greets – leon22 May 26 '11 at 09:30
  • @leon22 : I can only answer that concretely if you show the implementation of `UnmanagedClass::SomeMethod`, especially if/how it allocates memory. – ildjarn May 26 '11 at 09:34
  • Ok. An other point: it's possible in VS 2008 to debug also to the unmanaged dll (to see where the error occurs). At the moment I added only an reference in my C sharp project to the managed C++/Cli dll! – leon22 May 26 '11 at 11:11
0

I have found the error (System.AccessViolationException):

I'm using an other object in the unmanaged code without initialization (null object -> only declared)!

Init the object with new() and all should run properly!

leon22
  • 5,280
  • 19
  • 62
  • 100