VC6动态链接库之MFC规则介绍

转自:http://www.a3gs.com/BookViews.asp?InfoID=2840&classID=819&InfoType=0

描述

本文讲述了MFC规则动态链接库相关原理及使用方法

技术实现

我们知道VC6中的动态链接库分非MFC动态链接库、MFC规则动态链接库、MFC扩展动态链接库;上一章中我们以例子的形式介绍了非MFC动态链接库的实现方法、使用方式及应该注意的地方等,在这一节中我们将对MFC规则动态链接库进行介绍。


1 MFC规则动态链接库

1.1 概述

MFC规则动态链接库(MFC Regular DLL),顾名思义其包含两个方面的做含义(MFC与规则);所谓“MFC”意味着可以在这种DLL的内部使用MFC,而所谓的“规则”则意味着它不同于MFC扩展动态链接库,在MFC规则动态链接库的内部虽然可以使用MFC,但是其与应用程序的接口不能是MFC。而MFC扩展动态链接库与应用程序的接口可以是MFC,可以从MFC扩展动态链接库中导出一个MFC类的派生类。

MFC规则动态链接库能够被所有支持DLL技术的语言所编写的应用程序调用,当然也包括使用MFC的应用程序。在这种动态连接库中,包含一个从CWinApp继承下来的类,DllMain函数则由MFC自动提供。

MFC规则动态链接库分为两类:静态链接到MFC 的规则动态库(Regular DLL with MFC statically linked)与动态链接到MFC 的规则动态库(Regular DLL using shared MFC DLL);到底使用那一种可以在创建工程时选择,也可以在工程生成之后对工程进行修改。

两类MFC规则动态链接库的区别如下:

Ø Regular DLL with MFC statically linked

静态链接到MFC的规则DLLMFC库(包括MFC扩展 DLL)静态链接,将MFC库的代码直接生成在.dll文件中。在调用这种DLL的接口时,MFC使用DLL的资源。因此,在静态链接到MFC 的规则DLL中不需要进行模块状态的切换。

使用这种方法生成的规则DLL其程序较大,也可能包含重复的代码;但其好处是在使用中就无需MFC的相关DLL了。

Ø Regular DLL using shared MFC DLL

动态链接到MFC 的规则DLL 可以和使用它的可执行文件同时动态链接到 MFC DLL 和任何MFC扩展 DLL。在使用了MFC共享库的时候,默认情况下,MFC使用主应用程序的资源句柄来加载资源模板。这样,当DLL和应用程序中存在相同ID的资源时(即所谓的资源重复问题),系统可能不能获得正确的资源。因此,对于共享MFC DLL的规则DLL,我们必须进行模块切换以使得MFC能够找到正确的资源模板。

注:如果工程已经创建我们可以在Visual C++中设置MFC规则DLL是静态链接到MFC DLL还是动态链接到MFC DLL。依次选择Visual C++project -> Settings -> General菜单或选项,在Microsoft Foundation Classes中进行设置,当然也可以在创建工程时进行选择。


1.2 一个简单的MFC规则DLL

在这里我们以一个简单的例子说明MFC规则动态库的创建方法,从上面一节中我们知道MFC规则动态库分成Regular DLL with MFC statically linkedRegular DLL using shared MFC DLL由于后一种在开发及使用过程中所涉及的注意点相对多一些,所以在这一小节中我们以Regular DLL with MFC statically linked类型创建一个简单的MFC规则动态库。

运行VC6,选择FileàNew…,在弹出的New对话框中选择Projects选项卡,在项目类型列表中选择MFC AppWizard(dll),在Project name输入框中输入项目名称(如本例取SMFCRegDll),在Location输入框中输入创建工程的位置,点击OK按钮,弹出MFC AppWizard Step 1 of 1对话框。

在所弹出的MFC AppWizard Step 1 of 1对话框中的What kind of DLL would you like to create?中选择Regular DLL with MFC statically linked,别的都保持默认值,点击Finish按钮,在弹出的New Project Informaction对话框中点击OK

OK,现在一个MFC规则动态链接库的框架已经完成,接下来就是添加我们自己的价值代码的时候了;不急,让我们先来看看Class Wizard到底为我们生成了那些东东;在workspace中我先来看看ClassView,发现里面有一个CSMFCRegDllApp类、一个全局的CSMFCRegDllApp实例theApp,其中CSMFCRegDllApp继承了CwinApp;再来看看ResouceView,发现里面只有一个Version;而FileView中的Resource Files中有SMFCRegDll.rc2Header Files中有Resource.hSMFCRegDll.hStdAfx.h,在Source Files中有SMFCRegDll.cppSMFCRegDll.defSMFCRegDll.rcStdAfx.cpp;你看看MFC就为我们生成了这些东东,这些简单的东东我想就不用多讲了吧;接下来我们就来创建一个对话框类吧。

选择InsertàResource,在弹出的Inert Resource对话框中的Resource types中选择Dialog,然后点击NewOK一个对话框资源已经出现在我们的工程中了;现在你想把对话框改成什么样子由你自己高兴啦,反正这和平常的对话框程序开发没什么两样。

现以到了该为我们的对话框资源添加类的时候了;选择InsertàNew Class…,在弹出的New Class对话框中的Class type下拉框中选择MFC Class,在Class informaction中的Name输入框中输入所要创建的类名(本例子中取CMyTestDialog),在Class informaction中的Base class下拉框中选择Cdialog,在Class informaction中的Dialog ID中选择我们刚才所添加的对话框资源ID(本例中IDD_DIALOG1),别的都保持默认,点击OK

OK,现在一个测试用的简单对话框类已经生成,接下来你爱给这几个按钮添加什么处理函数那就由你的高兴啦(这和平常的对话框程序没什么区别)。

接下来我们就来写一个函数让应用程序调用,而此函数就是简单的把我们刚才所创建的对话框弹出来;函数代码如下:

extern "C" __declspec(dllexport) void ShowDlg(void)

{

CMyTestDialog dllDialog;

dllDialog.DoModal();

}

注:在这里我们是采用直接导出的方式,当然你也可以在Def文件中导出;还有就是这个函数写在那里都行,只要你能用到CmyTestDialog既可。


1.3 MFC规则动态库的调用

调用MFC规则动态库与调用非MFC动态链接库没什么区别,在这里我们就不再多说了,例如我们中以采用动态库的静态加载形式,例如如下:

#pragma comment(lib,"..//Debug//SMFCRegDll.lib")

extern "C" __declspec(dllimport) void ShowDlg();

void CTestDlg::OnButton1()

{

// TODO: Add your control notification handler code here

ShowDlg();

}

你看看我说的没错吧,和非MFC动态库的调用一模一样!


1.4 共享MFC DLL的规则动态库

从上面的介绍中我们知道MFC规则动态链接库分为两类:静态链接到MFC 的规则动态库(Regular DLL with MFC statically linked)与动态链接到MFC 的规则动态库(Regular DLL using shared MFC DLL);上面我们讲述了Regular DLL with MFC statically linked类型,下面我们就来谈谈Regular DLL using shared MFC DLL

对于Regular DLL using shared MFC DLL我们就不现举例子说明了,只是谈一谈这种类型规则动态库应该注意的要点。

我们知道应用程序进程本身及其调用的每个DLL模块都具有一个全局唯一的HINSTANCE句柄,它们代表了DLLEXE模块在进程虚拟空间中的起始地址。进程本身的模块句柄一般为0x400000,而DLL模块的缺省句柄为0x10000000。如果程序同时加载了多个DLL,则每个DLL模块都会有不同的HINSTANCE。应用程序在加载DLL时对其进行了重定位。

共享MFC DLL(或MFC扩展DLL)的规则DLL涉及到HINSTANCE句柄问题,HINSTANCE句柄对于加载资源特别重要。EXEDLL都有其自己的资源,而且这些资源的ID可能重复,应用程序需要通过资源模块的切换来找到正确的资源。如果应用程序需要来自于DLL的资源,就应将资源模块句柄指定为DLL的模块句柄;如果需要EXE文件中包含的资源,就应将资源模块句柄指定为EXE的模块句柄。

假设我们把上的例子工程SMFCRegDll的类型改成Regular DLL using shared MFC DLL将会出现什么要的结果呢?当我们用一个对话框程序去测试调用ShowDlg函数时可能出现的情况有两种,第一种就是弹出的对话框和调用此函数的对话框是同一个对话框,第二种情况就是根本就不会弹出对话框!

哈哈,这回怪事出现了吧,其实从上面的分析中这也不是什么怪事;产生这个问题的根源在于应用程序与MFC规则DLL共享MFC DLL(或MFC扩展DLL)的程序总是默认使用EXE的资源,我们必须进行资源模块句柄的切换,其实现方法有三:

Ø 方法一

DLL接口函数中使用AFX_MANAGE_STATE(AfxGetStaticModuleState());我们将DLL中的接口函数ShowDlg改为:

extern "C" __declspec(dllexport) void ShowDlg(void)

{

AFX_MANAGE_STATE(AfxGetStaticModuleState());

CMyTestDialog dllDialog;

dllDialog.DoModal();

}

注:AfxGetStaticModuleState是一个函数,其原型为:AFX_MODULE_STATE* AFXAPI AfxGetStaticModuleState( ); 该函数的功能是在栈上(这意味着其作用域是局部的)创建一个AFX_MODULE_STATE类(模块全局数据也就是模块状态)的实例,对其进行设置,并将其指针pModuleState返回。

AFX_MODULE_STATE类利用其构造函数和析构函数进行存储模块状态现场及恢复现场的工作,类似汇编中call指令对pc指针和sp寄存器的保存与恢复、中断服务程序的中断现场压栈与恢复以及操作系统线程调度的任务控制块保存与恢复。

Ø 方法二

DLL接口函数中使用AfxGetResourceHandle(); AfxSetResourceHandle(HINSTANCE xxx);其中AfxGetResourceHandle用于, 获取当前资源模块句柄,而AfxSetResourceHa, ndle则用于设置程序目前要使用的资源模块句柄。

我们将DLL中的接口函数ShowDlg改为:

extern "C" __declspec(dllexport) void ShowDlg(void)

{

HINSTANCE save_hInstance = AfxGetResourceHandle();

AfxSetResourceHandle(theApp.m_hInstance);

CMyTestDialog dllDialog;

dllDialog.DoModal();

AfxSetResourceHandle(save_hInstance);

}

Ø 方法三

由应用程序自身切换;资源模块的切换除了可以由DLL接口函数完成以外,由应用程序自身也能完成。现在我们把DLL中的接口函数改为最初的样子既:

extern "C" __declspec(dllexport) void ShowDlg(void)

{

CMyTestDialog dllDialog;

dllDialog.DoModal();

}

此时我们把相应的调用函数改成如下:

void CVvvvDlg::OnButton1()

{

HINSTANCE exe_hInstance = GetModuleHandle(NULL);

HINSTANCE dll_hInstance = GetModuleHandle("../Debug/ SMFCRegDll.dll");

AfxSetResourceHandle(dll_hInstance); //切换状态

ShowDlg(); //此时显示的是DLL的对话框

AfxSetResourceHandle(exe_hInstance); //恢复状态

//资源模块恢复后再调用ShowDlg

ShowDlg(); //此时显示的是EXE的对话框

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值