Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/130.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 有没有更好的方法在C++;?_C++_Windows_Dll_Loadlibrary - Fatal编程技术网

C++ 有没有更好的方法在C++;?

C++ 有没有更好的方法在C++;?,c++,windows,dll,loadlibrary,C++,Windows,Dll,Loadlibrary,现在我做了一些类似的事情,如果我在我的DLL中有很多我想要引用的函数的话,这看起来很混乱。是否有更好更干净的方法访问函数,而不必为每个函数定义创建typedef,以便正确编译和加载函数。我的意思是,函数定义已经在.h文件中,我不应该在加载函数后重新声明它们(或者我需要吗?),有比使用LoadLibrary更好的解决方案吗?如果有一种方法可以在VisualStudio2005项目设置中执行相同的操作,那么我不一定需要该函数 BHannan_测试h级 #包括“stdafx.h” #包括 #ifnd

现在我做了一些类似的事情,如果我在我的DLL中有很多我想要引用的函数的话,这看起来很混乱。是否有更好更干净的方法访问函数,而不必为每个函数定义创建typedef,以便正确编译和加载函数。我的意思是,函数定义已经在.h文件中,我不应该在加载函数后重新声明它们(或者我需要吗?),有比使用LoadLibrary更好的解决方案吗?如果有一种方法可以在VisualStudio2005项目设置中执行相同的操作,那么我不一定需要该函数


BHannan_测试h级
#包括“stdafx.h”
#包括
#ifndef BHANNAN_测试H类_
#定义BHANNAN_测试类_
外部“C”{
//返回n!(n的阶乘)。对于负n,n!定义为1。
整数declspec(dllexport)阶乘(intn);
//如果n是质数,则返回true。
bool_uuudeclspec(dllexport)IsPrime(intn);
}
#endif//BHANNAN_测试_H类_

BHannan_测试级cpp
#包括“stdafx.h”
#包括“BHannan_测试h类”
//返回n!(n的阶乘)。对于负n,n!定义为1。
整数阶乘(整数n){
int结果=1;
对于(int i=1;i n/i)中断;
//现在,我们有i(0);
}
免费图书馆(myDLL);
}
}

构建.dll后,在附近获取.lib文件,并将测试应用程序与其链接。使用.h中声明的函数

您需要在头文件中做一个小更改:

#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
}

这样,在构建dll时,您可以在项目设置中定义
EXPORTS\u API
,在客户端应用程序中导出函数,而无需定义任何内容。

在构建dll时,您还应该获得一个可以链接的lib文件。这将为你在后台完成繁重的工作。包括已创建的头文件,但更改为dllimport而不是dllexport。您可以为此使用定义,这样对于dll项目,它将使用dllexport,而所有其他不使用此定义的项目将使用dllimport

如果要自己动态加载dll,只需手动加载库和typedef。如果执行上述方法,如果dll不存在,exe将失败

您还可以将dll项目构建到一个静态库中,并加载该库,这也将消除该问题,但会增加exe的大小。如果您真的希望它是一个dll,这当然不是一个选项。

(.lib)简化用户代码中dll的使用,例如,有关基本教程,请参阅。

它们让用户不用自己使用
GetProcAddress()
和函数指针来加载DLL,而是静态链接到导入库,导入库为用户完成工作。

您可以直接链接到DLL的符号,而不用使用
GetProcAddress()
,后者在运行时获取函数的地址

头文件片段示例:

#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
然后在
BHannan_Test_Class.cpp
中,您将在包含标题之前定义MY_LIB_导出


dll\u test.cpp
中,您可以包括标题,只需使用
Factorial()
,就像使用普通函数一样。链接时,您希望链接到生成DLL的建筑。这使得链接到DLL的代码可以使用DLL中的符号。

在Windows世界中,有(至少)4种使用DLL的方法:

  • (你现在在做什么)
  • (使用DLL的“典型”方式)
  • 我不必解释运行时动态链接,因为您已经在这样做了。我选择现在不解释延迟负载动态链接,而仅仅描述它是什么。延迟加载本质上与加载时动态链接相同,只是它只是及时完成,而不是在应用程序加载时完成。这并不像您可能认为的那样有用或有益,它很难使用,也很难编写代码。所以我们不要去那里,至少现在是这样。DLL转发甚至比延迟加载更奇特——如此奇特,直到@mox在评论中提到它,我才听说过它。我将让您阅读上面的链接来了解它,但只需说DLL转发是指您在一个DLL中调用导出函数,但该请求实际上被转发到另一个DLL中的另一个函数

    加载时间动态链接

    这是我认为是香草DLL链接。

    这就是大多数人在应用程序中使用DLL时所指的。您只需
    #包含
    DLL的头文件并链接到LIB文件。无需
    GetProcAddress()
    或创建函数指针typedef。简而言之,它的工作原理如下:

    1) 通常会得到3个文件:一个包含运行时代码的DLL、一个LIB文件和一个头文件。头文件只是一个头文件——它描述了DLL中可以使用的所有工具

    2) 编写应用程序时,
    #包括从DLL中调用头文件并调用这些函数,就像在头文件中使用任何函数一样。编译器知道您使用的函数和对象的名称,因为它们位于DLL的头文件中。但它还不知道它们在记忆中的位置。这就是LIB文件的来源

    3) 转到项目的链接器设置并添加“附加库依赖项”,指定LIB文件。LIB文件告诉链接器从H文件使用的函数和对象在内存中的位置(显然是相对的,而不是绝对的)

    4) 编译你的应用程序。如果您已经正确设置了所有内容,它应该编译、链接并运行。当您收到“未解析的外部引用”链接器错误时,通常是由于设置不正确。您可能没有指定LIB文件的正确路径,或者需要
    #include <BHannan_Test_Class.h>
    
    typedef int (*FactorialPtr) (int);
    FactorialPtr myFactorial=NULL;
    
    // Tests factorial of negative numbers.
    TEST(FactorialTest, Negative) {
    
        HMODULE myDLL = LoadLibrary("BHannan_Sample_DLL.dll");
    
        if(myDLL) {
            myFactorial = (FactorialPtr) GetProcAddress(myDLL,"Factorial");
    
            if(myFactorial)
            {
                EXPECT_EQ(1, myFactorial(-5));
                EXPECT_EQ(1, myFactorial(-1));
                EXPECT_TRUE(myFactorial(-10) > 0);
            }
    
            FreeLibrary(myDLL);
        }
    
    }
    
    #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
    }
    
    #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
    
    // 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);
    
    int (* myFactorial)(int) = 0;
    
    HMODULE myDLL = LoadLibrary("BHannan_Sample_DLL.dll");
    
    if(myDLL) {
        myFactorial = reinterpret_cast<int (*) (int)>( GetProcAddress(myDLL,"Factorial"));
        ...
    }
    
    if ( HMODULE myDLL = LoadLibrary("BHannan_Sample_DLL.dll") ) {
        if ( int (* myFactorial)(int) = GetProcAddress ( myFactorial, myDLL, "Factorial" ) ) {
            ...
        }
    }
    
    template <typename T>
    T GetProcAddress ( const T&, HMODULE mod, const char* name) 
    {
        return reinterpret_cast<T> (GetProcAddress(mod,name)); 
    }