动态链接库DLL编程深入浅出3Word格式.docx

上传人:b****4 文档编号:7032174 上传时间:2023-05-07 格式:DOCX 页数:16 大小:212.28KB
下载 相关 举报
动态链接库DLL编程深入浅出3Word格式.docx_第1页
第1页 / 共16页
动态链接库DLL编程深入浅出3Word格式.docx_第2页
第2页 / 共16页
动态链接库DLL编程深入浅出3Word格式.docx_第3页
第3页 / 共16页
动态链接库DLL编程深入浅出3Word格式.docx_第4页
第4页 / 共16页
动态链接库DLL编程深入浅出3Word格式.docx_第5页
第5页 / 共16页
动态链接库DLL编程深入浅出3Word格式.docx_第6页
第6页 / 共16页
动态链接库DLL编程深入浅出3Word格式.docx_第7页
第7页 / 共16页
动态链接库DLL编程深入浅出3Word格式.docx_第8页
第8页 / 共16页
动态链接库DLL编程深入浅出3Word格式.docx_第9页
第9页 / 共16页
动态链接库DLL编程深入浅出3Word格式.docx_第10页
第10页 / 共16页
动态链接库DLL编程深入浅出3Word格式.docx_第11页
第11页 / 共16页
动态链接库DLL编程深入浅出3Word格式.docx_第12页
第12页 / 共16页
动态链接库DLL编程深入浅出3Word格式.docx_第13页
第13页 / 共16页
动态链接库DLL编程深入浅出3Word格式.docx_第14页
第14页 / 共16页
动态链接库DLL编程深入浅出3Word格式.docx_第15页
第15页 / 共16页
动态链接库DLL编程深入浅出3Word格式.docx_第16页
第16页 / 共16页
亲,该文档总共16页,全部预览完了,如果喜欢就下载吧!
下载资源
资源描述

动态链接库DLL编程深入浅出3Word格式.docx

《动态链接库DLL编程深入浅出3Word格式.docx》由会员分享,可在线阅读,更多相关《动态链接库DLL编程深入浅出3Word格式.docx(16页珍藏版)》请在冰点文库上搜索。

动态链接库DLL编程深入浅出3Word格式.docx

我们可以在VisualC++中设置MFC规则DLL是静态链接到MFCDLL还是动态链接到MFCDLL。

如图8,依次选择VisualC++的project->

Settings->

General菜单或选项,在MicrosoftFoundationClasses中进行设置。

图8设置动态/静态链接MFCDLL

  5.2MFC规则DLL的创建

  我们来一步步讲述使用MFC向导创建MFC规则DLL的过程,首先新建一个project,如图9,选择project的类型为MFCAppWizard(dll)。

点击OK进入如图10所示的对话框。

图9MFCDLL工程的创建

  图10所示对话框中的1区选择MFCDLL的类别。

  2区选择是否支持automation(自动化)技术,automation允许用户在一个应用程序中操纵另外一个应用程序或组件。

例如,我们可以在应用程序中利用MicrosoftWord或MicrosoftExcel的工具,而这种使用对用户而言是透明的。

自动化技术可以大大简化和加快应用程序的开发。

  3区选择是否支持WindowsSockets,当选择此项目时,应用程序能在TCP/IP网络上进行通信。

CWinApp派生类的InitInstance成员函数会初始化通讯端的支持,同时工程中的StdAfx.h文件会自动include<

AfxSock.h>

头文件。

添加socket通讯支持后的InitInstance成员函数如下:

BOOLCRegularDllSocketApp:

:

InitInstance()

{

if(!

AfxSocketInit())

AfxMessageBox(IDP_SOCKETS_INIT_FAILED);

returnFALSE;

}

returnTRUE;

  4区选择是否由MFC向导自动在源代码中添加注释,一般我们选择“Yes,please”。

图10MFCDLL的创建选项

  5.3一个简单的MFC规则DLL

  这个DLL的例子(属于静态链接到MFC的规则DLL)中提供了一个如图11所示的对话框。

图11MFC规则DLL例子

  在DLL中添加对话框的方式与在MFC应用程序中是一样的。

  在图11所示DLL中的对话框的Hello按钮上点击时将MessageBox一个“Hello,pconline的网友”对话框,下面是相关的文件及源代码,其中删除了MFC向导自动生成的绝大多数注释(下载本工程附件):

第一组文件:

CWinApp继承类的声明与实现

//RegularDll.h:

mainheaderfilefortheREGULARDLLDLL

#if!

defined(AFX_REGULARDLL_H__3E9CB22B_588B_4388_B778_B3416ADB79B3__INCLUDED_)

#defineAFX_REGULARDLL_H__3E9CB22B_588B_4388_B778_B3416ADB79B3__INCLUDED_

#if_MSC_VER>

1000

#pragmaonce

#endif//_MSC_VER>

#ifndef__AFXWIN_H__

#errorinclude'

stdafx.h'

beforeincludingthisfileforPCH

#endif

#include"

resource.h"

//mainsymbols

classCRegularDllApp:

publicCWinApp

public:

CRegularDllApp();

DECLARE_MESSAGE_MAP()

};

#endif

//RegularDll.cpp:

DefinestheinitializationroutinesfortheDLL.

stdafx.h"

RegularDll.h"

#ifdef_DEBUG

#definenewDEBUG_NEW

#undefTHIS_FILE

staticcharTHIS_FILE[]=__FILE__;

BEGIN_MESSAGE_MAP(CRegularDllApp,CWinApp)

END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////

//CRegularDllAppconstruction

CRegularDllApp:

CRegularDllApp()

//TheoneandonlyCRegularDllAppobject

CRegularDllApptheApp;

  分析:

  在这一组文件中定义了一个继承自CWinApp的类CRegularDllApp,并同时定义了其的一个实例theApp。

乍一看,您会以为它是一个MFC应用程序,因为MFC应用程序也包含这样的在工程名后添加“App”组成类名的类(并继承自CWinApp类),也定义了这个类的一个全局实例theApp。

我们知道,在MFC应用程序中CWinApp取代了SDK程序中WinMain的地位,SDK程序WinMain所完成的工作由CWinApp的三个函数完成:

virtualBOOLInitApplication();

virtualBOOLInitInstance();

virtualBOOLRun();

//传说中MFC程序的“活水源头”

  但是MFC规则DLL并不是MFC应用程序,它所继承自CWinApp的类不包含消息循环。

这是因为,MFC规则DLL不包含CWinApp:

Run机制,主消息泵仍然由应用程序拥有。

如果DLL生成无模式对话框或有自己的主框架窗口,则应用程序的主消息泵必须调用从DLL导出的函数来调用PreTranslateMessage成员函数。

  另外,MFC规则DLL与MFC应用程序中一样,需要将所有DLL中元素的初始化放到InitInstance成员函数中。

  第二组文件自定义对话框类声明及实现(点击查看附件)

  这一部分的编程与一般的应用程序根本没有什么不同,我们照样可以利用MFC类向导来自动为对话框上的控件添加事件。

MFC类向导照样会生成类似ON_BN_CLICKED(IDC_HELLO_BUTTON,OnHelloButton)的消息映射宏。

  第三组文件DLL中的资源文件

//{{NO_DEPENDENCIES}}

//MicrosoftDeveloperStudiogeneratedincludefile.

//UsedbyRegularDll.rc

//

#defineIDD_DLL_DIALOG1000

#defineIDC_HELLO_BUTTON1000

  在MFC规则DLL中使用资源也与在MFC应用程序中使用资源没有什么不同,我们照样可以用VisualC++的资源编辑工具进行资源的添加、删除和属性的更改。

  第四组文件MFC规则DLL接口函数

StdAfx.h"

DllDialog.h"

extern"

C"

__declspec(dllexport)voidShowDlg(void)

CDllDialogdllDialog;

dllDialog.DoModal();

  这个接口并不使用MFC,但是在其中却可以调用MFC扩展类CdllDialog的函数,这体现了“规则”的概类。

  与非MFCDLL完全相同,我们可以使用__declspec(dllexport)声明或在.def中引出的方式导出MFC规则DLL中的接口。

5.4MFC规则DLL的调用

  笔者编写了如图12的对话框MFC程序(下载本工程附件)来调用5.3节的MFC规则DLL,在这个程序的对话框上点击“调用DLL”按钮时弹出5.3节MFC规则DLL中的对话框。

图12MFC规则DLL的调用例子

  下面是“调用DLL”按钮单击事件的消息处理函数:

voidCRegularDllCallDlg:

OnCalldllButton()

typedefvoid(*lpFun)(void);

HINSTANCEhDll;

//DLL句柄

hDll=LoadLibrary("

RegularDll.dll"

);

if(NULL==hDll)

MessageBox("

DLL加载失败"

lpFunaddFun;

//函数指针

lpFunpShowDlg=(lpFun)GetProcAddress(hDll,"

ShowDlg"

if(NULL==pShowDlg)

DLL中函数寻找失败"

pShowDlg();

上述例子中给出的是显示调用的方式,可以看出,其调用方式与第4节中非MFCDLL的调用方式没有什么不同。

我们照样可以在EXE程序中隐式调用MFC规则DLL,只需要将DLL工程生成的.lib文件和.dll文件拷入当前工程所在的目录,并在RegularDllCallDlg.cpp文件(图12所示对话框类的实现文件)的顶部添加:

#pragmacomment(lib,"

RegularDll.lib"

voidShowDlg(void);

  并将voidCRegularDllCallDlg:

OnCalldllButton()改为:

ShowDlg();

  5.5共享MFCDLL的规则DLL的模块切换

  应用程序进程本身及其调用的每个DLL模块都具有一个全局唯一的HINSTANCE句柄,它们代表了DLL或EXE模块在进程虚拟空间中的起始地址。

进程本身的模块句柄一般为0x400000,而DLL模块的缺省句柄为0x10000000。

如果程序同时加载了多个DLL,则每个DLL模块都会有不同的HINSTANCE。

应用程序在加载DLL时对其进行了重定位。

  共享MFCDLL(或MFC扩展DLL)的规则DLL涉及到HINSTANCE句柄问题,HINSTANCE句柄对于加载资源特别重要。

EXE和DLL都有其自己的资源,而且这些资源的ID可能重复,应用程序需要通过资源模块的切换来找到正确的资源。

如果应用程序需要来自于DLL的资源,就应将资源模块句柄指定为DLL的模块句柄;

如果需要EXE文件中包含的资源,就应将资源模块句柄指定为EXE的模块句柄。

  这次我们创建一个动态链接到MFCDLL的规则DLL(下载本工程附件),在其中包含如图13的对话框。

图13DLL中的对话框

  另外,在与这个DLL相同的工作区中生成一个基于对话框的MFC程序,其对话框与图12完全一样。

但是在此工程中我们另外添加了一个如图14的对话框。

图14EXE中的对话框

  图13和图14中的对话框除了caption不同(以示区别)以外,其它的都相同。

尤其值得特别注意,在DLL和EXE中我们对图13和图14的对话框使用了相同的资源ID=2000,在DLL和EXE工程的resource.h中分别有如下的宏:

//DLL中对话框的ID

#defineIDD_DLL_DIALOG2000

//EXE中对话框的ID

#defineIDD_EXE_DIALOG2000

  与5.3节静态链接MFCDLL的规则DLL相同,我们还是在规则DLL中定义接口函数ShowDlg,原型如下:

SharedDll.h"

voidShowDlg(void)

{

CDialogdlg(IDD_DLL_DIALOG);

//打开ID为2000的对话框

dlg.DoModal();

  而为应用工程主对话框的“调用DLL”的单击事件添加如下消息处理函数:

voidCSharedDllCallDlg:

  我们以为单击“调用DLL”会弹出如图13所示DLL中的对话框,可是可怕的事情发生了,我们看到是图14所示EXE中的对话框!

  惊讶?

  产生这个问题的根源在于应用程序与MFC规则DLL共享MFCDLL(或MFC扩展DLL)的程序总是默认使用EXE的资源,我们必须进行资源模块句柄的切换,其实现方法有三:

  方法一在DLL接口函数中使用:

AFX_MANAGE_STATE(AfxGetStaticModuleState());

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

//方法1:

在函数开始处变更,在函数结束时恢复

//将AFX_MANAGE_STATE(AfxGetStaticModuleState());

作为接口函数的第一//条语句进行模块状态切换

//打开ID为2000的对话框

  这次我们再点击EXE程序中的“调用DLL”按钮,弹出的是DLL中的如图13的对话框!

嘿嘿,弹出了正确的对话框资源。

AfxGetStaticModuleState是一个函数,其原型为:

AFX_MODULE_STATE*AFXAPIAfxGetStaticModuleState();

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

AFX_MODULE_STATE类的原型如下:

//AFX_MODULE_STATE(globaldataforamodule)

classAFX_MODULE_STATE:

publicCNoTrackObject

#ifdef_AFXDLL

AFX_MODULE_STATE(BOOLbDLL,WNDPROCpfnAfxWndProc,DWORDdwVersion);

AFX_MODULE_STATE(BOOLbDLL,WNDPROCpfnAfxWndProc,DWORDdwVersion,BOOLbSystem);

#else

AFX_MODULE_STATE(BOOLbDLL);

~AFX_MODULE_STATE();

CWinApp*m_pCurrentWinApp;

HINSTANCEm_hCurrentInstanceHandle;

HINSTANCEm_hCurrentResourceHandle;

LPCTSTRm_lpszCurrentAppName;

…//省略后面的部分

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

  许多看似不着边际的知识点居然有惊人的相似!

AFX_MANAGE_STATE是一个宏,其原型为:

AFX_MANAGE_STATE(AFX_MODULE_STATE*pModuleState)

  该宏用于将pModuleState设置为当前的有效模块状态。

当离开该宏的作用域时(也就离开了pModuleState所指向栈上对象的作用域),先前的模块状态将由AFX_MODULE_STATE的析构函数恢复。

  方法二在DLL接口函数中使用:

AfxGetResourceHandle();

AfxSetResourceHandle(HINSTANCExxx);

  AfxGetResourceHandle用于获取当前资源模块句柄,而AfxSetResourceHandle则用于设置程序目前要使用的资源模块句柄。

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

//方法2的状态变更

HINSTANCEsave_hInstance=AfxGetResourceHandle();

AfxSetResourceHandle(theApp.m_hInstance);

//方法2的状态还原

AfxSetResourceHandle(save_hInstance);

  通过AfxGetResourceHandle和AfxSetResourceHandle的合理变更,我们能够灵活地设置程序的资源模块句柄,而方法一则只能在DLL接口函数退出的时候才会恢复模块句柄。

方法二则不同,如果将ShowDlg改为:

externCSharedDllApptheApp;

//需要声明theApp外部全局变量

//使用方法2后在此处再进行操作针对的将是应用程序的资源

CDialogdlg1(IDD_DLL_DIALOG);

dlg1.DoModal();

  在应用程序主对话框的“调用DLL”按钮上点击,将看到两个对话框,相继为DLL中的对话框(图13)和EXE中的对话框(图14)。

方法三由应用程序自身切换

  资源模块的切换除了可以由DLL接口函数完成以外,由应用程序自身也能完成(下载本工程附件)。

  现在我们把DLL中的接口函数改为最简单的:

  而将应用程序的OnCalldllButton函数改为:

//方法3:

由应用程序本身进行状态切换

//获取EXE模块句柄

HINSTANCEexe_hInstance=GetModuleHandle(NULL);

//或者HINSTANCEexe_hInstance=AfxGetResourceHandle();

//获取DLL模块句柄

HINSTANCEdll_hInstance=GetModuleHandle("

SharedDll.dll"

AfxSetResourceHandle(dll_hInstance);

//切换状态

//此时显示的是DLL的对话框

AfxSetResourceHandle(exe_hInstance);

//恢复状态

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

//此时显示的是EXE的对话框

  方法三中的Win32函数GetModuleHandle可以根据DLL的文件名获取DLL的模块句柄。

如果需要得到EXE模块的句柄,则应调用带有Null参数的GetModuleHandle。

  方法三与方法二的不同在于方法三是在应用程序中利用AfxGetResourceHandle和AfxSetResourceHandle进行资源模块句柄切换的。

同样地,在应用程序主对话框的“调用DLL”按钮上点击,也将看到两个对话框,相继为DLL中的对话框(图13)和EXE中的对话框(图14)。

  在下一节我们将对MFC扩展DLL进行详细分析和实例讲解,欢迎您继续关注本系列连载。

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > PPT模板 > 商务科技

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2