Solved

Derived Classes and DLLs

Posted on 2000-04-16
9
365 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 5
  • 2
  • 2
9 Comments
 
LVL 22

Accepted Solution

by:
nietod earned 75 total points
ID: 2721187
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
ID: 2721189
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
ID: 2721199
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
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 

Author Comment

by:XycsoscyX
ID: 2721562
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
 
LVL 22

Expert Comment

by:nietod
ID: 2722406
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
ID: 2724174
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
ID: 4305554
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
ID: 4305797
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
ID: 4312876
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

Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Many modern programming languages support the concept of a property -- a class member that combines characteristics of both a data member and a method.  These are sometimes called "smart fields" because you can add logic that is applied automaticall…
Basic understanding on "OO- Object Orientation" is needed for designing a logical solution to solve a problem. Basic OOAD is a prerequisite for a coder to ensure that they follow the basic design of OO. This would help developers to understand the b…
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 viewer will learn how to clear a vector as well as how to detect empty vectors in C++.

710 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