Archived

This topic is now archived and is closed to further replies.

DLL's and inheritence

This topic is 6112 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I''d like to create a factory of sorts where the concrete implementations are located in DLL''s. (psudo)_ class CRenderer static CRenderer* CreateObject(type) in Renderer.cpp CRenderer* CRenderer::CreateObject(type) { switch(types) OPENGL LoadLibrary addr = GetprocAddress return new addr DIRECT3D PS : the DLL has a class called CRenderer that COpenGLRenderer inherits from. ~well something like that... The goal is to only load the renderer that will be used. I''m not sure however about how to dpo a getprocaddress on a class. I''ve worked with functions. Are classes any different. Is this even possible? I''ve VERY light on DLL experience, I''ve just finished the whole MSDN chapter on the subject but that didn''t help. Any pointers? Tutorial or sample you could point out? Many thanks Chris

Share this post


Link to post
Share on other sites
Make an abstract base class to specify the interface, and place that header in both the EXE and any DLLs you wish to make. For each DLL, derive from the abstract base class, and implement the methods.

Place the following code in each DLL, using the same name and format:


extern "C" {
base* allocate() { return new derived; }
deallocate(base* p) { delete p; }
};


Then at run-time, load the DLL of choice using LoadLibrary/FreeLibrary, and call those two functions from the DLL using GetProcAddress. (You''ll have to cast the return value of GetProcAddress to the proper function pointer type.) Those methods manage an instance of the derived class which you can then use via the abstract base w/ virtual functions.

Example:


typedef base* (* allocate_type)();
typedef void (* deallocate_type)(base*);

// Load the DLL into memory
HMODULE hDLL = LoadLibrary("Sample");

// Manually link the functions
allocate_type allocate = reinterpret_cast<allocate_type>(GetProcAddress(hDLL, "allocate"));
deallocate_type deallocate = reinterpret_cast<deallocate_type>(GetProcAddress(hDLL, "deallocate");

// Create an instance of some unknown derived class
base* p = allocate();
p->function1();
p->function2();
deallocate(p);
p = 0;

// Unlink the functions
allocate = 0;
deallocate = 0;

// Unload the DLL
FreeLibrary(hDLL);


That''s all there is to it... I have wrapped all the messy Windows code and casting inside a class just to make the code cleaner.

Good Luck,
- null_pointer

Share this post


Link to post
Share on other sites
Thanks all, this looks good, the base of this system I already have in place (the class defined in the exe\dll then derived from in the dll.

I wouldn''t be able to use com as the engine is geared towards platform independence.

Thanks

Chris

Share this post


Link to post
Share on other sites
Thanks all. I have used HawkNL and SDL until recently and they are both libraries that are crossplatform so my term DLL was just to refer to whatever they do on other platforms.

In the past I was a middleware VB programmer who used COM\DCOM\MTS\MSMQ\ADSI so the thought of using something COM like is appealing, however the one part of COM that sucked was all that registry crap. I would have preferred just using COM DLL''s like normal DLL without having to have the registry aware of the physical location of the library. Since VB however I''ve never used anything COM like, just straight monolithic code OR static\load time linked libraries''s.

I''ll have a read around and see if I can come up with some kind of simple COM like interface.

Thanks again.

Share this post


Link to post
Share on other sites
Bing!

I get it now. You practically handed it to me on a platter and I didn''t see it. I''ll go give this a try now.

Thanks again guys

cb

Share this post


Link to post
Share on other sites
Ok, guys I think I''m close,

I''ve read the tutorial suggested and null_pointers''s code sample. The code seems almost compilable. I have some problems with the Class I''l importing which I''m not sure are my of this new codes fault(simple due to the fact that I''ve never gotten this code to compile anyway).

Here are the problems:

1) warning C4273: ''CNULLRenderer::CNULLRenderer'' : inconsistent dll linkage. dllexport assumed.
This occurs on every function that has an implementation in the DLL file.

2) NULL Renderer.obj : error LNK2001: unresolved external symbol "__declspec(dllimport) const CNULLRenderer::`vftable''" (__imp_??_7CNULLRenderer@@6B@)
Strangely however a similar message appears when I have no default constructor define in the base or derived class:
NULL Renderer.obj : error LNK2001: unresolved external symbol "__declspec(dllimport) public: __thiscall CNULLRenderer::CNULLRenderer(void)" (__imp_??0CNULLRenderer@@QAE@XZ)


Following is some source that should be relevent:
  
////////////////////////////////////////Interface.h Defines a base class object for all objects created in DLL''s

class IInterface
{
};

typedef IInterface* (* allocate_type)();
typedef void (* deallocate_type)(IInterface*);


////////////////////////////////////////Renderer.h This file is included in each renderer implementation DLL

class CRenderer : public IInterface
{
public:
...
}
/////////////////////////////////////////NULLRenderer.h This is a DLL''s include file.

#ifdef EXPORT
#define EXPORT __declspec(dllexport)
#else
#define EXPORT __declspec(dllimport)
#endif

#pragma warning (disable:4275) //An exported class was derived from a class that was not exported.


#include "Renderer.h"

class EXPORT CNULLRenderer : public CRenderer
{
public:


const bool Create(void);
const bool Destroy(void);

};


extern "C"
{
IInterface* allocate() { return new CNULLRenderer; }
void deallocate(IInterface* p) { delete p; }
};

///////////////////////////////////////Library.h This file wraps library loading \ class access. For simplicity each DLL will only have master 1 class derived from IInterface

class CLibrary
{
public:

CLibrary();
~CLibrary();

IInterface* Load(const char* a_LibraryName);
void Unload(void);

private:

void* m_LibraryHandle;
IInterface* m_InterfaceClass;

};



If someone is willing to help and this is not enough information to go on I''m happy to mail the file, zipped they should only be a few K

Thanks

Chris

Share this post


Link to post
Share on other sites
(Look up "__declspec(dllexport)" in the MSDN docs, they explain it much better than I can. )

In your case, use __declspec(dllexport) in the DLL. This will create the export symbol table so GetProcAddress can find the function pointers from the names. Your EXE should not include headers or .lib files from the DLLs because you want to link them manually.

Here''s a sample I created to test this out.

In the Win32 Console Application:


// Dynamic Linking.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include
#include

class base { public: virtual void function() = 0; };

typedef base* (* allocate_type)();
typedef void (* deallocate_type)(base*);

int main(int argc, char* argv[])
{
HMODULE hDLL = LoadLibrary("Example");

allocate_type allocate = reinterpret_cast<allocate_type>(GetProcAddress(hDLL, "allocate"));
deallocate_type deallocate = reinterpret_cast<deallocate_type>(GetProcAddress(hDLL, "deallocate"));

base* p = allocate();
p->function();
deallocate(p);

FreeLibrary(hDLL);
return 0;
}



In the Win32 DLL:


// Example.cpp : Defines the entry point for the DLL application.
//

#include "stdafx.h"
#include

class base { public: virtual void function() = 0; };
class derived : public base { public: virtual void function() { std::cout << "derived function called"; } };

extern "C" {
__declspec(dllexport) base* allocate() { return new derived; }
__declspec(dllexport) void deallocate(base* p) { delete p; }
};

BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
return TRUE;
}


Note the only uses of __declspec(-anything-) are in the DLL, and only in the functions. Those function are the only point of communication between the EXE and the DLL; once the derived class has been instantiated, all communication with the DLL will go through the virtual function table as in: p->function().

The code works, I''ve tested it myself, and it correctly prints out "derived function called". Remember to place the compiled DLL in the project directory of the console application. Do not place it in the "Debug" or "Release" directories!

Good Luck,
- null_pointer

Share this post


Link to post
Share on other sites
Thankyou VERY much null, this isn''t the first time you''ve taken the time to help me understand something very useful.

Share this post


Link to post
Share on other sites
Konk...

Looks like I spoke too soon. When I first implemented this it worked fine, now on exit I get a crt debug error when calling Deallocate(delete) on the pointer. I have your example and it compiles fine. My engine code isn''t much different.

Can you, anyone, think of a reason why the pointer while valid would cause a debug message on deletion?

Once again many thanks?

Chris

Share this post


Link to post
Share on other sites
Hmm...well, there could be several reasons causing an error on delete, and none of them seem to apply to this situation, unless it happens to be a simple typo or something in your code.

  • Calling delete on an invalid non-zero pointer.

  • Calling delete on memory allocated from a different heap.

  • Calling the wrong version of delete.

  • MSVC 4.0 had a rare bug which wouldn't let you delete objects created inside DLLs if the object had virtual functions.



Can you send the code to me?

(BTW, if you are calling delete on a base class pointer to a derived class, make sure the destructors are virtual! Otherwise, the derived class destructor may not be called. )


Edited by - null_pointer on March 20, 2001 3:06:41 PM

Share this post


Link to post
Share on other sites
A common problem with linking to DLL''s at run time is that they often have separate heaps. This means that when you allocate memory in the DLL, and try and deallocate it from the main program, it will cause an error because the main application heap is trying to free memory it knows nothing about.

There are a couple of ways to fix this problem:

1)
Have a DeleteThis() function in each base class that simply is:
virtual void DeleteThis() { delete this; }

And instead of calling ''delete myObject'', do myObject->DeleteThis().

2)
I haven''t tried this, but I assume it would work.

For MSVC, use the compiler switch /MD or /MDd (you can change this in the link options for the project) to change the CRT heap to use the msvcrt.dll as the crt.


Hope this helps.

Share this post


Link to post
Share on other sites
Oh good grief, I spend an hour pouring over the source code - why didn''t I think of that? I just had the same problem with delete and the run-time library a few weeks ago! Kudos to Phillip.

Change the projects to use the same run-time library. Open up the Project Settings and go to the C++ tab. Select Code Generation from the drop-down list box, and select "Multithreaded DLL" for the Release build and "Debug Multithreaded DLL" for the Debug build. If for some strange reason this doesn''t work, you can always go back to the defaults by finding the item with the asterisk (*).

This should also make your total app size smaller if you are using DLLs in your project, but probably not by much. For more information look up "MSVCRT.DLL" in the MSDN Library''s index.

Good Luck,
- null_pointer

Share this post


Link to post
Share on other sites
Thnaks all. It''s now fixed though the first method of "DeleteThis()". I couldn''t get my application to compile when I changed the library type... for some reason it started complaining about basic_string being multiply defined...

Anyway... it''s now solved...

Thanks again

Chris

Share this post


Link to post
Share on other sites