Share via


Calling a C++ Class Constructor from a DLL

Question

Thursday, April 16, 2009 2:00 PM

Hi, 

i've defined a C++ dll and exported all its symbols. The DLL code is the following:

### myDll.h 

class MyClass {

public:

  MyClass(int val, chat val2);

 bool MyClassFunc(int val);

}

### myDll.cpp

MyClass::MyClass (int val, chat val2){

    //Something ....

}

bool MyClass::MyClassFunc(int val){

   //Something....

   return true;

}

I compile the C++ code and i generate the myDll.dll and the myDll.lib files, exporting all (defined) symbols of the myDll.obj file ( cygwin: nm -g myDll.obj ). 

Now how can a use this class into my executable ??

I load the dll and i get the procedure using the windows functions. I assign the constructor pointer retrived from the dll to a function pointer defined into the executable program, but i can not call the new on this function ....

##Executable

typedef void (*ctrPointer)(int val, chat val2);

ctrPointer myCtrPointer;

HINSTANCE myDll = LoadLibrary("myDll.dll");

myCtrPointer = (ctrPointer )GetProcAddress(myDll,"#####@@@@ Exported Symbol Name @@@@#####");

new myCtrPointer (1,'A'); < ERROR

Which is the way to call a class constructor defined into a Dll and allocate the created object into the heap ?

All replies (7)

Thursday, April 16, 2009 4:56 PM ✅Answered

Be aware that exporting classes is generally a bad idea. Let me repeat: generally speaking exporting classes is a Really Bad Idea. More often than not, the client code and the DLL must be built using the identical compiler version and identical compiler switches, which typically defeats the purpose of creating a DLL in the first place.


Thursday, April 16, 2009 6:54 PM ✅Answered

Be aware that exporting classes is generally a bad idea. Let me repeat: generally speaking exporting classes is a Really Bad Idea . More often than not, the client code and the DLL must be built using the identical compiler version and identical compiler switches, which typically defeats the purpose of creating a DLL in the first place.

I agree. But if you use PaulH's method to export an interface only, then it will work well:

__declspec( dllexport ) MyInterface* Create()
{
    return new CMyClass();
}

__declspec( dllexport ) void Destroy( MyInterface* pC )
{
    delete (CMyClass*)pC;
};

where CMyClass derives from MyInterface (which should be pure interface -- all virtual functions, with no constructor or destructor). The concrete class CMyClass is defined in the DLL, and is not known to the client.

The above is essentially what COM does.


David Wilkinson | Visual C++ MVP


Thursday, April 16, 2009 9:02 PM ✅Answered

I feel compelled to offer that MyInterface could contain a virtual destroy method

struct MyInterface
{
   virtual void method() = 0;
   // ... etc.

   virtual void Destroy() = 0;
};

struct MyClass : public MyInterface
{
   void method() {}

   void Destroy() {
       delete this; return;
   }
};

then instead of delete foo you call foo->Destroy() ;

This is how COM's AddRef() and Release() work.

And you only have to export one function...the Create() function, that returns a pointer to the interface.

I also disagree with c-style casting a MyInterface* to a CMyClass*.


Thursday, April 16, 2009 3:13 PM

In your DLL, export a function that is not part of the class like this:

__declspec( dllexport ) CMyClass* Create()
{
    return new CMyClass();
}

__declspec( dllexport ) void Destroy( CMyClass* pC )
{
    delete pC;
    pC = NULL;
};

Then, do your GetProcAddress() on "Create()" and "Destroy()".
CMyClass* myClass = myCtrPointer->Create();
...
myCtrPointer->Destroy( myClass );

-PaulH


Thursday, April 16, 2009 8:19 PM

__declspec( dllexport ) MyInterface* Create()
{
    return new CMyClass();
}

__declspec( dllexport ) void Destroy( MyInterface* pC )
{
    delete (CMyClass*)pC;
};

Oops. Yes.
Alexander - Do this. Not what I posted.

-PaulH


Thursday, April 16, 2009 9:42 PM

I feel compelled to offer that MyInterface could contain a virtual destroy method

If you are going to do that, I think you could also make the destructor private, which would ensure you don't accidentally leak the memory allocated by Create().

struct MyInterface
{
   virtual void method() = 0;
   // ... etc.

   virtual void Destroy() = 0;

private:
    virtual ~MyInterface() = 0;
};

-PaulH


Friday, April 17, 2009 10:27 AM | 1 vote

Wyck:

Yes, you can do it that way also. A real virtual destructor will work also I think, though it is not necessary because the type of the argument to my form of the Destroy() mechanism should always be CMyClass*, so you can use a cast. Yes, a static cast, or even a dynamic_cast with sanity check would be better.

The important thing is to present only the interface to the client, to achieve compiler-independence.David Wilkinson | Visual C++ MVP