24

Can I put a class inside a DLL? The class i wrote is this:

    class SDLConsole
{
      public:
             SDLConsole();
             ~SDLConsole(){};
             void getInfo(int,int);
             void initConsole(char*, char*, SDL_Surface*, int, int, int);
             void sendMsg(char*,int, SDL_Surface*);
             void cls(SDL_Surface*);

      private:
              TTF_Font *font;
              SDL_Surface *consoleImg;
              int width, pos, height, line, size, ctLine;
              SDL_Surface* render(char*,int);

};

I know how to load a DLL and use the function inside a DLL, but how can I put a class inside a DLL? Thank you very much.

r1cebank
  • 345
  • 1
  • 3
  • 12

4 Answers4

29

If you use run time dynamic linking (uses LoadLibrary to load the dll) you cannot access the class directly, you need to declare a interface for your class and create a function that returns a instance of this class, like this:

class ISDLConsole
{
  public:             
         virtual void getInfo(int,int) = 0;
         virtual void initConsole(char*, char*, SDL_Surface*, int, int, int) = 0;
         virtual void sendMsg(char*,int, SDL_Surface*) = 0;
         virtual void cls(SDL_Surface*) = 0;
 };

 class SDLConsole: public ISDLConsole
 {
    //rest of the code
 };

 __declspec(dllexport) ISDLConsole *Create()
 {
    return new SDLConsole();
 }

Otherwise, if you link the dll during load time, just use the information provided by icecrime: http://msdn.microsoft.com/en-us/library/a90k134d.aspx

bcsanches
  • 2,362
  • 21
  • 32
  • This way is much more robust than `__declspec(dllexport)`. Even load-time linking should use this method. – Ben Voigt Dec 29 '10 at 17:08
  • 5
    Because only the v-table layout has to match between library and client, which is relatively easy to accomplish, even between different languages. On the other hand, with `__declspec(dllexport)` everything has to match: compiler vendor, compiler version, compile options, or you will either end up with name-mangling mismatch (link error) or a one-definition-rule violation and corresponding crashes. – Ben Voigt Dec 29 '10 at 18:43
  • 3
    Eventually you end with a situation where you have to compile your application with version X of the compiler, since that's what library A uses. Then you want to use library B, but you can't, because it requires version Y of the compiler. – Ben Voigt Dec 29 '10 at 18:46
  • 1
    In all my years as a Windows C++ developer I have never come across this trick before - excellent answer and something I will definitely be using myself. – Rob Dec 29 '10 at 19:55
  • How do we call class method in our process from dll if we use this method. – spt025 Jun 12 '15 at 09:42
  • @spt025 your dll will be loaded by the process and it needs a entry point so the process can "init" or call something there. When it does that, it can provide a pointer to the class or a function pointer that your dll can call to instantiate the class. – bcsanches Jun 15 '15 at 04:13
  • @bcsanches, can I use std::shared_ptr when return an instance? – Zach Jun 27 '15 at 02:09
  • @Zach I do not see any problem. You may be aware that shared_ptr and friends are template code, implemented on header, so who includes your header file, must have the exactly same version of the lib that you have, otherwise they may have trouble. I have done this lot of times and never had a issue. – bcsanches Jul 16 '15 at 14:01
  • 2
    Perhaps the COM (Component Object Model) deserves mention in this answer, because it works in pretty much the same way: The entry point function is called `DllGetClassObject`, and you only ever receive interface pointers. – stakx - no longer contributing Jul 10 '16 at 08:55
  • The subtle thing to note here is that, you can actually access the class if you use an import library and thus will result to a static linking. The import library .lib is paired with it's corresponding .dll but you do not use LoadLibrary/GetProcAddress to load this dll. On the other hand, if you use LoadLibrary/GetProcAddress technique then you have no visibility of the class definition and is thus forced to rely on a base class or via COM (IUnknown, IDispatch) technique, either which it is requiring a common base class that could poke into the object that is hidden in the DLL. – daparic Jul 30 '18 at 20:16
13

Solution suggested by bcsanches,

 __declspec(dllexport) ISDLConsole *Create()
 {
    return new SDLConsole();
 }

If you're going to use this approach as suggested by bcsanches, then make sure that you use the following function to delete your object,

 __declspec(dllexport) void Destroy(ISDLConsole *instance)
 {
       delete instance;
 }

Define such functions always in pair, as it ensures that you delete your objects from the same heap/memory-pool/etc they were created on. See this pair-functions

Community
  • 1
  • 1
Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • I want to create a dll out of my c++ class and use that dll in my C# application. can you please guide me on that too? what else is needed? how can i call my dll in c# when i create it this way? – Hossein Jul 28 '13 at 08:31
  • 1
    @Hossein: Search for pinvoke in C#. You will find lots of topics on it. – Nawaz Jul 28 '13 at 08:48
  • you mean i need to use the conventional DIIIMport just like normal dlls (such as user32.dll)? ok i'll give it a try – Hossein Jul 28 '13 at 10:28
  • Ok here is the problem! How should i specify the return type of my factory class? public static extern object?! Create_xGramManilpulator(wchar_t* filename); and what should i use in C# to address vector and wchar_t* type? – Hossein Jul 28 '13 at 10:42
  • @Nawaz: If you want to export a C++ class to C#, you need to do two things: lay out your class like a COM class (i.e. have it implement `IUnknown` and follow the COM protocol) so that you can use COM interop on the .NET side. Second, export a factory function from your DLL that returns an instance of your class, as suggested in bcsanches' answer, which you then `[DllImport]` from your .NET code. – stakx - no longer contributing Jul 10 '16 at 09:00
5

You can, and all the information you need are on this page and this page :

#ifdef _EXPORTING
   #define CLASS_DECLSPEC __declspec(dllexport)
#else
   #define CLASS_DECLSPEC __declspec(dllimport)
#endif

class CLASS_DECLSPEC SDLConsole
{
    /* ... */
};

All there is left is to define the preprocessor symbol _EXPORTING when building the DLL.

icecrime
  • 74,451
  • 13
  • 99
  • 111
  • 2
    That's not "all there is left". You also need to make sure that the same exact compiler is used for building the DLL and all clients, that compiler options also match. You pay a huge maintainability penalty for doing things this way, the [pure virtual interface as suggested by bcsanches](http://stackoverflow.com/questions/4555961/how-to-use-a-class-in-dll/4556025#4556025) is much better. – Ben Voigt Dec 29 '10 at 17:11
  • @Ben: you're probably right, but I have to admit I've always done things this way and that I just cannot imagine using the 'pure virtual interface' method on a big project – icecrime Dec 29 '10 at 18:11
  • If you've got modules which are closely coupled because they're all local to a single project, why not just use static libraries? – Ben Voigt Dec 29 '10 at 18:48
2

If you want to expose the data in a class, the above solutions won't cut it. You have to slap a __declspec(dllexport) on the class itself in the DLL compilation, and a __declspec(dllimport) in the module that links to the DLL.

A common technique is to do this (Microsoft wizards produce code like this):

#ifdef EXPORT_API
#define MY_API __declspec(dllexport)
#else
#define MY_API __declspec(dllimport)
#endif

class MY_API MyClass {
   ...
};

Then make sure EXPORT_API is defined in the DLL project, and make sure it isn't defined in the module that links to the DLL.

If you create a new DLL project in Visual C++ from scratch, and check the check box "Export symbols", some sample code will be generated using this technique.

Jörgen Sigvardsson
  • 4,839
  • 3
  • 28
  • 51