Is there a better way to load a dll in C++?

前端 未结 7 1323
北海茫月
北海茫月 2020-12-13 16:46

Right now I do something like this and it seems messy if I end having a lot of functions I want to reference in my DLL. Is there a better and cleaner way of accessing the fu

相关标签:
7条回答
  • 2020-12-13 16:48

    Why don't you get VS to generate a shim static library around your DLL. That way all you have to do is add a calling convention in the header file and add a couple of pre-procesor directives. The easiest way to figure out how to do it is to create a new DLL project (Visual C++>Win32 Project, Choose DLL Project, check Import symbols)

    Use the main header file as an example on how to decorate your classes with the import/export calling convention. This head is the important bit as it explains how to use the functions and classes declared there:

    // The following ifdef block is the standard way of creating macros which make exporting 
    // from a DLL simpler. All files within this DLL are compiled with the DLLTEST2_EXPORTS
    // symbol defined on the command line. this symbol should not be defined on any project
    // that uses this DLL. This way any other project whose source files include this file see 
    // DLLTEST2_API functions as being imported from a DLL, whereas this DLL sees symbols
    // defined with this macro as being exported.
    
    #ifdef DLLTEST2_EXPORTS
    #define DLLTEST2_API __declspec(dllexport)
    #else
    #define DLLTEST2_API __declspec(dllimport)
    #endif
    
    // This class is exported from the dlltest2.dll
    class DLLTEST2_API Cdlltest2 {
    public:
        Cdlltest2(void);
        // TODO: add your methods here.
    };
    
    extern DLLTEST2_API int ndlltest2;
    
    DLLTEST2_API int fndlltest2(void);
    

    Then, in the project that uses that DLL simply include the header file and .lib that the DLL project generated. That way it automatically loads the DLL and you can use all the functions as though statically linked.

    0 讨论(0)
  • 2020-12-13 16:55

    Import libraries (.lib) simplify DLL usage in user code, see e.g. here for a basic tutorial.
    They spare the users from loading the DLL, using GetProcAddress() and function pointers themselves - they statically link to the import library instead which does the work for them.

    0 讨论(0)
  • 2020-12-13 16:58

    In the Windows world, there are (at least) 4 ways to use DLLs:

    1. Run-Time Dynamic Linking (What you're doing now)
    2. Load-Time Dynamic Linking (the "typical" way of using DLLs)
    3. Delay-Load Dynamic Linking
    4. DLL Forwarding

    I don't have to explain Run-Time Dynamic Linking since you're already doing it. I choose not to explain Delay-Load Dynamic Linking now beyond just describing what it is in general terms. Delay Load is essentially the same as Load-Time Dynamic Linking except it's done Just-In-Time instead of at application load. This is not as useful or as beneficial as you might think, it is difficult to work with and tricky to code for. So let's not go there, at least for now. DLL Forwarding is even more exotic than Delay-Loading -- so exotic, I'd never even heard of it until @mox mentioned it in the comments. I'll let you read the link above to learn about it, but suffice it to say that DLL Forwarding is when you call an exported function in one DLL but that request is actually forwarded to another function in a different DLL.

    Load-Time Dynamic Linking

    This is what I would consider to be Vanilla DLL Linking.

    This is what most people are referring to when they refer to using DLLs in their applications. You just #include the DLL's header file and link to the LIB file. No need to GetProcAddress() or create function pointer typedefs. Here's how it works in a nutshell:

    1) You typically get 3 files: a DLL with the runtime code, a LIB file and a header file. The header file is just a header file -- it describes all the facilities in the DLL you can use.

    2) You write your application, #include'ing the header file from the DLL and making calls to those functions just like you would use any function in any header file. The compiler knows the names of functions and objects you use because they are in the DLL's header file. But it doesn't know where they are in memory yet. That is where the LIB file comes in...

    3) You go to the linker settings for your project and add an "additional library dependency," specifying the LIB file. The LIB file tells the linker where the functions and objects you use from the H file reside in memory (in relative terms, not absolute terms, obviously).

    4) Compile your app. If you have set everything up correctly it should compile, link and run. When you get "unresolved external reference" linker errors commonly this is due to things not being set up right. You may either have not specified the correct path to the LIB file or you need to include more LIB files.

    0 讨论(0)
  • 2020-12-13 17:03

    After building your .dll get the .lib file nearby and link your test application with it. Use functions as they are declared in .h

    There's a minor change you need to do in your header file:

    #ifdef EXPORTS_API
      #define MY_API_EXPORT __declspec (dllexport)
    #else
      #define MY_API_EXPORT __declspec (dllimport)
    #endif
    
    extern "C" {
        int MY_API_EXPORT Factorial(int n);
    
        // do the same for other functions
    }
    

    This way, when building your dll you define EXPORTS_API in your project settings and functions get exported, in the client application, no need to define anything.

    0 讨论(0)
  • 2020-12-13 17:04

    You can link to the DLL's symbols directly instead of using GetProcAddress(), which gets the address of a function at runtime.

    Example header file snippet:

    #if defined(MY_LIB_STATIC)
    #define MY_LIB_EXPORT
    #elif defined(MY_LIB_EXPORTS)
    #define MY_LIB_EXPORT __declspec(dllexport)
    #else
    #define MY_LIB_EXPORT __declspec(dllimport)
    #endif
    
    #ifdef __cplusplus
    extern "C"
    {
    #endif
    
    int MY_LIB_EXPORT Factorial(int n);
    
    #ifdef __cplusplus
    }
    #endif
    

    Then in BHannan_Test_Class.cpp, you would #define MY_LIB_EXPORTS before including the header.

    In dll_test.cpp you would include the header and just use Factorial() as you would use a normal function. When linking, you want to link to the import library that building your DLL produced. This makes the symbols from the DLL available to the code that links to it.

    0 讨论(0)
  • 2020-12-13 17:09

    Of course you don't need the typedef

    int (* myFactorial)(int) = 0;
    
    HMODULE myDLL = LoadLibrary("BHannan_Sample_DLL.dll");
    
    if(myDLL) {
        myFactorial = reinterpret_cast<int (*) (int)>( GetProcAddress(myDLL,"Factorial"));
        ...
    }
    

    or, exploiting C++ initialise and test idiom

    if ( HMODULE myDLL = LoadLibrary("BHannan_Sample_DLL.dll") ) {
        if ( int (* myFactorial)(int) = GetProcAddress ( myFactorial, myDLL, "Factorial" ) ) {
            ...
        }
    }
    

    given this to tidy up the repetition of the type

    template <typename T>
    T GetProcAddress ( const T&, HMODULE mod, const char* name) 
    {
        return reinterpret_cast<T> (GetProcAddress(mod,name)); 
    }
    

    But not using a typedef is generally worse rather than better, as C's function pointer types are a bit tricky to get right unless you're using them regularly. (if you are using them regularly, then your software may be somewhat unorthodox).

    The Microsoft dllimport extensions and compiler create a static library which does the loading for you and provides trampolines or thunks, as others have posted. Unless you're creating a plug-in system which doesn't know which dll it will load, then use that instead.

    0 讨论(0)
提交回复
热议问题