Solved

Derived Classes and DLLs

Posted on 2000-04-16
9
361 Views
Last Modified: 2013-12-14
Here's my problem.  So far, I have been programming some DLLs with __declspec(import and export)  I have just classes  (and callback functions, which are not my problem so n/m)  I am making a rendering class, with a base class, and modules for differnet renderers, DirectX, OpenGL, SoftWare, etc.  I have the basic Render class has the basic functions with no definitions, and the derived classes are the actual rendering devices that have the functions (from the base class)  are defined.  My problem is this, I want to have the base class compiled with the __declspec() but the derived classes to be loaded dynamically so that all rendering devices are not all loaded at once, and this will make room for people to compile their own rendering modules themselves.  I have read how to load simple functions from a DLL with LoadLibrary, GetProcAddress (or whatever)  and all those functions, but I want to know how to load an entire class, without having to typedef each seperate function then prototypeing from the typedef then loading from the DLL to the prototype, this just seems like too much work and I hope there's a quicker and more simplisitic way, without having to have multiple headers for the classes for build and runtime.  Can anyone help?  (Or understand what I mean)
0
Comment
Question by:XycsoscyX
  • 5
  • 2
  • 2
9 Comments
 
LVL 22

Accepted Solution

by:
nietod earned 75 total points
Comment Utility
This can be done by using virtual functions (it would be nearly impossible without them).  I think I have a "prewwritten" answer on this.  I'll see if I can find it.
0
 
LVL 22

Expert Comment

by:nietod
Comment Utility
Example.
************ Base.h*******
// Note no export directive.  Not of any value for you
// since you are linking at run-time.
class Paths {
 public :
         Paths() ;
        // note all functions are virtual, because linking
        // is to be done through the VTBL  No need for
        // GetProcAddress().
         virtual ~Paths() = 0;;
         virtual int DoSometingWith (int x, int y)  = 0;
         vitual char* SomethingElse (int v, char *w) = 0 ;
};

// Type defintition for the "factory" function.
typedef Path * (*MakePtrTyp)();

***********Dll.cpp************
#inlude "Base.h"

// Derived concrete class.  Functions can be added here that
// are not virtual, so long as they are not to be used by the EXE.
// Any functions the EXE uses must be virtual.
class DerivedPaths : public Paths
{
public:
         DerivedPaths() ;
         virtual ~Paths()  {};
         virtual int DoSometingWith (int x, int y)  { return x+y; };
         vitual char* SomethingElse (int v, char *w)  { return w+v; } ;
}

// The factory function.  Uses extern "C" so that it is easier for
// the EXE to get using GetProcAddress();
extern "C" Paths *MakePaths()
{
    return new DerivedPaths;
};

***************EXE.cpp*****************
WinMain()
{
   HINSTANCE PathLib = Loadlibrary("some path");
   MakePtrTyp MakeProc = (MakePtrTyp) GetProcAddress(PathLib,"MakePaths");

   Paths *PathsPtr = (*makeProc)(); // Make a paths object.

   PathsPtr->DoSomethingWith(1,2);
   delete PathsPtr;
}

A couple more words of explanation.  

The only time you need to use GetProcAddress() with this scheme is to find the factory function in the DLL that creates the objects.  All the other functions are handled through virtual functions calls.  That is obviously much more convenient than lots of GetProcAddress() calls!

The DLL allocates objects using new and the EXE eventually deletes it with delete.  For this to work the two must share a common heap, this means you must use the DLL version of the run-time library.  (a good idea in any case.)  Another alternative is for the DLL to have a function that does the delete, but I would do the other.

The EXE can load different DLLs that define different derived classes.  So if the derived class has different versions or changes with time, the EXE does not need to be recompiled.

This approach is in many ways the C++ version of COM.
0
 
LVL 22

Expert Comment

by:nietod
Comment Utility
That is an example, but not an explanation.  What you need to do is to make all the public functions of the class virtual.  And you do not need to export them from the DLL (but you can, it just doesn't matter).  This is so that the virtual table will be used to find the right procedure to call at run time.  This is is important because you (realistically) cannot use the return value from GetProcAddress() to call a non-static member function.  So we get around this by using virtual functions.

Now you will need to use GetProcAddress() still, but only for one thing, which is nice because it is inconvenient to use!  when you need to create a object you will use GetProcAddress() to call a factory function in the DLL.  To be specific, each DLL will have an exported function with a specific name (or ordinal) and this function will return a pointer to a dynamically allocated object of whatever class this DLL is supposed to create.  Now the object returned by the DLL is of a class derived from the class the EXE "knows" about.  The EXE doesn't "know" about the derived class.  But that is fine.  The factory function creates the class and the virtual functions manipulat the class, so the EXE only needs to "know" about the base class.

Let me know if you have any questions.
0
 

Author Comment

by:XycsoscyX
Comment Utility
I accepted the answer because it works now, with one workaround.  When I compiled at first, I got an error  (when I compiled the DLL for the derived class)  Since I have to use the base class as : public RenderSystem (which is what I am using)  But I get an error when I compile saying the Initializer and DeInitializer from the base class are not defined.  My temporary workaround was to define the Init and DeInit within the Derived class modules seperately, but I want to have the functions for the Init and DeInit of the base class with the exe itself, not the seperated modules.  How can I fix this?
0
Highfive Gives IT Their Time Back

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 
LVL 22

Expert Comment

by:nietod
Comment Utility
I'm not really following you.  Are you tallking about constructors and destructors, or other functions?

hmmmm.

Did you get this error when compiling the EXE or the DLL?  You might get this when compiling the DLL....   If so, I think you're going to have to place these functions in the base class's include file, so they are placed in each module.  

another option, might be to export the the functions from the class in the EXE and then link the DLL with the EXE's .lib file.   That sort of technique is actually posible.  (havig a DLL use exports from the EXE that loads it.)  but I've never done it and there may bother steps invloved and adding the fact that these are member functions could compilcate it.
0
 

Author Comment

by:XycsoscyX
Comment Utility
Okay, thanks, I thik what I wil to is make my base renderer a dll  (well, actually base render, input, sound, etc)  and export the classes to it, so I have it and the dll, then link my derived classes to the lib from the base dll, and link the exe to this base dll also.....thank for all your help.
0
 

Expert Comment

by:gpbaldazzi
Comment Utility
I used the code Nietod code and I find it great!
But I have a trouble: my "MakePaths" function is exactally the same, I can use pointers returned by this function to call virtual function and everithing is all right.
But my program crashes vhen I call the
"delete" on this pointers!

Any suggestion?
Thanks
GP
0
 
LVL 22

Expert Comment

by:nietod
Comment Utility
Are you using the DLL version of the run-time library (RTL)?  You need to.  The static RTL will not work for this.

From another question:

**********************************

The problem is that if the EXE and DLL use the staticly linked version of the run-time library (RTL), they each have their own seperate copies of the RTL.  These copies each have thier own seperate heaps for allocating memory with the new operator.   The problem is that each one does not "know" about the other.  So for example, if the DLL allocates memory, the memory comes from the heap in the DLL's copy of the RTL.  If a pointer to that memory is passed back to the EXE (it may be passed in a subtle way, like inside a class) and if that EXE later makes changes that require that the memory specified by the pointer be deleted, then the EXE will try to delete the memory, but will not be able to find the memory inside its heap.  This is is because the memory did not come from the heap.  Hence the problem.

The solution is to have the EXE and all the C++ DLLS that it uses link with the DLL version of the RTL.  Then the EXE and all the DLLS will share a single copy of the run-time library and will therefore share a single heap.

To set this in VC:

"Project" menu
"Settings..." menu item
in the dialog box that appears  "C/C++" tab
"Code generation" Category
in "Use run-time library:" select one of the DLL options.

(There are two DLLoptions there, one for a debug version, one for a release version.  Make sure you choose the setting that is right for the version you are creating)

Note that these settings need to be changed for EVERY version (debug. release etc) of the EXE and and DLLs that is shares memory with.
0
 

Expert Comment

by:gpbaldazzi
Comment Utility
thanks nietod for your answer.
You had already told that I need to use the Dll version of the RTL or call a member function for deleting the object, but I didn't read carefully your previous answer.

I chosed to implement a Release function in the dll, because I dont want to have any trouble with future .exe that may need to use the Static RTL.

Once again, this is COM!
thanks a lot
GP
0

Featured Post

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

What is C++ STL?: STL stands for Standard Template Library and is a part of standard C++ libraries. It contains many useful data structures (containers) and algorithms, which can spare you a lot of the time. Today we will look at the STL Vector. …
IntroductionThis article is the second in a three part article series on the Visual Studio 2008 Debugger.  It provides tips in setting and using breakpoints. If not familiar with this debugger, you can find a basic introduction in the EE article loc…
The viewer will learn how to use NetBeans IDE 8.0 for Windows to connect to a MySQL database. Open Services Panel: Create a new connection using New Connection Wizard: Create a test database called eetutorial: Create a new test tabel called ee…
The goal of the tutorial is to teach the user how to use functions in C++. The video will cover how to define functions, how to call functions and how to create functions prototypes. Microsoft Visual C++ 2010 Express will be used as a text editor an…

743 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

16 Experts available now in Live!

Get 1:1 Help Now