﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-swo2006-文章分类-vc 工程</title><link>http://www.cppblog.com/swo2006/category/3201.html</link><description /><language>zh-cn</language><lastBuildDate>Mon, 19 May 2008 20:57:07 GMT</lastBuildDate><pubDate>Mon, 19 May 2008 20:57:07 GMT</pubDate><ttl>60</ttl><item><title>将VC向导中创建出来的Win32项目和Win32控制台程序互相转换</title><link>http://www.cppblog.com/swo2006/articles/15791.html</link><dc:creator>swo</dc:creator><author>swo</author><pubDate>Wed, 29 Nov 2006 13:23:00 GMT</pubDate><guid>http://www.cppblog.com/swo2006/articles/15791.html</guid><wfw:comment>http://www.cppblog.com/swo2006/comments/15791.html</wfw:comment><comments>http://www.cppblog.com/swo2006/articles/15791.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/swo2006/comments/commentRss/15791.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/swo2006/services/trackbacks/15791.html</trackback:ping><description><![CDATA[

似乎在Win32项目中,只能使用WinMain函数,而Win32控制台程序中只能使用main函数.  <br /><span class="yinchang"><a href="http://www.faq-it.org/archives/uml_basic/">uml_basic</a></span>
似乎两个项目连接的crt0.obj有些不同.  <br />如何在VC中修改项目的属性?    <br />
  <br />
它们主要的区别是定义的宏不同，一个是WIN32,另一个是CONSOLE.   <br /><br />
在预处理中把_WINDOWS换成_CONSOLE就行了  <br />
  <br />
project  settings  -&gt;  Link  :将/SUBSUSTEM:WINDOWS开关改为/SUBSYSTEM:CONSOLE  <br />
  <br />
可将  Win32控制台程序  当成  在Win32项目  使用，反之亦然。  <br /> <br />
把/subsystem:windows或/subsystem:console删除,由编译器自己决定也可以<img src ="http://www.cppblog.com/swo2006/aggbug/15791.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/swo2006/" target="_blank">swo</a> 2006-11-29 21:23 <a href="http://www.cppblog.com/swo2006/articles/15791.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>windows 系统管理使用命令行</title><link>http://www.cppblog.com/swo2006/articles/14749.html</link><dc:creator>swo</dc:creator><author>swo</author><pubDate>Mon, 06 Nov 2006 13:47:00 GMT</pubDate><guid>http://www.cppblog.com/swo2006/articles/14749.html</guid><wfw:comment>http://www.cppblog.com/swo2006/comments/14749.html</wfw:comment><comments>http://www.cppblog.com/swo2006/articles/14749.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/swo2006/comments/commentRss/14749.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/swo2006/services/trackbacks/14749.html</trackback:ping><description><![CDATA[http://www.cppblog.com/mzty/archive/2006/11/03/14631.html<img src ="http://www.cppblog.com/swo2006/aggbug/14749.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/swo2006/" target="_blank">swo</a> 2006-11-06 21:47 <a href="http://www.cppblog.com/swo2006/articles/14749.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>动态链接库DLL的链接</title><link>http://www.cppblog.com/swo2006/articles/14742.html</link><dc:creator>swo</dc:creator><author>swo</author><pubDate>Mon, 06 Nov 2006 10:53:00 GMT</pubDate><guid>http://www.cppblog.com/swo2006/articles/14742.html</guid><wfw:comment>http://www.cppblog.com/swo2006/comments/14742.html</wfw:comment><comments>http://www.cppblog.com/swo2006/articles/14742.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/swo2006/comments/commentRss/14742.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/swo2006/services/trackbacks/14742.html</trackback:ping><description><![CDATA[
		<b>动态链接库DLL的链接</b>
		<br />
		<br />　　应用程序使用DLL可以采用两种方式：一种是隐式链
接，另一种是显式链接。在使用DLL之前首先要知道DLL中函数的结构信息。Visual
C++6.0在VC\bin目录下提供了一个名为Dumpbin.exe的小程序，用它可以查看DLL文件中的函数结构。另外，Windows系统将遵循
下面的搜索顺序来定位DLL： 1．包含EXE文件的目录，2．进程的当前工作目录， 3．Windows系统目录，
4．Windows目录，5．列在Path环境变量中的一系列目录。<br /><br />　　1．隐式链接<br /><br />　　隐式链接就是在程序开始执行时
就将DLL文件加载到应用程序当中。实现隐式链接很容易，只要将导入函数关键字_declspec(dllimport)函数名等写到应用程序相应的头文
件中就可以了。下面的例子通过隐式链接调用MyDll.dll库中的Min函数。首先生成一个项目为TestDll，在DllTest.h、
DllTest.cpp文件中分别输入如下代码：<br /><table bgcolor="#ffffff" border="0" cellpadding="0" width="100%"><tbody><tr><td>//Dlltest.h<br />#pragma comment(lib，"MyDll.lib")<br />extern "C"_declspec(dllimport) int Max(int a,int b);<br />extern "C"_declspec(dllimport) int Min(int a,int b);<br />//TestDll.cpp<br />#include<stdio.h><br />#include"Dlltest.h"<br />void main()<br />{int a;<br />a=min(8,10)<br />printf("比较的结果为%d\n"，a);<br />}<br /></stdio.h></td></tr></tbody></table><p>　　在创建DllTest.exe文件之前，要先将MyDll.dll和MyDll.lib拷贝到当前工程所在的目录下面，也可以拷贝到
windows的System目录下。如果DLL使用的是def文件，要删除TestDll.h文件中关键字extern
"C"。TestDll.h文件中的关键字Progam commit是要Visual
C+的编译器在link时，链接到MyDll.lib文件，当然，开发人员也可以不使用#pragma
comment(lib，"MyDll.lib")语句，而直接在工程的Setting-&gt;Link页的Object/Moduls栏填入
MyDll.lib既可。<br /><br />　　2．显式链接<br /><br />　　显式链接是应用程序在执行过程中随时可以加载DLL文件，也可以随时卸载
DLL文件，这是隐式链接所无法作到的，所以显式链接具有更好的灵活性，对于解释性语言更为合适。不过实现显式链接要麻烦一些。在应用程序中用
LoadLibrary或MFC提供的AfxLoadLibrary显式的将自己所做的动态链接库调进来，动态链接库的文件名即是上述两个函数的参数，此
后再用GetProcAddress()获取想要引入的函数。自此，你就可以象使用如同在应用程序自定义的函数一样来调用此引入函数了。在应用程序退出之
前，应该用FreeLibrary或MFC提供的AfxFreeLibrary释放动态链接库。下面是通过显式链接调用DLL中的Max函数的例子。<br /></p><table bgcolor="#ffffff" border="0" cellpadding="0" width="100%"><tbody><tr><td>#include <studio.h><br />#include<widows.h><br />void main(void)<br />{<br />typedef int(*pMax)(int a,int b);<br />typedef int(*pMin)(int a,int b);<br />HINSTANCE hDLL;<br />PMax Max<br />HDLL=LoadLibrary("MyDll.dll");//加载动态链接库MyDll.dll文件；<br />Max=(pMax)GetProcAddress(hDLL,"Max");<br />A=Max(5,8);<br />Printf("比较的结果为%d\n"，a);<br />FreeLibrary(hDLL);//卸载MyDll.dll文件；<br />}</widows.h></studio.h></td></tr></tbody></table><p>　　在上例中使用类型定义关键字typedef，定义指向和DLL中相同的函数原型指针，然后通过LoadLibray()将DLL加载到当前的应
用程序中并返回当前DLL文件的句柄，然后通过GetProcAddress()函数获取导入到应用程序中的函数指针，函数调用完毕后，使用
FreeLibrary()卸载DLL文件。在编译程序之前，首先要将DLL文件拷贝到工程所在的目录或Windows系统目录下。<br /><br />　　
使用显式链接应用程序编译时不需要使用相应的Lib文件。另外，使用GetProcAddress()函数时，可以利用MAKEINTRESOURCE
()函数直接使用DLL中函数出现的顺序号，如将GetProcAddress(hDLL,"Min")改为GetProcAddress(hDLL,
MAKEINTRESOURCE(2))（函数Min()在DLL中的顺序号是2），这样调用DLL中的函数速度很快，但是要记住函数的使用序号，否则会
发生错误。</p><img src ="http://www.cppblog.com/swo2006/aggbug/14742.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/swo2006/" target="_blank">swo</a> 2006-11-06 18:53 <a href="http://www.cppblog.com/swo2006/articles/14742.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>DLL</title><link>http://www.cppblog.com/swo2006/articles/12746.html</link><dc:creator>swo</dc:creator><author>swo</author><pubDate>Wed, 20 Sep 2006 04:21:00 GMT</pubDate><guid>http://www.cppblog.com/swo2006/articles/12746.html</guid><wfw:comment>http://www.cppblog.com/swo2006/comments/12746.html</wfw:comment><comments>http://www.cppblog.com/swo2006/articles/12746.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/swo2006/comments/commentRss/12746.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/swo2006/services/trackbacks/12746.html</trackback:ping><description><![CDATA[　　<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 /><br />我们可以在Visual C++中设置MFC规则DLL是静态链接到MFC DLL还是动态链接到MFC DLL。如图8，依次选择Visual
C++的project -&gt; Settings -&gt; General菜单或选项，在Microsoft Foundation
Classes中进行设置。<br /><p align="center"><img alt="" src="http://www.pconline.com.cn/pcedu/empolder/gj/vc/0509/pic/05-09-22-vc-8.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="http://www.pconline.com.cn/pcedu/empolder/gj/vc/0509/pic/05-09-22-vc-9.jpg" border="0" /></p><p align="center">图9 MFC DLL工程的创建</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 /><br />添加socket通讯支持后的InitInstance成员函数如下：<br /><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><br />　　4区选择是否由MFC向导自动在源代码中添加注释，一般我们选择“Yes,please”。<br /><p align="center"><img alt="" src="http://www.pconline.com.cn/pcedu/empolder/gj/vc/0509/pic/05-09-22-vc-10.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="http://www.pconline.com.cn/pcedu/empolder/gj/vc/0509/pic/05-09-22-vc-11.jpg" border="0" /></p><p align="center">图11 MFC规则DLL例子</p>　　在DLL中添加对话框的方式与在MFC应用程序中是一样的。<br /><br />　　在图11所示DLL中的对话框的Hello按钮上点击时将MessageBox一个“Hello,pconline的网友”对话框，下面是相关的文件及源代码，其中删除了MFC向导自动生成的绝大多数注释（下载本工程<a href="http://www.pconline.com.cn/pcedu/empolder/gj/vc/0509/acc/RegularDll.zip">附件</a>）：<br /><br /><br />第一组文件：CWinApp继承类的声明与实现<br /><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><br />　　分析：<br /><br />　
　在这一组文件中定义了一个继承自CWinApp的类CRegularDllApp，并同时定义了其的一个实例theApp。乍一看，您会以为它是一个
MFC应用程序，因为MFC应用程序也包含这样的在工程名后添加“App”组成类名的类（并继承自CWinApp类），也定义了这个类的一个全局实例
theApp。<br /><br />我们知道，在MFC应用程序中CWinApp取代了SDK程序中WinMain的地位，SDK程序WinMain所完成的工作由CWinApp的三个函数完成：<br /><p class="code">virtual BOOL InitApplication( );<br /><br />virtual BOOL InitInstance( );<br /><br />virtual BOOL Run( ); //传说中MFC程序的“活水源头”</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">附件</a>)<br /><br />　　分析：<br /><br />　　这一部分的编程与一般的应用程序根本没有什么不同，我们照样可以利用MFC类向导来自动为对话框上的控件添加事件。MFC类向导照样会生成类似ON_BN_CLICKED(IDC_HELLO_BUTTON, OnHelloButton)的消息映射宏。<br /><br />　　第三组文件 DLL中的资源文件<br /><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><br />　　分析：<br /><br />　　在MFC规则DLL中使用资源也与在MFC应用程序中使用资源没有什么不同，我们照样可以用Visual C++的资源编辑工具进行资源的添加、删除和属性的更改。<br /><br />　　第四组文件 MFC规则DLL接口函数<br /><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><br />　　分析：<br /><br />　　这个接口并不使用MFC，但是在其中却可以调用MFC扩展类CdllDialog的函数，这体现了“规则”的概类。<br /><br />　　与非MFC DLL完全相同，我们可以使用__declspec(dllexport)声明或在.def中引出的方式导出MFC规则DLL中的接口。<br /><br /><strong>5.4 MFC规则DLL的调用</strong><br /><br />　　笔者编写了如图12的对话框MFC程序（下载本工程<a href="http://www.pconline.com.cn/pcedu/empolder/gj/vc/0509/acc/RegularDllCall.zip">附件</a>）来调用5.3节的MFC规则DLL，在这个程序的对话框上点击“调用DLL”按钮时弹出5.3节MFC规则DLL中的对话框。<br /><p align="center"><img alt="" src="http://www.pconline.com.cn/pcedu/empolder/gj/vc/0509/pic/05-09-22-vc-12.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><br />　　上述例子中给出的是显示调用的方式，可以看出，其调用方式与第4节中非MFC DLL的调用方式没有什么不同。<br /><br />我们照样可以在EXE程序中隐式调用MFC规则DLL，只需要将DLL工程生成的.lib文件和.dll文件拷入当前工程所在的目录，并在RegularDllCallDlg.cpp文件（图12所示对话框类的实现文件）的顶部添加：<br /><p class="code">#pragma comment(lib,"RegularDll.lib")<br /><br />void ShowDlg(void); </p><br />　　并将void CRegularDllCallDlg::OnCalldllButton() 改为：<br /><p class="code">void CRegularDllCallDlg::OnCalldllButton() <br /><br />{<br /><br />ShowDlg();<br /><br />}</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">附件</a>），在其中包含如图13的对话框。<br /><p align="center"><img alt="" src="http://www.pconline.com.cn/pcedu/empolder/gj/vc/0509/pic/05-09-22-vc-13.jpg" border="0" /></p><p align="center">图13 DLL中的对话框</p><p>　　另外，在与这个DLL相同的工作区中生成一个基于对话框的MFC程序，其对话框与图12完全一样。但是在此工程中我们另外添加了一个如图14的对话框。<br /></p><p align="center"><img alt="" src="http://www.pconline.com.cn/pcedu/empolder/gj/vc/0509/pic/05-09-22-vc-14.jpg" border="0" /></p><p align="center">图14 EXE中的对话框</p>　　图13和图14中的对话框除了caption不同（以示区别）以外，其它的都相同。<br /><br />尤其值得特别注意，在DLL和EXE中我们对图13和图14的对话框使用了相同的资源ID=2000，在DLL和EXE工程的resource.h中分别有如下的宏：<br /><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><br />　　与5.3节静态链接MFC DLL的规则DLL相同，我们还是在规则DLL中定义接口函数ShowDlg，原型如下：<br /><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><br />　　而为应用工程主对话框的“调用DLL”的单击事件添加如下消息处理函数：<br /><p class="code">void CSharedDllCallDlg::OnCalldllButton() <br /><br />{<br /><br />ShowDlg();<br /><br />}</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 class="code">AFX_MANAGE_STATE(AfxGetStaticModuleState());</p>我们将DLL中的接口函数ShowDlg改为：<br /><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><br />　　这次我们再点击EXE程序中的“调用DLL”按钮，弹出的是DLL中的如图13的对话框！嘿嘿，弹出了正确的对话框资源。<br /><br />AfxGetStaticModuleState是一个函数，其原型为：<br /><p class="code">AFX_MODULE_STATE* AFXAPI AfxGetStaticModuleState( );</p><br />　　该函数的功能是在栈上（这意味着其作用域是局部的）创建一个AFX_MODULE_STATE类（模块全局数据也就是模块状态）的实例，对其进行设置，并将其指针pModuleState返回。<br /><br />AFX_MODULE_STATE类的原型如下：<br /><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><br />　　AFX_MODULE_STATE类利用其构造函数和析构函数进行存储模块状态现场及恢复现场的工作，类似汇编中call指令对pc指针和sp寄存器的保存与恢复、中断服务程序的中断现场压栈与恢复以及操作系统线程调度的任务控制块保存与恢复。<br /><br />　　许多看似不着边际的知识点居然有惊人的相似！<br /><br />AFX_MANAGE_STATE是一个宏，其原型为： <br /><p class="code">AFX_MANAGE_STATE( AFX_MODULE_STATE* pModuleState )</p><br />　　该宏用于将pModuleState设置为当前的有效模块状态。当离开该宏的作用域时（也就离开了pModuleState所指向栈上对象的作用域），先前的模块状态将由AFX_MODULE_STATE的析构函数恢复。<br /><br />　　方法二 在DLL接口函数中使用：<br /><p class="code">AfxGetResourceHandle();<br /><br />AfxSetResourceHandle(HINSTANCE xxx);</p><br />　　AfxGetResourceHandle用于获取当前资源模块句柄，而AfxSetResourceHandle则用于设置程序目前要使用的资源模块句柄。<br /><br />　　我们将DLL中的接口函数ShowDlg改为：<br /><p class="code">void ShowDlg(void)<br /><br />{ <br /><br />//方法2的状态变更<br /><br />HINSTANCE save_hInstance = AfxGetResourceHandle(); <br /><br />AfxSetResourceHandle(theApp.m_hInstance); <br /><br /><br /><br />CDialog dlg(IDD_DLL_DIALOG);//打开ID为2000的对话框<br /><br />dlg.DoModal();<br /><br />//方法2的状态还原<br /><br />AfxSetResourceHandle(save_hInstance);<br /><br />}</p><br />　　通过AfxGetResourceHandle和AfxSetResourceHandle的合理变更，我们能够灵活地设置程序的资源模块句柄，而方法一则只能在DLL接口函数退出的时候才会恢复模块句柄。方法二则不同，如果将ShowDlg改为：<br /><p class="code">extern CSharedDllApp theApp; //需要声明theApp外部全局变量<br /><br />void ShowDlg(void)<br />{ <br />//方法2的状态变更<br />HINSTANCE save_hInstance = AfxGetResourceHandle(); <br />AfxSetResourceHandle(theApp.m_hInstance); <br />CDialog dlg(IDD_DLL_DIALOG);//打开ID为2000的对话框<br />dlg.DoModal();<br /><br /><br />//方法2的状态还原<br />AfxSetResourceHandle(save_hInstance);<br />//使用方法2后在此处再进行操作针对的将是应用程序的资源<br />CDialog dlg1(IDD_DLL_DIALOG); //打开ID为2000的对话框<br />dlg1.DoModal();<br />}</p><br />　　在应用程序主对话框的“调用DLL”按钮上点击，将看到两个对话框，相继为DLL中的对话框（图13）和EXE中的对话框（图14）。<br /><br />方法三 由应用程序自身切换<br /><br />　　资源模块的切换除了可以由DLL接口函数完成以外，由应用程序自身也能完成（下载本工程<a href="http://www.pconline.com.cn/pcedu/empolder/gj/vc/0509/acc/yyqh_SharedDll.zip">附件</a>）。<br /><br />　　现在我们把DLL中的接口函数改为最简单的：<br /><p class="code">void ShowDlg(void)<br />{ <br />CDialog dlg(IDD_DLL_DIALOG); //打开ID为2000的对话框<br />dlg.DoModal();<br />}</p><br />　　而将应用程序的OnCalldllButton函数改为：<br /><p class="code">void CSharedDllCallDlg::OnCalldllButton() <br />{<br />//方法3：由应用程序本身进行状态切换<br /><br />//获取EXE模块句柄<br /><br />HINSTANCE exe_hInstance = GetModuleHandle(NULL); <br />//或者HINSTANCE exe_hInstance = AfxGetResourceHandle(); <br />//获取DLL模块句柄<br />HINSTANCE dll_hInstance = GetModuleHandle("SharedDll.dll"); <br />AfxSetResourceHandle(dll_hInstance); //切换状态<br />ShowDlg(); //此时显示的是DLL的对话框 <br />AfxSetResourceHandle(exe_hInstance); //恢复状态<br /><br />//资源模块恢复后再调用ShowDlg<br />ShowDlg(); //此时显示的是EXE的对话框<br /><br />}</p><br />　　方法三中的Win32函数GetModuleHandle可以根据DLL的文件名获取DLL的模块句柄。如果需要得到EXE模块的句柄，则应调用带有Null参数的GetModuleHandle。<br /><br />　
　方法三与方法二的不同在于方法三是在应用程序中利用AfxGetResourceHandle和AfxSetResourceHandle进行资源模块
句柄切换的。同样地，在应用程序主对话框的“调用DLL”按钮上点击，也将看到两个对话框，相继为DLL中的对话框（图13）和EXE中的对话框（图
14）。<br /><br />　　在下一节我们将对MFC扩展DLL进行详细分析和实例讲解，欢迎您继续关注本系列连载。<br /><br /><br /><img src ="http://www.cppblog.com/swo2006/aggbug/12746.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/swo2006/" target="_blank">swo</a> 2006-09-20 12:21 <a href="http://www.cppblog.com/swo2006/articles/12746.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>