创建动态链接库 (DLL) 项目
-------参考MSDN和Repeaterbin的专栏
向动态链接库添加类
// MathFuncsDll.h
#ifdef MATHFUNCSDLL_EXPORTS
#define MATHFUNCSDLL_API __declspec(dllexport)
#else
#define MATHFUNCSDLL_API __declspec(dllimport)
#endif
namespace MathFuncs
{
// This class is exported from the MathFuncsDll.dll
class MyMathFuncs
{
public:
// Returns a + b
static MATHFUNCSDLL_API double Add(double a, double b);
// Returns a - b
static MATHFUNCSDLL_API double Subtract(double a, double b);
// Returns a * b
static MATHFUNCSDLL_API double Multiply(double a, double b);
// Returns a / b
// Throws const std::invalid_argument& if b is 0
static MATHFUNCSDLL_API double Divide(double a, double b);
};
}
// MathFuncsDll.cpp : Defines the exported functions for the DLLapplication.
#include "stdafx.h"
#include "MathFuncsDll.h"
#include
using namespace std;
namespace MathFuncs
{
double MyMathFuncs::Add(double a, double b)
{
return a + b;
}
double MyMathFuncs::Subtract(double a, double b)
{
return a - b;
}
double MyMathFuncs::Multiply(double a, double b)
{
return a * b;
}
double MyMathFuncs::Divide(double a, double b)
{
if (b == 0)
{
throw invalid_argument("b cannot be zero!");
}
return a / b;
}
}
备注:导出函数常用方式:
1,使用DEF文件从DLL中导出
.def 文件必须至少包含下列模块定义语句:
文件中的第一个语句必须是 LIBRARY 语句。 此语句将 .def 文件标识为属于 DLL。 LIBRARY 语句的后面是 DLL 的名称。 链接器将此名称放到 DLL 的导入库中。
EXPORTS 语句列出名称,可能的话还会列出 DLL 导出函数的序号值。 通过在函数名的后面加上 @ 符和一个数字,给函数分配序号值。 当指定序号值时,序号值的范围必须是从 1 到N,其中 N 是 DLL 导出函数的个数。
LIBRARY BTREE
EXPORTS
Insert @1
Delete @2
Member @3
Min @4
2,使用__declspec(dllexport) 从DLL 导出
可以使用 __declspec(dllexport) 关键字从 DLL 导出数据、函数、类或类成员函数。 __declspec(dllexport) 会将导出指令添加到对象文件中,因此不需要使用 .def 文件。
若要导出函数,__declspec(dllexport) 关键字必须出现在调用约定关键字的左边(如果指定了关键字)。
__declspec(dllexport) void __cdecl Function1(void);
若要导出类中的所有公共数据成员和成员函数,关键字必须出现在类名的左边,
class__declspec(dllexport) CExampleExport
{ ... classdefinition ... };
我们常用的导出定义:
#ifdef _EXPORTING
#defineAPI_DECLSPEC __declspec(dllexport)
#else
#defineAPI_DECLSPEC __declspec(dllimport)
#endif
class API_DECLSPECCBtt
{
public:
CBtt(void);
~CBtt(void);
public:
CString m_str;
static int GetValue()
{
return m_nValue;
}
private:
static int m_nValue;
};
注:单独使用__declspec(dllexport)已经可以实现DLL中库函数的导出,不使用 __declspec(dllimport)也能正确编译代码,但使用 __declspec(dllimport)使编译器可以生成更好的代码。编译器之所以能够生成更好的代码,是因为它可以确定函数是否存在于 DLL 中,这使得编译器可以生成跳过间接寻址级别的代码,而这些代码通常会出现在跨 DLL 边界的函数调用中。但是,必须使用 __declspec(dllimport)才能导入 DLL 中使用的变量。
__declspec(dllimport)的实际用处:
SIMPLEDLL_EXPORT
SimpleDLLClass.h
#ifdefSIMPLEDLL_EXPORT
#define DLL_EXPORT__declspec(dllexport)
#else
#define DLL_EXPORT
#endif
class DLL_EXPORTSimpleDLLClass
{
public:
SimpleDLLClass();
virtual ~SimpleDLLClass();
virtual getValue() { return m_nValue;};
private:
int m_nValue;
};
SimpleDLLClass.cpp
#include"SimpleDLLClass.h"
SimpleDLLClass::SimpleDLLClass()
{
m_nValue=0;
}
SimpleDLLClass::~SimpleDLLClass()
{
}
然后你再使用这个DLL类,在你的项目中include SimpleDLLClass.h时,你的项目不用定义 SIMPLEDLL_EXPORT 所以,DLL_EXPORT 就不会存在了,这个时候,不会遇到问题。这正好对应MSDN上说的__declspec(dllimport)定义与否都可以正常使用。但,我们改一下SimpleDLLClass,把它的m_nValue改成static,然后在cpp文件中加一行
int SimpleDLLClass::m_nValue=0;
改完之后,再去LINK一下,你的APP,看结果如何,结果是LINK告诉你找不到这个m_nValue。
改一下SimpleDLLClass.h:
#ifdefSIMPLEDLL_EXPORT
#define DLL_EXPORT__declspec(dllexport)
#else
#define DLL_EXPORT__declspec(dllimport)
#endif
再LINK,一切正常。原来dllimport是为了更好的处理类中的静态成员变量的,如果没有静态成员变量,那么这个__declspec(dllimport)无所谓。