VC++动态链接库编程之MFC扩展 DLL

2016-02-19 20:53 5 1 收藏

今天图老师小编给大家精心推荐个VC++动态链接库编程之MFC扩展 DLL教程,一起来看看过程究竟如何进行吧!喜欢还请点个赞哦~

【 tulaoshi.com - 编程语言 】

DLL类型入口函数 非 MFC DLL 编程者提供DllMain函数 MFC规则 DLL CWinApp对象的InitInstance 和 ExitInstance MFC扩展 DLL MFC DLL向导生成DllMain 函数
  对于MFC扩展DLL,系统会自动在工程中添加如下表所示的宏,这些宏为DLL和应用程序的编写提供了方便。像AFX_EXT_CLASS、AFX_EXT_API、AFX_EXT_DATA这样的宏,在DLL和应用程序中将具有不同的定义,这取决于_AFXEXT宏是否被定义。这使得在DLL和应用程序中,使用统一的一个宏就可以表示出输出和输入的不同意思。在DLL中,表示输出(因为_AFXEXT被定义,通常是在编译器的标识参数中指定/D_AFXEXT);在应用程序中,则表示输入(_AFXEXT没有定义)。
  
  宏定义 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
   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
  6.2 MFC扩展DLL导出MFC派生类
  
  在这个例子中,我们将产生一个名为“ExtDll”的MFC扩展DLL工程,在这个DLL中导出一个对话框类,这个对话框类派生自MFC类CDialog。
  
  使用MFC向导生成MFC扩展DLL时,系统会自动添加如下代码:
  
  static AFX_EXTENSION_MODULE ExtDllDLL = { NULL, NULL };
  extern "C" int APIENTRY
  
  DllMain( HINSTANCE hInstance, DWord dwReason, LPVOID lpReserved )
  {
   // Remove this if you use lpReserved
  
   UNREFERENCED_PARAMETER( lpReserved );
  
   //说明:lpReserved是一个被系统所保留的参数,对于隐式链接是一个非零值,对于显式链接值是零
  
   if (dwReason == DLL_PROCESS_ATTACH)
   {
  TRACE0( "EXTDLL.DLL Initializing!" );
  // Extension DLL one-time initialization
  if ( !AfxInitExtensionModule( ExtDllDLL, hInstance ))
   return 0;
   // Insert this DLL into the resource chain
  new CDynLinkLibrary( ExtDllDLL );
   }
   else if (dwReason == DLL_PROCESS_DETACH)
   {
  TRACE0( "EXTDLL.DLL Terminating!" );
  // Terminate the library before destrUCtors are called
  AfxTermExtensionModule( ExtDllDLL );
   }
   return 1; // ok
  }

  这一段代码含义晦涩,我们需要对其进行解读:
  
  (1)上述代码完成MFC扩展DLL的初始化和终止处理;
  
  (2)初始化期间所创建的 CDynLinkLibrary 对象使MFC扩展 DLL 可以将 DLL中的CRuntimeClass 对象或资源导出到应用程序;
  
  (3)AfxInitExtensionModule函数捕捉模块的CRuntimeClass 结构和在创建 CDynLinkLibrary 对象时使用的对象工厂(COleObjectFactory 对象);
  
  (4)AfxTermExtensionModule函数使 MFC 得以在每个进程与扩展 DLL 分离时(进程退出或使用AfxFreeLibrary卸载DLL时)清除扩展 DLL;
  
  (5)第一条语句static AFX_EXTENSION_MODULE ExtDllDLL = { NULL, NULL };定义了一个AFX_EXTENSION_MODULE类的静态全局对象,AFX_EXTENSION_MODULE的定义如下:
  
  struct AFX_EXTENSION_MODULE
  {
   BOOL bInitialized;
   HMODULE hModule;
   HMODULE hResource;
   CRuntimeClass* pFirstSharedClass;
   COleObjectFactory* pFirstSharedFactory;
  
   };

  由AFX_EXTENSION_MODULE的定义我们可以更好的理解(2)、(3)、(4)点。
  
  在资源编辑器中添加一个如图15所示的对话框,并使用MFC类向导为其添加一个对应的类CExtDialog,系统自动添加了ExtDialog.h和ExtDialog.cpp两个头文件。
  
  
  图15 MFC扩展DLL中的对话框
  修改ExtDialog.h中CExtDialog类的声明为:
  
  class AFX_EXT_CLASS CExtDialog : public CDialog
  {
   public:
  CExtDialog( CWnd* pParent = NULL );
  enum { IDD = IDD_DLL_DIALOG };
   protected:
  virtual void DoDataExchange( CDataExchange* pDX );
  DECLARE_MESSAGE_MAP()
  };

  这其中最主要的改变是我们在class AFX_EXT_CLASS CExtDialog语句中添加了“AFX_EXT_CLASS”宏,则使得DLL中的CExtDialog类被导出。 6.3 MFC扩展DLL的加载
  
  6.3.1 隐式加载
  
  我们在6.2工程所在的工作区中添加一个LoadExtDllDlg工程,用于演示MFC扩展DLL的加载。在LoadExtDllDlg工程中添加一个如图16所示的对话框,这个对话框上包括一个“调用DLL”按钮。
  
  
  图16 MFC扩展DLL调用工程中的对话框
  在与图16对应对话框类实现文件的头部添加:
  
  // LoadExtDllDlg.cpp : implementation file
  //
  
  #include "..ExtDialog.h"
  #pragma comment( lib, "ExtDll.lib" )
  
  而“调用DLL”按钮的单击事件的消息处理函数为:
  
  void CLoadExtDllDlg::OnDllcallButton()
  {
   CExtDialog extDialog;
   extDialog.DoModal();
  }

  当我们单击“调用DLL”的时候,弹出了如图15的对话框。
  
  为提供给用户隐式加载(MFC扩展DLL一般使用隐式加载,具体原因见下节),MFC扩展DLL需要提供三个文件:
  
  (1)描述DLL中扩展类的头文件;
  
  (2)与动态链接库对应的.LIB文件;
  
  (3)动态链接库.DLL文件本身。
  
  有了这三个文件,应用程序的开发者才可充分利用MFC扩展DLL。
  
  6.3.2 显示加载
  
  显示加载MFC扩展DLL应使用MFC全局函数AfxLoadLibrary而不是WIN32 API中的LoadLibrary。AfxLoadLibrary 最终也调用了 LoadLibrary这个API,但是在调用之前进行了线程同步的处理。
  
  AfxLoadLibrary 的函数原型与 LoadLibrary完全相同,为:
  
  HINSTANCE AFXAPI AfxLoadLibrary( LPCTSTR lpszModuleName );
  与之相对应的是,MFC 应用程序应使用AfxFreeLibrary 而非FreeLibrary 卸载MFC扩展DLL。AfxFreeLibrary的函数原型也与 FreeLibrary完全相同,为:
  
  BOOL AFXAPI AfxFreeLibrary( HINSTANCE hInstLib );
  假如我们把上例中的“调用DLL”按钮单击事件的消息处理函数改为:
  
  void CLoadExtDllDlg::OnDllcallButton()
  {
   HINSTANCE hDll = AfxLoadLibrary( "ExtDll.dll" );
   if(NULL == hDll)
   {
  AfxMessageBox( "MFC扩展DLL动态加载失败" );
  return;
   }
  
   CExtDialog extDialog;
   extDialog.DoModal();
   AfxFreeLibrary(hDll);
  }

  则工程会出现link错误:
  
  LoadExtDllDlg.obj : error LNK2001: unresolved external symbol "__declspec(dllimport) public: virtual __thiscall CExtDialog::~CExtDialog(void)" (__imp_??1CExtDialogUAE@XZ)
  
  LoadExtDllDlg.obj : error LNK2001: unresolved external symbol "__declspec(dllimport) public: __thiscall CExtDialog::CExtDialog(class CWnd *)" (__imp_??0CExtDialogQAE@PAVCWnd@Z)

  提示CExtDialog的构造函数和析构函数均无法找到!是的,对于派生MFC类的MFC扩展DLL,当我们要在应用程序中使用DLL中定义的派生类时,我们不宜使用动态加载DLL的方法。
  
  6.4 MFC扩展DLL加载MFC扩展DLL
  
  我们可以在MFC扩展DLL中再次使用MFC扩展DLL,但是,由于在两个DLL中对于AFX_EXT_CLASS、AFX_EXT_API、AFX_EXT_DATA宏的定义都是输出,这会导致调用的时候出现问题。
  
  
  我们将会在调用MFC扩展DLL的DLL中看到link错误:
  
  error LNK2001: unresolved external symbol ….......
  因此,在调用MFC扩展DLL的MFC扩展DLL中,在包含被调用DLL的头文件之前,需要临时重新定义AFX_EXT_CLASS的值。下面的例子显示了如何实现:
  
  //临时改变宏的含义“输出”为“输入”
  
  #undef AFX_EXT_CLASS
  #undef AFX_EXT_API
  #undef AFX_EXT_DATA
  #define AFX_EXT_CLASS AFX_CLASS_IMPORT
  #define AFX_EXT_API AFX_API_IMPORT
  #define AFX_EXT_DATA AFX_DATA_IMPORT
  
  //包含被调用MFC扩展DLL的头文件
  
  #include "CalledDLL.h"
  
  //恢复宏的含义为输出
  
  #undef AFX_EXT_CLASS
  #undef AFX_EXT_API
  #undef AFX_EXT_DATA
  #define AFX_EXT_CLASS AFX_CLASS_EXPORT
  #define AFX_EXT_API AFX_API_EXPORT
  #define AFX_EXT_DATA AFX_DATA_EXPORT
 6.5 MFC扩展DLL导出函数和变量
  
  
  MFC扩展DLL导出函数和变量的方法也十分简单,下面我们给出一个简单的例子。
  
  我们在MFC向导生成的MFC扩展DLL工程中添加gobal.h和global.cpp两个文件:
  
  //global.h:MFC扩展DLL导出变量和函数的声明
  
  extern "C"
  {
   int AFX_EXT_DATA total; //导出变量
   int AFX_EXT_API add( int x, int y ); //导出函数
  }
  
  //global.cpp:MFC扩展DLL导出变量和函数定义
  
  #include "StdAfx.h"
  #include "global.h"
  
  extern "C" int total;
  int add(int x,int y)
  {
   total = x + y;
   return total;
  }

  编写一个简单的控制台程序来调用这个MFC扩展DLL:
  
  #include
  #include 单击此处下载本工程)。
  
  我们知道static控件所对应的CStatic类不具备设置背景和文本颜色的接口,这使得我们不能在对话框或其它用户界面上自由灵活地修改static控件的颜色风格,因此我们需要一个提供了SetBackColor和SetTextColor接口的CStatic派生类CMultiColorStatic。
   
  这个类的声明如下:
  
  class AFX_EXT_CLASS CMultiColorStatic : public CStatic
  {
   // Construction
  
   public:
  CMultiColorStatic();
  virtual ~CMultiColorStatic();
  // Attributes
   protected:
  CString m_strCaption;
  COLORREF m_BackColor;
  COLORREF m_TextColor;
  // Operations
   public:
  void SetTextColor( COLORREF TextColor );
  void SetBackColor( COLORREF BackColor );
  void SetCaption( CString strCaption );
  
  // Generated message map functions
   protected:
  afx_msg void OnPaint();
  DECLARE_MESSAGE_MAP()
  };

  在这个类的实现文件中,我们需要为它提供WM_PAINT消息的处理函数(这是因为颜色的设置依靠于WM_PAINT消息):
  
  BEGIN_MESSAGE_MAP(CMultiColorStatic, CStatic)
  
  //{{AFX_MSG_MAP(CMultiColorStatic)
   ON_WM_PAINT() //为这个类定义WM_PAINT消息处理函数
  /

来源:http://www.tulaoshi.com/n/20160219/1624756.html

延伸阅读
windows中,链接库分为两种类型:静态链接库.lib和动态链接库.dll。其中动态链接库在被使用的时候,通常还提供一个.lib,称为引入库,它主要提供被Dll导出的函数和符号名称,使得链接的时候能够找到dll中对应的函数映射。 静态链接库和动态链接库的作用相似,都是提供给其他程序进行调用的资源。其中,动态链接库的调用方法分隐式调用(静态导...
比较大应用程序都由很多模块组成,这些模块分别完成相对独立的功能,它们彼此协作来完成整个软件系统的工作。其中可能存在一些模块的功能较为通用,在构造其它软件系统时仍会被使用。在构造软件系统时,如果将所有模块的源代码都静态编译到整个应用程序EXE文件中,会产生一些问题:一个缺点是增加了应用程序的大小,它会占用更多的磁盘空间...
标签: Delphi
    一.DLL 库内存共享机制   从使用效果看,DLL和unit 很像,它们都可以被别的工程模块所调用,但二者在内部的实现机制上确存在着差别。如果一个程序模块中用uses语句引用了某个unit,编译程序在编译该模块时,便会连同unit一起编译,并把编译后的可执行代码链接到本程序模块中,这就是一个程序模块能够调用所引用unit中过程...
一、静态链接库         1.静态链接库的生成方法         在vc下建立一个新项目,项目类型选择win32 static library,然后在项目中加入.h.cpp.c文件,编译链接后就会生成一个静态链接库.lib文件。         如果想要取得尽量好...
Win7恢复dll动态链接库的方法   1.一般来说,如果电脑中的dll动态链接库有问题,便会出现相关的警示窗口,这个时候,便需要从电脑中出现的警示窗口中得知该动态链接的文件名,例如SHELL30.dll这种以dll后缀的文件,而它的路径则是C:WINDOWSsystem32SHELL30.dll,这是需要记录下来的信息。 2.之后,同时按下键盘上的win+R快捷键...