How to use a class in DLL?

30,685

Solution 1

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

Solution 2

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

Solution 3

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.

Solution 4

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.

Share:
30,685
r1cebank
Author by

r1cebank

Updated on September 26, 2020

Comments

  • r1cebank
    r1cebank over 3 years

    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.

  • Ben Voigt
    Ben Voigt over 13 years
    This way is much more robust than __declspec(dllexport). Even load-time linking should use this method.
  • Ben Voigt
    Ben Voigt over 13 years
    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 is much better.
  • icecrime
    icecrime over 13 years
    @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
  • Ben Voigt
    Ben Voigt over 13 years
    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
    Ben Voigt over 13 years
    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
    Ben Voigt over 13 years
    If you've got modules which are closely coupled because they're all local to a single project, why not just use static libraries?
  • Rob
    Rob over 13 years
    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.
  • Hossein
    Hossein almost 11 years
    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?
  • Nawaz
    Nawaz almost 11 years
    @Hossein: Search for pinvoke in C#. You will find lots of topics on it.
  • Hossein
    Hossein almost 11 years
    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
    Hossein almost 11 years
    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<string> and wchar_t* type?
  • spt025
    spt025 almost 9 years
    How do we call class method in our process from dll if we use this method.
  • bcsanches
    bcsanches almost 9 years
    @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.
  • Zach
    Zach almost 9 years
    @bcsanches, can I use std::shared_ptr<ISDLConsole> when return an instance?
  • bcsanches
    bcsanches almost 9 years
    @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.
  • stakx - no longer contributing
    stakx - no longer contributing almost 8 years
    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
    stakx - no longer contributing almost 8 years
    @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.
  • truthadjustr
    truthadjustr almost 6 years
    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.