动态链接库是一个模块,它包含了一些函数和数据,能够被其他模块进行调用(其他程序或DLL)。
下面演示如何将函数,数据和类导出供其他可执行文件调用。
导出的数据,函数,和类如下
// Global Data有两种方法可以从DLL中导出数据
int g_nVal1
int g_nVal2
// Ordinary Functions
int __cdecl GetStringLength1(PCWSTR pszString);
int __stdcall GetStringLength2(PCWSTR pszString);
// Callback Function
int __stdcall CompareInts(int a, int b, PFN_COMPARE cmpFunc)
// Class
class CSimpleObject
{
public:
CSimpleObject(void); // Constructor
virtual ~CSimpleObject(void); // Destructor
// Property
float get_FloatProperty(void);
void set_FloatProperty(float newVal);
// Method
HRESULT ToString(PWSTR pszBuffer, DWORD dwSize);
// Static method
static int GetStringLength(PCWSTR pszString);
private:
float m_fField;
};
1.使用.DEF文件进行导出
模块定义文件(.DEF)是一个纯文本文件,包括了一个或多个模块的声明,用来描述DLL的属性。
2.使用导出符号__declspec(dllexport)
A 使用.DEF导出的具体实现方法是如下
1.首先在头文件中声明导出数据和函数,然后在cpp中进行定义
int g_nVal1;2.添加一个.DEF文件,名称为CppDynamicLinkLibrary.def。文件的第一行必须是LIBRARY,然后紧跟要导出的DLL的名字,例如CppDynamicLinkLibrary 。接下来导出声明列出将要导出的数据或函数的名字。
int /*__cdecl*/ GetStringLength1(PCWSTR pszString)
int __stdcall GetStringLength1(PCWSTR pszString)
int __stdcall CompareInts(int a, int b, PFN_COMPARE cmpFunc)
LIBRARY CppDynamicLinkLibrary由于在连接过程中DLL工程会调用.def文件,所以我们应该在项目的属性对话框中的Linker/Input 页面将 模块定义文件的值设置为我们刚才创建的那个.def文件。
EXPORTS
GetStringLength1 @1
CompareInts @2
g_nVal1 DATA
B 使用__declspec(dllexport)导出符号进行导出
首先在头文件中定义如下预编译块
这样做的目的是使得我们在导入导出的时候更方便,因为我们可以使用SYMBOL_DECLSPEC宏来替代看起来十分繁琐吓人的__declspec(dllexport)导出符号。
#ifdef CPPDYNAMICLINKLIBRARY_EXPORTS
#define SYMBOL_DECLSPEC __declspec(dllexport)
#else
#define SYMBOL_DECLSPEC __declspec(dllimport)
#endif
在每个将要导出的数据或函数前都加上SYMBOL_DECLSPEC,这里我们额外添加EXTERN_C(extern “C”)的目的是为了支持我们的模块被C语言或其他动态链接的程序调用。添加这个的意思就是指明使用C的连接方式,在连接的时候函数名不会改变,而不是C++的安全命名法,会改变函数名称。
EXTERN_C SYMBOL_DECLSPEC int g_nVal2;EXTERN_C SYMBOL_DECLSPEC int /*__cdecl*/ GetStringLength2(PCWSTR pszString);EXTERN_C SYMBOL_DECLSPEC int __stdcall GetStringLength2(PCWSTR pszString);class SYMBOL_DECLSPEC CSimpleObject{ ...};
完整代码:
.h
#pragma once.cpp
#include <windows.h>
// 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 CPPDYNAMICLINKLIBRARY_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
// SYMBOL_DECLSPEC and SYMBOL_DEF functions as being imported from a DLL,
// whereas this DLL sees symbols defined with these macros as being exported.
#ifdef CPPDYNAMICLINKLIBRARY_EXPORTS
#define SYMBOL_DECLSPEC __declspec(dllexport)
#define SYMBOL_DEF
#else
#define SYMBOL_DECLSPEC __declspec(dllimport)
#define SYMBOL_DEF __declspec(dllimport)
#endif
#pragma region Global Data
EXTERN_C SYMBOL_DECLSPEC int g_nVal2;
#pragma endregion
#pragma region Ordinary Functions
SYMBOL_DEF int /*__cdecl*/ GetStringLength1(PCWSTR pszString);
EXTERN_C SYMBOL_DECLSPEC int __stdcall GetStringLength2(PCWSTR pszString);
#pragma endregion
#pragma region Callback Function
// Type-definition: 'PFN_COMPARE' now can be used as type
typedef int (CALLBACK *PFN_COMPARE)(int, int);
// An exported/imported stdcall function using a DEF file
// It requires a callback function as one of the arguments
// Sym: CompareInts
// See: CppDynamicLinkLibrary.cpp
SYMBOL_DEF int __stdcall CompareInts(int a, int b, PFN_COMPARE cmpFunc);
#pragma endregion
#pragma region Class
class SYMBOL_DECLSPEC CSimpleObject
{
public:
CSimpleObject(void); // Constructor
virtual ~CSimpleObject(void); // Destructor
// Property
float get_FloatProperty(void);
void set_FloatProperty(float newVal);
// Method
HRESULT ToString(PWSTR pszBuffer, DWORD dwSize);
// Static method
static int GetStringLength(PCWSTR pszString);
private:
float m_fField;
};
#pragma endregion
#include "CppDynamicLinkLibrary.h".def
#include <strsafe.h>
#pragma region DLLMain
BOOL APIENTRY DllMain(HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
#pragma endregion
#pragma region Global Data
// An exported/imported global data using a DEF file
// Initialize it to be 1
int g_nVal1 = 1;
// An exported/imported global data using __declspec(dllexport/dllimport)
// Initialize it to be 2
SYMBOL_DECLSPEC int g_nVal2 = 2;
#pragma endregion
#pragma region Ordinary Functions
// An exported/imported cdecl(default) function using a DEF file
int /*__cdecl*/ GetStringLength1(PCWSTR pszString)
{
return static_cast<int>(wcslen(pszString));
}
// An exported/imported stdcall function using __declspec(dllexport/dllimport)
SYMBOL_DECLSPEC int __stdcall GetStringLength2(PCWSTR pszString)
{
return static_cast<int>(wcslen(pszString));
}
#pragma endregion
#pragma region Callback Function
// An exported/imported stdcall function using a DEF file
// It requires a callback function as one of the arguments
int __stdcall CompareInts(int a, int b, PFN_COMPARE cmpFunc)
{
// Make the callback to the comparison function
// If a is greater than b, return a;
// If b is greater than or equal to a, return b.
return ((*cmpFunc)(a, b) > 0) ? a : b;
}
#pragma endregion
#pragma region Class
// Constructor of the simple C++ class
CSimpleObject::CSimpleObject(void) : m_fField(0.0f)
{
}
// Destructor of the simple C++ class
CSimpleObject::~CSimpleObject(void)
{
}
float CSimpleObject::get_FloatProperty(void)
{
return this->m_fField;
}
void CSimpleObject::set_FloatProperty(float newVal)
{
this->m_fField = newVal;
}
HRESULT CSimpleObject::ToString(PWSTR pszBuffer, DWORD dwSize)
{
return StringCchPrintf(pszBuffer, dwSize, L"%.2f", this->m_fField);
}
int CSimpleObject::GetStringLength(PCWSTR pszString)
{
return static_cast<int>(wcslen(pszString));
}
#pragma endregion
LIBRARY CppDynamicLinkLibrary
EXPORTS
GetStringLength1 @1
CompareInts @2
g_nVal1 DATA