第 55 章
下,
这个名字必须与定义函数的名字完全一致,如此就得到一个没有任何修饰的函数名。
? 可以使用DEs criptION 语句描述DLL 的用途(此句可选);
? ";"对一行进行注释(可选)。
10.5 动态链接库中的资源
利用Visual C++工具能够创建基于MFC 的常规/扩张动态链接库,这种形式的动态链接
库可以方便地添加资源。应用程序在调用DLL 的时候可以很方便地使用其中的资源,这在很
大程度上方便了应用程序的编写。为了使读者理解在动态链接库中使用资源的方法,本节将
通过在动态链接库中添加对话框资源来介绍使用资源的具体过程。
实例10-1:动态链接库中使用资源实例。源代码在光盘中“\10\实例10-1\vcDlgDLL”目录下。
为了能够在动态链接库中方便地使用资源,可以先创建一个“MFC AppWizard(dll)”工
程,如图10-4 所示。然后选择“Regular Dll using shared MFC DLL”项,单击“Finish”按钮
即可生成动态链接库。
图10-4 生成Regular Dll using shared MFC DLL
枫叶文学网www.fywxw.com
第10 章 动态链接库
·265·
添加一个对话框资源到工程中,从菜单中依次选择“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
枫叶文学网www.fywxw.com
Visual C++ 6.0 程序设计从入门到精通
·266·
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 CDoccomnt
{
?
}
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); //释放动态链接库资源
枫叶文学网www.fywxw.com
第10 章 动态链接库
·267·
// CDialog::OnOK();
}
执行的结果如图10-5 所示。从图中可以看出,可执行程序成功地调用了动态链接库中的
对话框资源。
图10-5 调用DLL 中的对话框资源
10.6 界面汉化示例
在Windows 系统中,应用程序开发者可以通过利用动态链接库,用一套源代码来支持多
种文字。本节将通过一个界面汉化的示例来演示动态链接库中资源的应用方法。
利用Visual C++编程,可以把所有的可见资源封装在一个资源动态链接库中,以简化本
地化工作。一般情况下,资源包含在应用程序中,但也可以通过调用AfxSetResourceHandle
函数指向一个不同的单元以完成资源的引用。本例就是首先调用该函数从动态链接库中采集
到所有的应用程序可用资源,然后通过调用GetSystemDefaultLangID 函数判断系统默认语种,
以载入不同语种的资源动态链接库实现界面与系统的自动适应。
实例10-2:界面汉化实例。源代码在光盘中“\10\实例10-2”目录下。
本节以创建一个默认语种为简体中文的Languages 应用程序为例,进一步详细说明。该
程序不含任何资源,应用程序根据系统的语种设置连接对应的资源链接库,以完成对中文和
英文两种语言的支持。
附带光盘中的chinese.dll 和english.dll 两个动态链接库分别封装了中文资源和英文资源,
下面具体介绍Languages 应用程序的实现过程。
1.创建Languages
用MFC AppWizad(exe)创建新项目的工作区,选择Simple Doccomnt 类型、中国中文(其
他的选项选择默认),并且为了明确,将工作区目录改为“多语种支持”。
2.添加数据成员
由于要动态地装入资源链接库,所以需要保存链接库的句柄以便在程序结束的时候释放
枫叶文学网www.fywxw.com
Visual C++ 6.0 程序设计从入门到精通
·268·
资源。将下述数据成员添加到CLanguagesApp 类中,代码如下:
protected:
//资源链接库句柄
HINSTANCE m_hLangDLL;
3.修改InitInstance()函数
应用程序需要判别系统的默认语种,并装入对应的资源链接库。将下面的代码加到
InitInstance 函数中,代码如下:
BOOL CLanguagesApp::InitInstance()
{
AfxEnableControlContainer();
// 判定系统默认语种
WORD wLangPID=PRIMARYLANGID(::GetSystemDefaultLangID());
// 载入资源动态链接库
switch( wLangPID)
{
case LANG_CHINESE:
m_hLangDLL=::LoadLibrary("chinese.dll");
break ;
default:
m_hLangDLL=::LoadLibrary("english.dll");
break;
}
if(!m_hLangDLL)
{
AfxMessageBox(_T("无法装载资源链接库!")) ;
return FALSE ;
}
// 连接资源
AfxSetResourceHandle(m_hLangDLL) ;
??
}
其中,cāo作系统所使用的默认语种由Win 32 函数GetSystemDefaultLangID 取得。宏
PRIMARYLANGID 取出主语言标识符进行判断,以正确选择应该调用的链接库。链接库的
加载由Win32 函数LoadLibrary 实现。程序中所使用的资源库由AfxSetResourceHandle 函数
指定。
4.处理ExitInstance()函数
程序退出时使用Win 32 函数FreeLibrary 卸载已经装入的动态链接库。将下列代码添加
到ExitInstance 函数中,代码如下:
枫叶文学网www.fywxw.com
第10 章 动态链接库
·269·
int CLanguagesApp::ExitInstance()
{
//释放资源链接库
if(m_hLangDLL)
AfxFreeLibrary(m_hLangDLL);
return CWinApp::ExitInstance();
}
5.修改OnDraw
为了说明是从资源链接库中动态地获取数据而不是从程序的执行体中获取,该程序从资
源链接库中获取了一个字符串,并绘制在屏幕上。代码如下:
void CLanguagesView::OnDraw(CDC* pDC)
{
CLanguagesDoc* pDoc = GetDoccomnt();
ASSERT_VALID(pDoc);
CString strMsg;
strMsg.LoadString(IDS_HELLO);
pDC->TextOut(60,15,strMsg);
// TODO: add draw code for native data here
}
6.从项目中移走Languages.rc 文件
因为Languages 自身并不需要含有任何资源,所以可以从项目列表文件中移走
Languages.rc 文件(并不删除)。ClassWizad 不允许项目不包含资源文件,可以创建一个空资
源文件并将其加入到项目中,然后重建信息文件(Languages.CLW),使得ClassWizad 可以继
续管理程序的消息处理。但在本例中所有的函数都已经加入,可不必为项目创建空资源文件。
7.建立项目
修改设置, 选择“Project| Setting ? ” 菜单命令, 在Link 标签下将输出文件名
\Debug\Languages.exe 改为Languages.exe。编译项目,如果应用程序中没有任何资源,会出
现找不到资源链接库的错误,下面的一系列步骤为本项目分别创建简体中文和美国英语的资
源链接库。在这两个链接库
松语文学免费小说阅读_www.16sy.com
这个名字必须与定义函数的名字完全一致,如此就得到一个没有任何修饰的函数名。
? 可以使用DEs criptION 语句描述DLL 的用途(此句可选);
? ";"对一行进行注释(可选)。
10.5 动态链接库中的资源
利用Visual C++工具能够创建基于MFC 的常规/扩张动态链接库,这种形式的动态链接
库可以方便地添加资源。应用程序在调用DLL 的时候可以很方便地使用其中的资源,这在很
大程度上方便了应用程序的编写。为了使读者理解在动态链接库中使用资源的方法,本节将
通过在动态链接库中添加对话框资源来介绍使用资源的具体过程。
实例10-1:动态链接库中使用资源实例。源代码在光盘中“\10\实例10-1\vcDlgDLL”目录下。
为了能够在动态链接库中方便地使用资源,可以先创建一个“MFC AppWizard(dll)”工
程,如图10-4 所示。然后选择“Regular Dll using shared MFC DLL”项,单击“Finish”按钮
即可生成动态链接库。
图10-4 生成Regular Dll using shared MFC DLL
枫叶文学网www.fywxw.com
第10 章 动态链接库
·265·
添加一个对话框资源到工程中,从菜单中依次选择“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
枫叶文学网www.fywxw.com
Visual C++ 6.0 程序设计从入门到精通
·266·
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 CDoccomnt
{
?
}
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); //释放动态链接库资源
枫叶文学网www.fywxw.com
第10 章 动态链接库
·267·
// CDialog::OnOK();
}
执行的结果如图10-5 所示。从图中可以看出,可执行程序成功地调用了动态链接库中的
对话框资源。
图10-5 调用DLL 中的对话框资源
10.6 界面汉化示例
在Windows 系统中,应用程序开发者可以通过利用动态链接库,用一套源代码来支持多
种文字。本节将通过一个界面汉化的示例来演示动态链接库中资源的应用方法。
利用Visual C++编程,可以把所有的可见资源封装在一个资源动态链接库中,以简化本
地化工作。一般情况下,资源包含在应用程序中,但也可以通过调用AfxSetResourceHandle
函数指向一个不同的单元以完成资源的引用。本例就是首先调用该函数从动态链接库中采集
到所有的应用程序可用资源,然后通过调用GetSystemDefaultLangID 函数判断系统默认语种,
以载入不同语种的资源动态链接库实现界面与系统的自动适应。
实例10-2:界面汉化实例。源代码在光盘中“\10\实例10-2”目录下。
本节以创建一个默认语种为简体中文的Languages 应用程序为例,进一步详细说明。该
程序不含任何资源,应用程序根据系统的语种设置连接对应的资源链接库,以完成对中文和
英文两种语言的支持。
附带光盘中的chinese.dll 和english.dll 两个动态链接库分别封装了中文资源和英文资源,
下面具体介绍Languages 应用程序的实现过程。
1.创建Languages
用MFC AppWizad(exe)创建新项目的工作区,选择Simple Doccomnt 类型、中国中文(其
他的选项选择默认),并且为了明确,将工作区目录改为“多语种支持”。
2.添加数据成员
由于要动态地装入资源链接库,所以需要保存链接库的句柄以便在程序结束的时候释放
枫叶文学网www.fywxw.com
Visual C++ 6.0 程序设计从入门到精通
·268·
资源。将下述数据成员添加到CLanguagesApp 类中,代码如下:
protected:
//资源链接库句柄
HINSTANCE m_hLangDLL;
3.修改InitInstance()函数
应用程序需要判别系统的默认语种,并装入对应的资源链接库。将下面的代码加到
InitInstance 函数中,代码如下:
BOOL CLanguagesApp::InitInstance()
{
AfxEnableControlContainer();
// 判定系统默认语种
WORD wLangPID=PRIMARYLANGID(::GetSystemDefaultLangID());
// 载入资源动态链接库
switch( wLangPID)
{
case LANG_CHINESE:
m_hLangDLL=::LoadLibrary("chinese.dll");
break ;
default:
m_hLangDLL=::LoadLibrary("english.dll");
break;
}
if(!m_hLangDLL)
{
AfxMessageBox(_T("无法装载资源链接库!")) ;
return FALSE ;
}
// 连接资源
AfxSetResourceHandle(m_hLangDLL) ;
??
}
其中,cāo作系统所使用的默认语种由Win 32 函数GetSystemDefaultLangID 取得。宏
PRIMARYLANGID 取出主语言标识符进行判断,以正确选择应该调用的链接库。链接库的
加载由Win32 函数LoadLibrary 实现。程序中所使用的资源库由AfxSetResourceHandle 函数
指定。
4.处理ExitInstance()函数
程序退出时使用Win 32 函数FreeLibrary 卸载已经装入的动态链接库。将下列代码添加
到ExitInstance 函数中,代码如下:
枫叶文学网www.fywxw.com
第10 章 动态链接库
·269·
int CLanguagesApp::ExitInstance()
{
//释放资源链接库
if(m_hLangDLL)
AfxFreeLibrary(m_hLangDLL);
return CWinApp::ExitInstance();
}
5.修改OnDraw
为了说明是从资源链接库中动态地获取数据而不是从程序的执行体中获取,该程序从资
源链接库中获取了一个字符串,并绘制在屏幕上。代码如下:
void CLanguagesView::OnDraw(CDC* pDC)
{
CLanguagesDoc* pDoc = GetDoccomnt();
ASSERT_VALID(pDoc);
CString strMsg;
strMsg.LoadString(IDS_HELLO);
pDC->TextOut(60,15,strMsg);
// TODO: add draw code for native data here
}
6.从项目中移走Languages.rc 文件
因为Languages 自身并不需要含有任何资源,所以可以从项目列表文件中移走
Languages.rc 文件(并不删除)。ClassWizad 不允许项目不包含资源文件,可以创建一个空资
源文件并将其加入到项目中,然后重建信息文件(Languages.CLW),使得ClassWizad 可以继
续管理程序的消息处理。但在本例中所有的函数都已经加入,可不必为项目创建空资源文件。
7.建立项目
修改设置, 选择“Project| Setting ? ” 菜单命令, 在Link 标签下将输出文件名
\Debug\Languages.exe 改为Languages.exe。编译项目,如果应用程序中没有任何资源,会出
现找不到资源链接库的错误,下面的一系列步骤为本项目分别创建简体中文和美国英语的资
源链接库。在这两个链接库
松语文学免费小说阅读_www.16sy.com