当创建DLL时,要创建一组可执行模块(或其他DLL)可以调用的函数。DLL可以将变量、函数或C/C++类输出到其他模块。在实际工作环境中,应该避免输出变量,因为这会删除你的代码中的一个抽象层,使它更加难以维护你的DLL代码。此外,只有当使用同一个供应商提供的编译器对输入C++类的模块进行编译时,才能输出C++类。由于这个原因,也应该避免输出C++类,除非知道可执行模块的开发人员使用的工具与DLL模块开发人员使用的工具相同。
当创建DLL模槭保?紫扔Ω媒?⒁桓鐾肺募??梦募???四阆胍?涑龅谋淞浚ɡ嘈秃兔?郑┖秃??ㄔ?秃兔?郑?M肺募?贡匦攵ㄒ逵糜谑涑龊??捅淞康娜魏畏?藕褪?萁峁埂D愕腄LL的所有源代码模块都应该包含这个头文件。另外,必须分配该头文件,以便它能够包含在可能输入这些函数或变量的任何源代码中。拥有单个头文件,供DLL创建程序和可执行模块的创建程序使用,就可以大大简化维护工作。
下面的代码说明了应该如何对单个头文件进行编码,以便同时包含可执行文件和DLL的源代码文件:
/*************************************************************************
Module: MyLib.h
*************************************************************************/
#ifdef MYLIBAPI
// MYLIBAPI should be defined in all of the DLLs source
// code modules before this header file is included.
// All functions/variables are being exported
#else
// This header file is included by an EXE source code module
//Indicate that all functions/variables are being imported
#define MYLIBAPI extern "C" _declspec(dllimport)
#endif
/////////////////////////////////////////////////////////////////
//Define any data structures and symbols here
//////////////////////////////////////////////////////////////////
//Define exported variables here .(NOTE: Avoid exporting variables.)
MYLIBAPI int g_nResult;
/////////////////////////////////////////////////////////////////
//Define exported function prototypes here.
MYLIBAPI int Add(int nLeft , int nRight);
////////////////////////// End of File /////////////////////////
在你的每个DLL源代码文件中,应该包含下面的头文件:
/*****************************************************************
Module: MyLibFile1.cpp
******************************************************************/
// Include the standar Windows and C-Runtime header files here.
#include
//This DLL source code file exports functions and variables
#define MYLIBAPI extern "C" _declspce(dllexport)
//Include the exported data structures,symbols,functions,and variable.
#include "MyLib.h"
///////////////////////////////////////////////////////////////
// Place the code for this DLL source code file here
int g_nResult;
int Add(int nLeft,int nRight) {
g_nResult = nLeft + nRight;
return(g_nResult)
};
//////////////////////// End of File ////////////////////////
当上面的DLL源代码文件被编译时,在MyLib.h头文件的前面使用__declspec(DLLexport)对MYLIBAPI进行定义。当编译器看到负责修改变量、函数或C++类的__declspec(DLLexport)时,它就知道该变量、函数或C++类是从产生的DLL模块输出的。注意,MYLIBAPI标志被置于头文件中要输出的变量的定义之前和要输出的函数之前。
另外,在源代码文件(MyLibFile1.cpp0)中,MYLIBAPI标志并不出现在输出的变量和函数之前。MYLIBAPI标志在这里是不必要的,因为编译器在分析头文件时能够记住要输出哪些变量或函数。
你会发现,MYLIBAPI标志包含了extern“C”修改符。只有当你编写C++代码而不是直接编写C代码时,才能使用这个修改符。通常来说,C++编译器可能会改变函数和变量的名字,从而导致严重的链接程序问题。例如,假设你用C++编写一个DLL,并直接用C编写一个可执行模块,当你创建DLL时,函数名被改变,但是,当你创建可执行模块时,函数名没有改变。当链接程序试图链接可执行模块时,它就会抱怨说,可执行模块引用的符号不存在。如果使用extern“C”,就可以告诉编译器不要改变变量名或函数名,这样,变量和函数就可以供使用C、C++或任何其他编程语言编写的可执行模块来访问。
现在你已经知道DLL源代码文件是如何使用这个头文件的。但是,可执行模块的源代码文件情况又是如何呢?可执行模块的源代码文件不应该在这个头文件的前面定义MYLIBAPI。由于MYLIBAPI没有定义,因此头文件将MYLIBAPI定义为__declspec(DLLimport)。编译器看到可执行模块的源代码文件从DLL模块输入变量和函数。
如果观察Microsoft的标准Windows头文件,如WinBase.h,你将会发现Microsoft使用的方法基本上与上面介绍的方法相同。