Win32 DLL和MFC DLL 中封装对话框

简介: 现在最常看见的关于DLL的问题就是如何在DLL中使用对话框,这是一个很普遍的关于如何在DLL中使用资源的问题。这里我们从Win32   DLL和MFC   DLL两个方面来分析并解决这个问题。           1.Win32   DLL               在Win32   DLL中使用对话框很简单,你只需要在你的DLL中添加对话框资源,而且可以在对话框上面设置你所需要的控件。
现在最常看见的关于DLL的问题就是如何在DLL中使用对话框,这是一个很普遍的关于如何在DLL中使用资源的问题。这里我们从Win32   DLL和MFC   DLL两个方面来分析并解决这个问题。     
    
  1.Win32   DLL     
          在Win32   DLL中使用对话框很简单,你只需要在你的DLL中添加对话框资源,而且可以在对话框上面设置你所需要的控件。然后使用DialogBox或者CreateDialog这两个函数(或相同作用的其它函数)来创建对话框,并定义你自己的对话框回调函数处理对话框收到的消息。下面通过一个具体实例来学习如何在Win32   DLL中使用对话框,可以按照以下步骤来完成这个例子:     
    
    
    
  1)在VC菜单中File->New新建一个命名为UseDlg的Win32   Dynamic-Link   Library工程,下一步选择A   simple   DLL   project。     
    
    
    
  2)在VC菜单中Insert->Resource添加一个ID为IDD_DLG_SHOW的Dialog资源,将此Dialog上的Cancel按钮去掉,仅保留OK按钮。再添加一个ID为IDD_ABOUTBOX的对话框,其Caption为About。保存此资源,将资源文件命名为UseDlg.rc。并将resource.h和UseDlg.rc加入到工程里面。     
    
    
    
  3)在UseDlg.app中包含resource.h,并添加如下代码:     
    
    
    
  HINSTANCE   hinst   =   NULL;     
    
  HWND   hwndDLG   =   NULL;     
    
    
    
  BOOL   CALLBACK   DlgProc(HWND   hDlg,   UINT   message,     
    
  WPARAM   wParam,   LPARAM   lParam);     
    
  BOOL   CALLBACK   AboutProc(HWND   hDlg,   UINT   message,     
    
  WPARAM   wParam,   LPARAM   lParam);     
    
  extern   "C"   __declspec(dllexport)   void   ShowDlg();     
    
    
    
  BOOL   APIENTRY   DllMain(   HANDLE   hModule,     
    
                          DWORD   ul_reason_for_call,     
    
                          LPVOID   lpReserved     
    
                                      )     
    
  {     
    
          switch(ul_reason_for_call)     
    
          {     
    
          case   DLL_PROCESS_ATTACH:     
    
                hinst   =   (HINSTANCE)hModule;     
    
          case   DLL_PROCESS_DETACH:     
    
                break;     
    
          }     
    
      return   TRUE;     
    
  }     
    
    
    
  extern   "C"   __declspec(dllexport)   void   ShowDlg()     
    
  {     
    
          hwndDLG   =   CreateDialog(hinst,MAKEINTRESOURCE(IDD_DLG_SHOW),     
    
  NULL,(DLGPROC)DlgProc);     
    
          ShowWindow(hwndDLG,   SW_SHOW);     
    
  }     
    
    
    
  BOOL   CALLBACK   DlgProc(HWND   hDlg,   UINT   message,     
    
  WPARAM   wParam,   LPARAM   lParam)     
    
  {     
    
      switch(message)     
    
      {     
    
          case   WM_INITDIALOG:     
    
                return   TRUE;     
    
                    
    
          case   WM_COMMAND:     
    
                if(LOWORD(wParam)==IDOK)     
    
  DialogBox(hinst,MAKEINTRESOURCE(IDD_ABOUTBOX),     
    
  hDlg,(DLGPROC)AboutProc);     
    
                return   TRUE;             
    
          case   WM_CLOSE:     
    
                DestroyWindow(hDlg);     
    
                hwndDLG   =   NULL;     
    
                return   TRUE;     
    
      }     
    
      return   FALSE;     
    
  }     
    
    
    
  BOOL   CALLBACK   AboutProc(HWND   hDlg,   UINT   message,     
    
  WPARAM   wParam,   LPARAM   lParam)     
    
  {     
    
          switch(message)     
    
      {     
    
                case   WM_CLOSE:     
    
                        EndDialog(hDlg,NULL);     
    
                        hwndDLG   =   NULL;     
    
                        return   TRUE;     
    
      }     
    
      return   FALSE;     
    
  }     
    
    
    
  4)编译生成UseDlg.dll和UseDlg.lib。     
    
    
    
  接下来我们建立调用此DLL的应用程序,其步骤如下:     
    
    
    
  1)在VC菜单中File->New新建一个命名为Use的MFC   AppWizard(exe)工程,下一步选择Dialog   Based之后点击Finish按钮。     
    
    
    
  2)在主对话框上面添加一个按钮,之后双击此按钮,会弹出Add   Member   Function的对话框,直接点击OK进入void   CUseDlg::OnButton1()函数。并在此函数内添加一个函数调用:ShowDlg();。     
    
    
    
  3)紧跟在#include语句后面加上如下代码:     
    
    
    
  extern   "C"   __declspec(dllexport)   void   ShowDlg();     
    
  #pragma   comment(lib,"debug/UseDlg")     
    
    
    
  4)将上面UseDlg工程中生成的UseDlg.dll和UseDlg.lib两个文件复制到Use工程的Debug目录内。     
    
    
    
  5)编译生成Use.exe。     
    
    
    
          运行Use.exe,点击Button1按钮,可以看到一个名称为Dialog的非模态对话框弹出。点击上面的按钮,可以弹出模态对话框About。运行成功。     
    
    
    
          让我们来回顾一下在Win32   DLL中使用对话框的过程。     
    
    
    
  在DLL中,我们定义了两个对话框资源:IDD_DLG_SHOW和IDD_ABOUTBOX,并且导出了函数ShowDlg。在函数ShowDlg之中使用CreateDialog函数创建了非模态对话框IDD_DLG_SHOW,并指定了该对话框的回调函数DlgProc。在DlgProc之中处理了WM_INITDIALOG、WM_COMMAND和WM_CLOSE消息,以响应用户对对话框所做的动作。在处理按钮动作的时候,使用DialogBox函数创建IDD_ABOUTBOX这个模态对话框,指定其回调函数为AboutProc,并且在AboutProc中处理其相应消息。     
    
    
    
  在EXE中,我们使用隐式链接的方法来调用DLL,并使用DLL中导出的ShowDlg函数来调用DLL中的对话框。     
    
    
    
          在Win32   DLL中使用对话框就是这么简单,下面让我们来看一下在MFC   DLL中如何使用对话框。     
  2.MFC   DLL     
          在MFC   DLL中使用对话框不像Win32   DLL中那么简单,主要是因为MFC程序中存在一个模块状态(Module   State)的问题,也就是资源重复的问题。(此处的术语模块是指一个可执行程序,或指其操作不依赖于应用程序的其余部分但使用MFC运行库的共享副本的一个DLL(或一组DLL)。我们所创建的MFC   DLL就是这种模块的一个典型实例。)     
    
    
    
          在每个模块(EXE或DLL)中,都存在一种全局的状态数据,MFC依靠这种全局的状态数据来区分不同的模块,以执行正确的操作。这种数据包括:Windows实例句柄(用于加载资源),指向应用程序当前的CWinApp和CWinThread对象的指针,OLE模块引用计数,以及维护Windows对象句柄与相应的MFC对象实例之间连接的各种映射等。但当应用程序使用多个模块时,每个模块的状态数据不是应用程序范围的。相反,每个模块具有自已的MFC状态数据的私有副本。这种全局的状态数据就叫做MFC模块状态。     
    
    
    
  模块的状态数据包含在结构中,并且总是可以通过指向该结构的指针使用。当代码在执行时进入了某一个模块时,只有此模块的状态为“当前”或“有效”状态时,MFC才能正确的区分此模块并执行正确的操作。     
    
    
    
  例如,MFC应用程序可以使用下面代码从资源文件中加载字符串:     
    
    
    
  CString   str;     
    
  str.LoadString(IDS_MYSTRING);     
    
    
    
  使用这种代码非常方便,但它掩盖了这样一个事实:即此程序中IDS_MYSTRING可能不是唯一的标识符。一个程序可以加载多个DLL,某些DLL可能也用IDS_MYSTRING标识符定义了一个资源。MFC怎样知道应该加载哪个资源呢?MFC使用当前模块状态查找资源句柄。如果当前模块不是我们要使用的正确模块,那么就会产生不正确的调用或者错误。     
    
    
    
  按照MFC库的链接方法,一个MFC   DLL有两种使用MFC库的方法:静态链接到MFC的DLL和动态链接到MFC的DLL。下面我们就按照这两种类型的MFC   DLL来介绍如何切换当前模块状态以正确的在MFC   DLL中使用资源。     
    
  1、静态链接到MFC的DLL     
    
  静态链接到MFC的规则DLL与MFC库静态链接,则此时MFC库不能共享,所以MFC总是使用它所链接的DLL的模块状态。这样也就不存在管理模块状态的问题。但使用这种方法的缺点是DLL程序将会变大,而且会在程序中留下重复代码。下面给出的例子验证了这一点。本例可以按照以下步骤来完成:     
    
    
    
  1)在VC菜单中File->New新建一个命名为DLLStatic的MFC   AppWizard的工程,下一步选择Regular   DLL   with   MFC   statically   linked。     
    
    
    
  2)在工程中添加一个对话框资源,其ID为:IDD_ABOUTBOX。并在resource.h之中将IDD_ABOUTBOX   的数值改为100。     
    
    
    
  3)在DLLStatic.cpp中定义如下函数:     
    
    
    
  void   ShowDlg()     
    
  {     
    
          CDialog   dlg(IDD_ABOUTBOX);     
    
          dlg.DoModal();     
    
  }     
    
    
    
  4)在DLLStatic.def文件中的EXPORTS语句中添加一行:ShowDlg,以导出ShowDlg函数。     
    
    
    
  5)编译生成DLLStatic.dll和DLLStatic.lib。     
    
    
    
  继续使用上一节中的Use工程,将前面生成的DLLStatic.dll和DLLStatic.lib两个文件复制到工程的Debug目录内,并将     
    
    
    
  extern   "C"   __declspec(dllexport)   void   ShowDlg();     
    
  #pragma   comment(lib,"debug/UseDlg")     
    
    
    
  这两行改为:     
    
    
    
  void   ShowDlg();     
    
  #pragma   comment(lib,"debug/DLLStatic")     
    
    
    
  编译并运行Use.exe。点击按钮,可以看到DLLStatic中的模态对话框弹出。     
    
    
    
  本例中,可以注意到DLL中所定义的About对话框资源与EXE中所定义的About对话框资源ID完全相同,但是当我们点击Use.exe上面的按钮时,弹出的是DLL中的模态对话框。说明,当使用静态链接到MFC的规则DLL时,不存在管理模块状态的问题。
目录
相关文章
|
敏捷开发 存储 开发工具
版本控制系统的选择:Git与SVN的比较
【8月更文挑战第14天】Git和SVN都是优秀的版本控制系统,它们各自具有独特的优势和适用场景。在选择版本控制系统时,需要根据具体的项目需求、团队特点和开发模式来综合考量。对于需要分布式团队协作、高效处理大型项目或采用敏捷开发模式的团队来说,Git是一个更好的选择。而对于传统团队、集中式开发或简单项目来说,SVN可能更加合适。无论选择哪种版本控制系统,都应该充分利用其提供的工具和功能来提高代码质量和开发效率。
|
7月前
|
人工智能 负载均衡 数据可视化
阿里云出手了,DeepSeek服务器拒绝繁忙,免费部署DeepSeek模型671B满血版
阿里云推出免费部署DeepSeek模型671B满血版服务,通过百炼大模型平台,用户无需编码,最快5分钟、最低0元即可完成部署。平台提供100万免费Token,支持DeepSeek-R1和DeepSeek-V3等多款模型调用,有效解决服务器繁忙问题。新手零基础也能轻松上手,享受高效稳定的API调用和自动弹性扩展功能。教程涵盖开通服务、获取API-KEY及配置Chatbox客户端等步骤,详细指引助您快速实现DeepSeek自由。
475 18
|
7月前
|
存储 开发框架 Devops
eino — 基于go语言的大模型应用开发框架(一)
Eino 是一个受开源社区优秀LLM应用开发框架(如LangChain和LlamaIndex)启发的Go语言框架,强调简洁性、可扩展性和可靠性。它提供了易于复用的组件、强大的编排框架、简洁明了的API、最佳实践集合及实用的DevOps工具,支持快速构建和部署LLM应用。Eino不仅兼容多种模型库(如OpenAI、Ollama、Ark),还提供详细的官方文档和活跃的社区支持,便于开发者上手使用。
1617 8
|
域名解析 安全 网络安全
全面了解CC攻击和防范策略
CC攻击是一种针对Web服务的攻击,模仿正常用户请求耗尽服务器资源。攻击类型包括直接、肉鸡、僵尸和代理攻击。目标包括网站、API、登录页面、基础设施组件、云服务、金融机构等。影响包括服务中断、性能下降、经济损失、品牌受损及法律问题。判断CC攻击可通过观察CPU上升、网站响应慢或检查系统日志。防护措施包括IP封禁、人机验证、使用安全加速服务、静态化页面、更改端口、完善日志和域名解析策略。CC与DDoS攻击主要区别在于攻击原理、对象、危害、门槛和所需流量。综合运用多种防御策略能有效抵御CC攻击。
|
安全 Go 开发者
Golang深入浅出之-Go语言中的CSP模型:深入理解并发哲学
【5月更文挑战第1天】Go语言基于CSP理论,借助goroutines和channels实现独特的并发模型。Goroutine是轻量级线程,通过`go`关键字启动,而channels提供安全的通信机制。文章讨论了数据竞争、死锁和goroutine泄漏等问题及其避免方法,并提供了一个生产者消费者模型的代码示例。理解CSP和妥善处理并发问题对于编写高效、可靠的Go程序至关重要。
347 2
|
11月前
|
数据采集 传感器 大数据
大数据中数据采集 (Data Collection)
【10月更文挑战第17天】
606 2
|
JavaScript 前端开发 搜索推荐
服务器端渲染技术SSR与ISR:深入解析与应用
【7月更文挑战第20天】服务器端渲染(SSR)和增量静态再生(ISR)作为现代Web开发中的两种重要渲染技术,各有其独特的优势和适用场景。在实际应用中,开发者应根据具体需求和条件选择合适的渲染模式。无论是追求极致的页面加载速度和SEO优化,还是实现内容的实时更新,SSR和ISR都能提供有效的解决方案。通过深入理解这些技术的工作原理和应用场景,开发者可以构建出更加高效、可靠和用户体验优异的Web应用。
|
Dart 开发工具 Android开发
快速集成 Flutter Shorebird 热更新
Flutter Shorebird 是一种云端代码推送服务,可以让开发者在几分钟内集成,无需修改代码即可将更新推送到任何 Dart 代码,支持所有 Android 和 iOS 设备,并符合 App Store 和 Play Store 的规定。Shorebird 最大的优点是无代码侵入,快速集成,设计优秀。
491 2
快速集成 Flutter Shorebird 热更新
|
SQL 缓存 API
SqlAlchemy 2.0 中文文档(五十六)(5)
SqlAlchemy 2.0 中文文档(五十六)
162 0
|
Ubuntu Java Linux
Ubuntu20.04下载jdk遇到各种奇怪问题大集,Linux如何将默认的OpenJDK切换成自己安装的JDK版本(以JDK1.8为例),无需卸载原有OpenJDK,Some packages co
Ubuntu20.04下载jdk遇到各种奇怪问题大集,Linux如何将默认的OpenJDK切换成自己安装的JDK版本(以JDK1.8为例),无需卸载原有OpenJDK,Some packages co