VC语言6.0程序设计从入门到精通-第60部分
按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!
第 10 章 动态链接库
_stdcall 调用约定在输出函数名前加上一个下划线前缀,后面加上一个“@ ”符号和其参数的
字节数,格式为_functionname@number 。_cdecl 调用约定仅在输出函数名前加上一个下划线
前缀,格式为_functionname 。_fastcall 调用约定在输出函数名前加上一个“@ ”符号,后面
也是一个“@ ”符号和其参数的字节数,格式为@functionname@number 。它们均不改变输出
函数名中字符的大小写,这和 PASCAL 调用约定不同,PASCAL 约定输出的函数名无任何修
饰且全部大写 。本例将给出一种完全模仿PASCAL 调用约定的方法,在 DEF 文件的 EXPORTS
段通过别名来实现。例如:
int __stdcall MyFunc (int a;double b);
void __stdcall InitCode (void);
在 DEF 文件中:
EXPORTS
MYFUNC=_MyFunc@12
INITCODE=_InitCode@0
Visual C++编译输出的函数名修饰较为复杂,编译时 stdcall 调用约定规则如下。
o 以“? ”标识函数名的开始,后跟函数名。
o 函数名后面以“@@YG”标识参数表的开始,后跟参数表。
o 参数表的第一项为该函数的返回值类型,其后依次为参数的数据类型。
o 参数表后以“@Z”标识整个名字的结束,如果该函数无参数,则以“Z ”标识结束。
其格式为“?functionname@@YG*****@Z ”或“?functionname@@YG*XZ ”,例如:
int Test1(char *var1;unsigned long)………… “?Test1@@YGHPADK@Z ”,void Test2()…………
“?Test2@@YGXXZ ”。
cdecl 调用约定规则同上面的 stdcall 调用约定类似,只是参数表的开始标识由上面的
“
@@YG”变为“@@YA”。
fastcall 调用约定规则同上面的 stdcall 调用约定,只是参数表的开始标识由上面的
@@YG”变为“@@YI”。
“
3 .得到没有修饰的函数名
Visual C++ 输 出 函 数 时 使 用 _declspec(dllexport) , 而 不 再 用 _export 修 饰 字 。
_declspec(dllexport)在 C 调用约定、C 编译情况下可以去掉输出函数名的下划线前缀。extern
〃C〃使得在 C++ 中使用 C 编译方式成为可能,在一个 C++文件中,用 extern 〃C〃来指明该函数
使用 C 编译方式。例如,在一个 C++文件中,有如下函数:
extern 〃C〃 {void __declspec(dllexport) __cdecl Test(int var);}
其输出函数名为 Test 。
为了方便,可以使用下列预处理语句:
#if defined(__cplusplus)
extern 〃C〃
{
#endif
// 函数原型说明
#if defined(__cplusplus)
·263 ·
…………………………………………………………Page 275……………………………………………………………
Visual C++ 6。0 程序设计从入门到精通
}
#endif
经过上面的特殊处理,不管在 C 中,还是在 C++ 中都可以得到一个无任何修饰的函数名。
如果不用_declspec(dllexport)修饰字输出函数,而用 DEF 文件来输出函数。将要输出的
函数修饰名罗列在 EXPORTS 之下,这个名字必须与定义函数的名字完全一致,如此就得到
一个没有任何修饰的函数名了。
10。4。4 模块定义文件(DEF 文件)
模块定义文件(DEF )是一个或多个用于描述 DLL 属性的模块语句组成的文本文件,每
个 DEF 文件至少必须包含以下模块定义语句。
o 第一个语句必须是 LIBRARY 语句,指出 DLL 的名字;
o EXPORTS 语句列出被导出函数的名字 ;将要输出的函数修饰名罗列在 EXPORTS 下,
这个名字必须与定义函数的名字完全一致,如此就得到一个没有任何修饰的函数名。
o 可以使用 DEs criptION 语句描述 DLL 的用途(此句可选);
o 〃;〃对一行进行注释(可选 )。
10。5 动态链接库中的资源
利用 Visual C++工具能够创建基于 MFC 的常规/扩张动态链接库,这种形式的动态链接
库可以方便地添加资源 。应用程序在调用 DLL 的时候可以很方便地使用其中的资源,这在很
大程度上方便了应用程序的编写。为了使读者理解在动态链接库中使用资源的方法,本节将
通过在动态链接库中添加对话框资源来介绍使用资源的具体过程。
实例 10…1:动态链接库中使用资源实例。源代码在光盘中“10实例 10…1vcDlgDLL”目录下。
为了能够在动态链接库中方便地使用资源,可以先创建一个“MFC AppWizard(dll) ”工
程,如图 10…4 所示。然后选择“Regular Dll using shared MFC DLL ”项,单击“Finish ”按钮
即可生成动态链接库。
图 10…4 生成 Regular Dll using shared MFC DLL
·264 ·
…………………………………………………………Page 276……………………………………………………………
第 10 章 动态链接库
添加一个对话框资源到工程中,从菜单中依次选择“Insert ”→“Resource ”项,添加“Dialog ”
选择“New ”项,至此对话框已添加到 DLL 工程中。
为对话框添加 CTest 类,基类为 CDialog 。同时在 MFCDLL。cpp 中( 因创建的工程为
MFCDLL)添加测试接口函数如下:
extern 〃C〃 __declspec(dllexport) void Show()
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
CTest test;
test。DoModal ();
}
静态连接到 MFC 的动态链接库只被 Visual C++ 的专业版和企业版所支持。该类 DLL 应
用程序里头的输出函数可以被任意的 Win32 程序使用,包括使用 MFC 的应用程序。输入函
数有如下形式:
extern 〃C〃 EXPORT YourExportedFunction();
如果没有 extern 〃C〃修饰,输出函数仅仅能从 C++代码中调用。
DLL 应用程序从 CWinApp 派生,但没有消息循环。
动态链接到 MFC 的规则 DLL 应用程序里头的输出函数可以被任意 Win32 程序使用,包
括使用 MFC 的应用程序。但是,所有从 DLL 输出的函数应该以如下语句开始:
AFX_MANAGE_STATE(AfxGetStaticModuleState())
此语句用来正确地切换 MFC 模块状态。
因为一般在动态链接库中使用嵌入资源是通过动态链接的,所以测试接口函数作了上述
程序片断的声明和定义。
在要输出的函数、类、数据的声明前加上_declspec(dllexport) 的修饰符,表示输出。
_declspec(dllexport)在 C 调用约定、C 编译情况下可以去掉输出函数名的下划线前缀。extern
〃C〃使得在 C++ 中使用 C 编译方式成为可能。在“C++ ”下定义〃C〃函数,需要加 extern 〃C〃
关键词。用 extern 〃C〃来指明该函数使用 C 编译方式。输出的〃C〃函数可以从〃C〃代码里调用。
下面以具体示例作详细介绍。在一个 C++文件中,有如下函数:
extern 〃C〃 {void __declspec(dllexport) __cdecl Test(int var);}
其输出函数名为 Test 。
MFC 提供了一些宏,就有这样的作用。代码如下:
AFX_CLASS_IMPORT :__declspec(dllexport)
AFX_API_IMPORT :__declspec(dllexport)
AFX_DATA_IMPORT :__declspec(dllexport)
AFX_CLASS_EXPORT :__declspec(dllexport)
AFX_API_EXPORT :__declspec(dllexport)
AFX_DATA_EXPORT :__declspec(dllexport)
AFX_EXT_CLASS : #ifdef _AFXEXT
AFX_CLASS_EXPORT
#else
·265 ·
…………………………………………………………Page 277……………………………………………………………
Visual C++ 6。0 程序设计从入门到精通
AFX_CLASS_IMPORT
AFX_EXT_API :#ifdef _AFXEXT
AFX_API_EXPORT
#else
AFX_API_IMPORT
AFX_EXT_DATA :#ifdef _AFXEXT
AFX_DATA_EXPORT
#else
AFX_DATA_IMPORT
像 AFX_EXT_CLASS 这样的宏,如果用于 DLL 应用程序的实现,则表示输出(因为
_AFX_EXT 被定义,通常是在编译器的标识参数中指定该选项/D_AFX_EXT )。如果用于使
用 DLL 的应用程序中,则表示输入(_AFX_EXT 没有定义)。
要输出整个的类,对类使用_declspec(_dllexpot) ;要输出类的成员函数,则对该函数使用
_declspec(_dllexport) 。代码如下:
class AFX_EXT_CLASS CTextDoc : public CDocument
{
…
}
extern 〃C〃 AFX_EXT_API void WINAPI InitMYDLL();
为了调用动态链接库的资源,新建了一个基于对话框的 MFC 应用程序测试函数接口,
测试的主要代码如下:
void CTestDlg::OnOK()
{
// TODO: Add extra validation here
typedef void (WINAPI * TESTDLL)(); //定义函数指针类型 TESTDLL
HINSTANCE hmod; //动态链接库实例句柄
hmod = ::LoadLibrary (〃mfcdll。dll〃); //加载 mfcdll。dll 动态链接库
if(hmod==NULL)
{
AfxMessageBox(〃Fail〃); //如果加载动态链接库失败
}
TESTDLL lpproc; //定义接收导出函数的函数指针 lpproc
lpproc = (TESTDLL)GetProcAddress (hmod;〃Show〃); //得到导出函数 Show 的地址
if(lpproc!=(TESTDLL)NULL) // 当成功得到导出函数地址的时候
(*lpproc)(); //执行动态链接库中的导出函数
FreeLibrary(hmod); //释放动态链接库资源
·266 ·
…………………………………………………………Page 278……………………………………………………………
第 10 章 动态链接库
// CDialog::OnOK();
}
执行的结果如图 10…5 所示。从图中可以看出,可执行程序成功地调用了动态链接库中的
对话框资源。
图 10…5 调用 DLL 中的对话框资源
10。6 界面汉化示例
在 Windows 系统中,应用程序开发者可以通过利用动态链接库,用一套源代码来支持多
种文字。本节将通过一个界面汉化的示例来演示动态链接库中资源的应用方法。
利用 Visual C++编程,可以把所有的可见资源封装在一个资源动态链接库中,以简化本
地化工作。一般情况下,资源包含在应用程序中,但也可以通过调用 AfxSetResourceHandle
函数指向一个不同的单元以完成资源的引用。本例就是首先调用该函数从动态链接库中采集
到所有的应用程序可用资源,然后通过调用 GetSystemDefaultLangID 函数判断系统默认语种,
以载入不同语种的资源动态链接库实现界面与系统的自动适应。
实例 10…2: