⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 vc++动态链接库(dll)编程深入浅出(三).htm

📁 VC++动态链接库编程之基础慨念-与编程讲解深入浅出 对原理不清的同学有一定的帮助
💻 HTM
📖 第 1 页 / 共 4 页
字号:
            href="http://www.study888.com/User/User_Favorite.asp?Action=Add&ChannelID=25&InfoID=125869" 
            target=_blank>加入收藏</A>】【<A 
            href="http://www.study888.com/computer/SendMail.asp?ArticleID=125869" 
            target=_blank>告诉好友</A>】【<A 
            href="http://www.study888.com/computer/Print.asp?ArticleID=125869" 
            target=_blank>打印此文</A>】【<A 
            href="javascript:window.close();">关闭窗口</A>】 </TD></TR><!--文章标题下部广告代码开始-->
        <TR>
          <TD align=middle colSpan=2>
            <SCRIPT src=""></SCRIPT>
          </TD></TR><!--文章标题下部广告代码结束-->
        <TR>
          <TD background=VC++动态链接库(DLL)编程深入浅出(三).files/ad_bx1.gif colSpan=2 
          height=6></TD></TR>
        <TR>
          <TD colSpan=6></TD></TR>
        <TR>
          <TD id=fontzoom style="WORD-BREAK: break-all" vAlign=top colSpan=2 
          height=600>
            <SCRIPT src="VC++动态链接库(DLL)编程深入浅出(三).files/wen-ad-300.js"></SCRIPT>
            第4节我们对非MFC 
            DLL进行了介绍,这一节将详细地讲述MFC规则DLL的创建与使用技巧。<BR><BR>  另外,自从本文开始连载后,收到了一些读者的e-mail。有的读者提出了一些问题,笔者将在本文的最后一次连载中选取其中的典型问题进行解答。由于时间的关系,对于读者朋友的来信,笔者暂时不能一一回复,还望海涵!由于笔者的水平有限,文中难免有错误和纰漏,也热诚欢迎读者朋友不吝指正!<BR><BR><BR>  <STRONG>5. 
            MFC规则DLL</STRONG><BR><BR>  <STRONG>5.1 
            概述</STRONG><BR><BR>  MFC规则DLL的概念体现在两方面:<BR><BR>  (1) 
            它是MFC的<BR><BR>  “是MFC的”意味着可以在这种DLL的内部使用MFC;<BR><BR>  (2) 
            它是规则的<BR><BR>  “是规则的”意味着它不同于MFC扩展DLL,在MFC规则DLL的内部虽然可以使用MFC,但是其与应用程序的接口不能是MFC。而MFC扩展DLL与应用程序的接口可以是MFC,可以从MFC扩展DLL中导出一个MFC类的派生类。<BR><BR>  Regular 
            DLL能够被所有支持DLL技术的语言所编写的应用程序调用,当然也包括使用MFC的应用程序。在这种动态连接库中,包含一个从CWinApp继承下来的类,DllMain函数则由MFC自动提供。<BR><BR>  Regular 
            DLL分为两类:<BR><BR>  (1)静态链接到MFC 
            的规则DLL<BR><BR>  静态链接到MFC的规则DLL与MFC库(包括MFC扩展 
            DLL)静态链接,将MFC库的代码直接生成在.dll文件中。在调用这种DLL的接口时,MFC使用DLL的资源。因此,在静态链接到MFC 
            的规则DLL中不需要进行模块状态的切换。<BR><BR>  使用这种方法生成的规则DLL其程序较大,也可能包含重复的代码。<BR><BR>  (2)动态链接到MFC 
            的规则DLL<BR><BR>  动态链接到MFC 的规则DLL 可以和使用它的可执行文件同时动态链接到 MFC DLL 和任何MFC扩展 
            DLL。在使用了MFC共享库的时候,默认情况下,MFC使用主应用程序的资源句柄来加载资源模板。这样,当DLL和应用程序中存在相同ID的资源时(即所谓的资源重复问题),系统可能不能获得正确的资源。因此,对于共享MFC 
            DLL的规则DLL,我们必须进行模块切换以使得MFC能够找到正确的资源模板。<BR>我们可以在Visual 
            C++中设置MFC规则DLL是静态链接到MFC DLL还是动态链接到MFC DLL。如图8,依次选择Visual C++的project 
            -&gt; Settings -&gt; General菜单或选项,在Microsoft Foundation 
            Classes中进行设置。<BR>
            <P></P>
            <P align=center><IMG alt="" 
            src="VC++动态链接库(DLL)编程深入浅出(三).files/20051121084943348.jpg" 
            border=0></P>
            <P align=center>图8 设置动态/静态链接MFC DLL</P>
            <P>  <STRONG>5.2 
            MFC规则DLL的创建</STRONG><BR><BR>  我们来一步步讲述使用MFC向导创建MFC规则DLL的过程,首先新建一个project,如图9,选择project的类型为MFC 
            AppWizard(dll)。点击OK进入如图10所示的对话框。<BR></P>
            <P align=center><IMG alt="" 
            src="VC++动态链接库(DLL)编程深入浅出(三).files/20051121084944136.jpg" 
            border=0></P>
            <P align=center>图9 MFC DLL工程的创建</P>
            <P>  图10所示对话框中的1区选择MFC DLL的类别。<BR><BR>  2区选择是否支持automation(自动化)技术, 
            automation 允许用户在一个应用程序中操纵另外一个应用程序或组件。例如,我们可以在应用程序中利用 Microsoft Word 
            或Microsoft 
            Excel的工具,而这种使用对用户而言是透明的。自动化技术可以大大简化和加快应用程序的开发。<BR><BR>  3区选择是否支持Windows 
            Sockets,当选择此项目时,应用程序能在 TCP/IP 网络上进行通信。 
            CWinApp派生类的InitInstance成员函数会初始化通讯端的支持,同时工程中的StdAfx.h文件会自动include 
            &lt;AfxSock.h&gt;头文件。<BR>添加socket通讯支持后的InitInstance成员函数如下:<BR></P>
            <P></P>
            <P class=code>BOOL 
            CRegularDllSocketApp::InitInstance()<BR><BR>{<BR><BR>if 
            (!AfxSocketInit())<BR><BR>{<BR><BR>AfxMessageBox(IDP_SOCKETS_INIT_FAILED);<BR><BR>return 
            FALSE;<BR><BR>}<BR><BR><BR>return TRUE;<BR><BR>}</P>
            <P><BR>  4区选择是否由MFC向导自动在源代码中添加注释,一般我们选择“Yes,please”。<BR></P>
            <P align=center><IMG alt="" 
            src="VC++动态链接库(DLL)编程深入浅出(三).files/20051121084944504.jpg" 
            border=0></P>
            <P align=center>图10 MFC DLL的创建选项</P>
            <P>  <STRONG>5.3 一个简单的MFC规则DLL</STRONG><BR><BR>  这个DLL的例子(属于静态链接到MFC 
            的规则DLL)中提供了一个如图11所示的对话框。<BR></P>
            <P align=center><IMG alt="" 
            src="VC++动态链接库(DLL)编程深入浅出(三).files/20051121084944732.jpg" 
            border=0></P>
            <P align=center>图11 MFC规则DLL例子</P>
            <P>  在DLL中添加对话框的方式与在MFC应用程序中是一样的。<BR><BR>  在图11所示DLL中的对话框的Hello按钮上点击时将MessageBox一个“Hello,pconline的网友”对话框,下面是相关的文件及源代码,其中删除了MFC向导自动生成的绝大多数注释</P>
            <P>第一组文件:CWinApp继承类的声明与实现<BR></P>
            <P></P>
            <P class=code>// RegularDll.h : main header file for the REGULARDLL 
            DLL<BR><BR><BR><BR>#if 
            !defined(AFX_REGULARDLL_H__3E9CB22B_588B_4388_B778_B3416ADB79B3__INCLUDED_)<BR><BR>#define 
            AFX_REGULARDLL_H__3E9CB22B_588B_4388_B778_B3416ADB79B3__INCLUDED_<BR><BR><BR><BR>#if 
            _MSC_VER &gt; 1000<BR><BR>#pragma once<BR><BR>#endif // _MSC_VER 
            &gt; 1000<BR><BR><BR><BR>#ifndef __AFXWIN_H__<BR><BR>#error include 
            'stdafx.h' before including this file for 
            PCH<BR><BR>#endif<BR><BR>#include "resource.h" // main 
            symbols<BR><BR><BR><BR>class CRegularDllApp : public 
            CWinApp<BR><BR>{<BR><BR>public:<BR><BR>CRegularDllApp();<BR><BR><BR><BR>DECLARE_MESSAGE_MAP()<BR><BR>};<BR><BR>#endif 
            <BR><BR><BR><BR>// RegularDll.cpp : Defines the initialization 
            routines for the DLL.<BR><BR><BR><BR>#include 
            "stdafx.h"<BR><BR>#include "RegularDll.h"<BR><BR><BR><BR>#ifdef 
            _DEBUG<BR><BR>#define new DEBUG_NEW<BR><BR>#undef 
            THIS_FILE<BR><BR>static char THIS_FILE[] = 
            __FILE__;<BR><BR>#endif<BR><BR><BR><BR>BEGIN_MESSAGE_MAP(CRegularDllApp, 
            CWinApp)<BR><BR>END_MESSAGE_MAP()<BR><BR><BR><BR>/////////////////////////////////////////////////////////////////////////////<BR><BR>// 
            CRegularDllApp 
            construction<BR><BR><BR><BR>CRegularDllApp::CRegularDllApp()<BR><BR>{<BR><BR>}<BR><BR><BR><BR>/////////////////////////////////////////////////////////////////////////////<BR><BR>// 
            The one and only CRegularDllApp object<BR><BR>CRegularDllApp 
            theApp;</P>
            <P><BR>  分析:<BR><BR>  在这一组文件中定义了一个继承自CWinApp的类CRegularDllApp,并同时定义了其的一个实例theApp。乍一看,您会以为它是一个MFC应用程序,因为MFC应用程序也包含这样的在工程名后添加“App”组成类名的类(并继承自CWinApp类),也定义了这个类的一个全局实例theApp。<BR>我们知道,在MFC应用程序中CWinApp取代了SDK程序中WinMain的地位,SDK程序WinMain所完成的工作由CWinApp的三个函数完成:<BR></P>
            <P class=code>virtual BOOL InitApplication( );<BR><BR>virtual BOOL 
            InitInstance( );<BR><BR>virtual BOOL Run( ); //传说中MFC程序的“活水源头”</P>
            <P><BR>  但是MFC规则DLL并不是MFC应用程序,它所继承自CWinApp的类不包含消息循环。这是因为,MFC规则DLL不包含CWinApp::Run机制,主消息泵仍然由应用程序拥有。如果DLL 
            生成无模式对话框或有自己的主框架窗口,则应用程序的主消息泵必须调用从DLL 
            导出的函数来调用PreTranslateMessage成员函数。<BR><BR>  另外,MFC规则DLL与MFC 
            应用程序中一样,需要将所有 DLL中元素的初始化放到InitInstance 成员函数中。<BR><BR>  第二组文件 
            自定义对话框类声明及实现(点击查看<A 
            href="http://www.pconline.com.cn/pcedu/empolder/gj/vc/0509/acc/05-09-22-vc-1.txt"><U><FONT 
            color=#0000ff>附件</FONT></U></A>)<BR><BR>  分析:<BR><BR>  这一部分的编程与一般的应用程序根本没有什么不同,我们照样可以利用MFC类向导来自动为对话框上的控件添加事件。MFC类向导照样会生成类似ON_BN_CLICKED(IDC_HELLO_BUTTON, 
            OnHelloButton)的消息映射宏。<BR><BR>  第三组文件 DLL中的资源文件<BR></P>
            <P class=code>//{{NO_DEPENDENCIES}}<BR><BR>// Microsoft Developer 
            Studio generated include file.<BR><BR>// Used by 
            RegularDll.rc<BR><BR>//<BR><BR>#define IDD_DLL_DIALOG 
            1000<BR><BR>#define IDC_HELLO_BUTTON 1000</P>
            <P><BR>  分析:<BR><BR>  在MFC规则DLL中使用资源也与在MFC应用程序中使用资源没有什么不同,我们照样可以用Visual 
            C++的资源编辑工具进行资源的添加、删除和属性的更改。<BR><BR>  第四组文件 MFC规则DLL接口函数<BR></P>
            <P class=code>#include "StdAfx.h"<BR><BR>#include 
            "DllDialog.h"<BR><BR><BR>extern "C" __declspec(dllexport) void 
            ShowDlg(void) <BR><BR>{<BR><BR>CDllDialog 
            dllDialog;<BR><BR>dllDialog.DoModal();<BR><BR>}</P>
            <P><BR>  分析:<BR><BR>  这个接口并不使用MFC,但是在其中却可以调用MFC扩展类CdllDialog的函数,这体现了“规则”的概类。<BR><BR>  与非MFC 
            DLL完全相同,我们可以使用__declspec(dllexport)声明或在.def中引出的方式导出MFC规则DLL中的接口。<BR><STRONG>5.4 
            MFC规则DLL的调用<BR><BR></STRONG>  笔者编写了如图12的对话框MFC程序(下载本工程<A 
            href="http://www.pconline.com.cn/pcedu/empolder/gj/vc/0509/acc/RegularDllCall.zip"><U><FONT 
            color=#0000ff>附件</FONT></U></A>)来调用5.3节的MFC规则DLL,在这个程序的对话框上点击“调用DLL”按钮时弹出5.3节MFC规则DLL中的对话框。<BR></P>
            <P align=center><IMG alt="" 
            src="VC++动态链接库(DLL)编程深入浅出(三).files/20051121084944904.jpg" 
            border=0></P>
            <P align=center>图12 MFC规则DLL的调用例子</P>
            <P>  下面是“调用DLL”按钮单击事件的消息处理函数:<BR></P>
            <P class=code>void CRegularDllCallDlg::OnCalldllButton() 
            <BR><BR>{<BR><BR>typedef void (*lpFun)(void);<BR><BR><BR>HINSTANCE 
            hDll; //DLL句柄 <BR><BR>hDll = 
            LoadLibrary("RegularDll.dll");<BR><BR>if 
            (NULL==hDll)<BR><BR>{<BR><BR>MessageBox("DLL加载失败");<BR><BR>}<BR><BR><BR><BR>lpFun 
            addFun; //函数指针<BR><BR>lpFun pShowDlg = 
            (lpFun)GetProcAddress(hDll,"ShowDlg");<BR><BR>if 
            (NULL==pShowDlg)<BR><BR>{<BR><BR>MessageBox("DLL中函数寻找失败"); 
            <BR><BR>}<BR><BR>pShowDlg();<BR><BR>}</P>
            <P><BR>  上述例子中给出的是显示调用的方式,可以看出,其调用方式与第4节中非MFC 
            DLL的调用方式没有什么不同。<BR>我们照样可以在EXE程序中隐式调用MFC规则DLL,只需要将DLL工程生成的.lib文件和.dll文件拷入当前工程所在的目录,并在RegularDllCallDlg.cpp文件(图12所示对话框类的实现文件)的顶部添加:<BR></P>
            <P class=code>#pragma comment(lib,"RegularDll.lib")<BR><BR>void 
            ShowDlg(void); </P>
            <P><BR>  并将void CRegularDllCallDlg::OnCalldllButton() 改为:<BR></P>
            <P class=code>void CRegularDllCallDlg::OnCalldllButton() 
            <BR><BR>{<BR><BR>ShowDlg();<BR><BR>}</P>
            <P><BR><BR>  <STRONG>5.5 共享MFC 
            DLL的规则DLL的模块切换</STRONG><BR><BR>  应用程序进程本身及其调用的每个DLL模块都具有一个全局唯一的HINSTANCE句柄,它们代表了DLL或EXE模块在进程虚拟空间中的起始地址。进程本身的模块句柄一般为0x400000,而DLL模块的缺省句柄为0x10000000。如果程序同时加载了多个DLL,则每个DLL模块都会有不同的HINSTANCE。应用程序在加载DLL时对其进行了重定位。 
            <BR><BR>  共享MFC 
            DLL(或MFC扩展DLL)的规则DLL涉及到HINSTANCE句柄问题,HINSTANCE句柄对于加载资源特别重要。EXE和DLL都有其自己的资源,而且这些资源的ID可能重复,应用程序需要通过资源模块的切换来找到正确的资源。如果应用程序需要来自于DLL的资源,就应将资源模块句柄指定为DLL的模块句柄;如果需要EXE文件中包含的资源,就应将资源模块句柄指定为EXE的模块句柄。<BR><BR>  这次我们创建一个动态链接到MFC 
            DLL的规则DLL(下载本工程<A 
            href="http://www.pconline.com.cn/pcedu/empolder/gj/vc/0509/acc/SharedDll.zip"><U><FONT 
            color=#0000ff>附件</FONT></U></A>),在其中包含如图13的对话框。<BR></P>
            <P align=center><IMG alt="" 
            src="VC++动态链接库(DLL)编程深入浅出(三).files/20051121084944747.jpg" 
            border=0></P>
            <P align=center>图13 DLL中的对话框</P>
            <P>  另外,在与这个DLL相同的工作区中生成一个基于对话框的MFC程序,其对话框与图12完全一样。但是在此工程中我们另外添加了一个如图14的对话框。<BR></P>
            <P align=center><IMG alt="" 
            src="VC++动态链接库(DLL)编程深入浅出(三).files/20051121084944202.jpg" 
            border=0></P>
            <P align=center>图14 EXE中的对话框</P>
            <P>  图13和图14中的对话框除了caption不同(以示区别)以外,其它的都相同。<BR>尤其值得特别注意,在DLL和EXE中我们对图13和图14的对话框使用了相同的资源ID=2000,在DLL和EXE工程的resource.h中分别有如下的宏:<BR></P>
            <P></P>
            <P class=code>//DLL中对话框的ID<BR><BR>#define IDD_DLL_DIALOG 
            2000<BR><BR><BR>//EXE中对话框的ID<BR><BR>#define IDD_EXE_DIALOG 2000</P>
            <P><BR>  与5.3节静态链接MFC 
            DLL的规则DLL相同,我们还是在规则DLL中定义接口函数ShowDlg,原型如下:<BR></P>
            <P class=code>#include "StdAfx.h"<BR><BR>#include 
            "SharedDll.h"<BR><BR>void ShowDlg(void)<BR><BR>{ <BR><BR>CDialog 
            dlg(IDD_DLL_DIALOG); 
            //打开ID为2000的对话框<BR><BR>dlg.DoModal();<BR><BR>}</P>
            <P><BR>  而为应用工程主对话框的“调用DLL”的单击事件添加如下消息处理函数:<BR></P>
            <P class=code>void CSharedDllCallDlg::OnCalldllButton() 
            <BR><BR>{<BR><BR>ShowDlg();<BR><BR>}</P>
            <P><BR>  我们以为单击“调用DLL”会弹出如图13所示DLL中的对话框,可是可怕的事情发生了,我们看到是图14所示EXE中的对话框!<BR><BR>  <STRONG>惊讶?</STRONG><BR><BR>  产生这个问题的根源在于应用程序与MFC规则DLL共享MFC 
            DLL(或MFC扩展DLL)的程序总是默认使用EXE的资源,我们必须进行资源模块句柄的切换,其实现方法有三:<BR><BR>  方法一 
            在DLL接口函数中使用:<BR></P>
            <P class=code>AFX_MANAGE_STATE(AfxGetStaticModuleState());</P>
            <P>我们将DLL中的接口函数ShowDlg改为:<BR></P>
            <P class=code>void ShowDlg(void)<BR><BR>{ 
            <BR><BR>//方法1:在函数开始处变更,在函数结束时恢复<BR><BR>//将AFX_MANAGE_STATE(AfxGetStaticModuleState());作为接口函数的第一//条语句进行模块状态切换<BR><BR>AFX_MANAGE_STATE(AfxGetStaticModuleState());<BR><BR><BR>CDialog 
            dlg(IDD_DLL_DIALOG);//打开ID为2000的对话框<BR><BR>dlg.DoModal();<BR><BR>}</P>
            <P><BR>  这次我们再点击EXE程序中的“调用DLL”按钮,弹出的是DLL中的如图13的对话框!嘿嘿,弹出了正确的对话框资源。<BR><BR>AfxGetStaticModuleState是一个函数,其原型为:<BR></P>
            <P class=code>AFX_MODULE_STATE* AFXAPI AfxGetStaticModuleState( 
            );</P>
            <P><BR>  该函数的功能是在栈上(这意味着其作用域是局部的)创建一个AFX_MODULE_STATE类(模块全局数据也就是模块状态)的实例,对其进行设置,并将其指针pModuleState返回。<BR><BR>AFX_MODULE_STATE类的原型如下:<BR></P>
            <P class=code>// AFX_MODULE_STATE (global data for a 
            module)<BR><BR>class AFX_MODULE_STATE : public 
            CNoTrackObject<BR><BR>{<BR><BR>public:<BR><BR>#ifdef 
            _AFXDLL<BR><BR>AFX_MODULE_STATE(BOOL bDLL, WNDPROC pfnAfxWndProc, 
            DWORD dwVersion);<BR><BR>AFX_MODULE_STATE(BOOL bDLL, WNDPROC 
            pfnAfxWndProc, DWORD dwVersion,BOOL 
            bSystem);<BR><BR>#else<BR><BR>AFX_MODULE_STATE(BOOL 
            bDLL);<BR><BR>#endif<BR><BR>~AFX_MODULE_STATE();<BR><BR><BR>CWinApp* 
            m_pCurrentWinApp;<BR><BR>HINSTANCE 
            m_hCurrentInstanceHandle;<BR><BR>HINSTANCE 
            m_hCurrentResourceHandle;<BR><BR>LPCTSTR 
            m_lpszCurrentAppName;<BR><BR><BR>… //省略后面的部分<BR><BR>}</P>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -