From: Hans-Jochen T. <hj...@tx...> - 2012-05-16 20:18:46
|
All, here is a summary of work that Pierre Martin and I did to establish a working prototype that will allow multiple instantiations of a class exported from a DLL. Some portion of this was visible on the list, and some was not. The fundamental factory function method for accessing the class is maintained. Pierre established that this still needs to be accompanied by dllexport/dllimport qualifications for the abstract interface class, the main class to be exported, and the factory functions themselves. My fixed-up demo, cut even more to the bare bones than my original post, is included in the message text below so as to have the final result archived in a convenient place. I apologize for the length of the message caused by this. Pierre's original fixed-up version at pastebin.com may remain for some time and it works just as well. We have tested this strategy with MinGW 4.4.0 as well as another recent development version. The code can be used essentially unchanged in VC++6 as well (and thus probably throughout the VC++ line of computers), with only the name of the DLL and the decorated names of the factory functions in the module definition file to be adjusted. (I prefer this compiler dependence to be in the module definition file rather than the source of the calling program). If I add a second class in the DLL that gets used by the primary exported class but not outside the DLL, that second class does not need to be exported. The ground rules thus are: Use an abstract interface class (called TestInterface in the demo). Use factory functions to create and delete instances of the real class. Decorate the definitions of the interface class and the real class with __declspec(dllimport/dllexport). Decorate the prototypes of the factory functions with __declspec(dllimport/dllexport). The calling program only needs to see the interface class directly. I hope this is helpful to other people. Thanks a lot again to Pierre for coming up with the missing elements. Cheers, Jochen =====DLL=include=file=testdll.h===== #ifdef MY_COMPILE_DLL #define MY_DECLSPEC __declspec(dllexport) #else #define MY_DECLSPEC __declspec(dllimport) #endif class MY_DECLSPEC TestInterface { public: TestInterface() ; virtual ~TestInterface() = 0 ; virtual bool Get(bool &flag, int &num) = 0 ; } ; typedef TestInterface* (*newtestdlltype)(const bool, const int) ; typedef void (*deletetestdlltype)(TestInterface *) ; TestInterface* MY_DECLSPEC newtestdll(const bool, const int) ; void MY_DECLSPEC deletetestdll(TestInterface*) ; =====end=of=file===== =====DLL=module=definition=testdll.def===== EXPORTS newtestdll = _Z10newtestdllbi deletetestdll = _Z13deletetestdllP13TestInterface =====end=of=file===== =====DLL=class=source=testdll.cpp===== #define MY_COMPILE_DLL #include "testdll.h" TestInterface::TestInterface() { } TestInterface::~TestInterface() { } class MY_DECLSPEC Test : public TestInterface { public: Test(const bool, const int) ; virtual ~Test(); virtual bool Get(bool &flag, int &num); private: bool f_flag ; int f_num ; char f_text80[80] ; }; Test::Test(const bool flag, const int num) : TestInterface(), f_flag(flag), f_num(num) { } Test::~Test() { } bool Test::Get(bool &flag, int &num) { flag = f_flag ; num = f_num ; return true ; } TestInterface* newtestdll(const bool flag, const int num) { return new Test(flag, num); } void deletetestdll(TestInterface *f) { delete f; } =====end=of=file===== =====Main=Program===== #include "testdll.h" int main(void) { bool bb ; int i, ii, numinstances=4 ; HMODULE testdll = LoadLibrary("libtestdll.dll") ; newtestdlltype ffunc_newtestdll = (newtestdlltype)GetProcAddress(testdll, "newtestdll") ; deletetestdlltype ffunc_deletetestdll = (deletetestdlltype)GetProcAddress(testdll, "deletetestdll") ; TestInterface **ftest = NULL ; ftest = new TestInterface*[numinstances] ; for (i=0; i<numinstances; i++) { ftest[i] = ffunc_newtestdll(i%2==0, i) ; ftest[i]->Get(bb, ii) ; } for (i=0; i<numinstances; i++) { ffunc_deletetestdll(ftest[i]) ; ftest[i] = NULL ; } delete [] ftest ; FreeLibrary(testdll) ; return 1 ; } =====end=of=file===== |