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