使用资源创建 WTL 对话框、属性表或向导(简单方法)






4.95/5 (49投票s)
在 Visual Studio 中设计完对话框后,使用 WTL 类向导将它们转换为 WTL 类,**而且不仅仅是从 Visual Studio 6 开始!**
- Visual Studio 6 插件版本
- 可执行版本
目录
引言
在使用 WTL 几年后,我发现有些操作会反复进行
- 基于资源创建对话框类。
- 为类添加混入(mixin)(最常见的是
CDialogResize
)。 - 将几个对话框推入属性表或向导。
- 注册应用程序将处理的扩展程序。
所以,有一天,当我(再次)发现自己复制默认的 AboutDlg.h 文件并为其进行调整时,我问自己:有没有更简单的方法?有什么自动化的东西吗?
好吧,就 Visual Studio 6 而言,实际上有两种方法:插件和宏。由于这项工作对宏来说太繁重了,所以插件是答案。
第三种方法,由 Tage 建议(见下文):一个独立的 .EXE 文件,可以添加到 VS .NET 的“工具”菜单中。对于那些在没有 Microsoft IDE 的情况下进行编码的人来说,它也可以使用。谢谢 Tage!
背景
有两种方法可以为 Visual Studio 6 编写插件:MFC 和 ATL。
在 ATL 中,您创建一个 ATL DLL 项目,添加一个插件对象,然后就可以了!
挑战在于如何访问活动项目 .rc 文件中的资源:基本上,这些资源不属于 Visual Studio 的对象模型(6.0 版本)。解决方案很明显:.dsp 和 .rc 文件是文本文件,资源标记分隔符是已知的(sscanf
分隔符和逗号),并且 <cstdio>(以前称为 <stdio.h>)在此方面非常有帮助。我更喜欢 C 标准 IO 库而不是 Windows API,因为我认为在逐字节读取文件时,它更方便、更简洁。
之后,就只剩下处理字符串了……
安装插件(Visual Studio 6)
将文件 WTLWizard.dll 复制到您选择的目录,然后
- 在 Visual Studio 6 中,打开菜单 **“工具/自定义”**
- 打开 **“插件和宏文件”** 选项卡
- 点击 **“浏览...”** 按钮
- 打开您复制 DLL 的位置。
- 开始使用它!
它应该看起来像这样
安装独立工具(Visual Studio .NET)
在 VS.NET 或 Visual Studio 2003 中,您可以使用 Wizard 的可执行版本。
这是一个 WTL 对话框应用程序,带有与 VS6 工具栏上的按钮相同的按钮。
要安装它,请将可执行文件复制到您选择的文件夹,打开 “工具|外部工具” 菜单,点击“添加”,然后填写类似的内容
首次运行后,可执行文件将添加几个上下文菜单项,每当您右键单击 .rc 文件时都会显示这些项
使用 WTL 类向导(两个版本)
仅限 Visual Studio 6:插件
目前,**WTL 类向导**只有一个工具栏,带有四个按钮
插件工具栏上的第一个按钮,以及可执行文件中的“对话框向导”按钮,使您能够从资源创建 WTL 对话框类。两者都会打开一个向导,让您选择当前打开项目资源脚本中的一个对话框,设置一些选项(例如生成 .cpp 文件、继承 CDialogResize
、继承 CPropertyPageImpl
或使用 DDX),甚至选择将附加到子控件的成员变量。
第二个按钮(相当于“属性表向导”)创建一个 WTL 属性表或向导,带有嵌入的对话框成员和一个嵌入的数据类。它会打开另一个向导,让您检查多个对话框资源,这些资源将成为属性表或属性页的成员,决定是否要分离接口与实现(通过使用 .cpp 文件),并在属性表和向导样式之间进行选择。
第三个按钮打开“扩展程序处理程序向导”,它创建一个类,并包含将应用程序注册为扩展程序处理程序的代码;在不同项目中生成此类时,唯一会改变的函数是其析构函数,它负责完成所有实际工作。理想情况下,您应该在关闭应用程序主窗口后立即声明该类的一个变量,并且它应该在调用 _Module.Term()
**之前**超出范围。
最后一个按钮将打开您的 Internet 浏览器,显示本文档以供参考。
所有生成的文件都以一些注释开头,包括
- 作者姓名(也就是您)。如果您至少使用 Windows 2000,则会以“友好格式”显示;否则,将显示您登录系统的用户名。
- 版权所有者(即 Visual Studio 的许可所有者)。
- 引用 GPL 许可证,与 WTL 7.5 源代码中的相同,这对于编写开源项目或发布代码的人来说可能很有用。
- 免责声明,用于类似目的。**请注意:我不是律师**,我也不知道代码将在哪个国家/地区使用,因此如果您认为免责声明与您的源代码无关,请随时删除它。
较新版本的 Visual Studio、非 Microsoft IDE,或记事本及无 IDE:可执行文件
由于可执行版本无法访问您的“活动项目”,因此您必须将所需项目的 .rc(资源)文件 **拖放到** 其主对话框上。您可以从任何 Windows 资源管理器窗口拖动它。
之后,您还可以单击任何按钮来运行与 Visual Studio 6 上看到的向导完全相同的向导。指向此页面的链接(供参考)可在“关于...”框中找到。
运行任何向导后,将显示以下对话框,您可以从中复制生成的文件名,并将它们添加到您的项目中
该对话框是可调整大小的,正如真正的 WTL 对话框一样。
首次运行可执行文件后,它将注册以处理 .rc 文件(资源脚本)。
免责声明。
我不是您的律师。我不是任何人的律师。我不是律师。我不知道您住在哪个国家/地区,或分发您的软件。因此,上述注释的某些部分可能对您完全无关、不当或不足。您可以根据需要随时删除或修改它们。
创建对话框
向导的第一个页面显示您资源脚本中的所有对话框。如果您将其作为文本文件编辑,并将对话框注释掉了,它仍然会显示在这里,因为注释会被忽略。
选择一个,然后继续...
在第二个页面上,您可以决定对话框类的一些常规设置。
默认的类名和文件名基于对话框资源名称,排除下划线之前的任何前缀,将下划线之后的所有字符大写,并省略所有下划线。如果您选择生成 .cpp 文件,其文件名将与头文件相同,只是扩展名不同。
如果您的对话框是属性页,它将继承自 CPropertyPageImpl
,链接到 CPropertyPageImpl
的消息映射,在构造函数中设置一些样式,并覆盖几个可覆盖的函数。如果您的对话框是可调整大小的,它将继承自 CDialogResize
并链接到它,并在其 WM_INITDIALOG
处理程序中调用 DlgResize_Init()
。
顺便说一句,如果您在 WM_INITDIALOG
处理程序中执行了任何非平凡的初始化,请不要忘记在 WM_DESTROY
处理程序中撤销它。
如果您实现 DDX,则仅创建一个原型映射,因为控件和 DDX 宏之间没有明显的_一一_对应关系。例如,一个数字编辑框可以使用 DDX_FLOAT
、DDX_INT
或 DDX_UINT
进行映射,无论是否进行验证。
您可以选择性地创建成员控件变量,这些变量将(使用 operator =
)附加到对话框中的控件。
对于您未勾选的那些,将生成注释掉的成员变量和赋值操作,从而允许稍后更改主意。
无论您在此页面上的选择如何,都会为所有按钮生成命令处理程序,并为所有组合框、列表框和扩展组合框的 CBN_SELCHANGE
和 LBN_SELCHANGE
通知生成一个处理函数。
如果您在继承自 CDialogImpl
的类中使用了 Rich Edit 控件,则会生成一个构造函数和一个虚析构函数。构造函数确保加载了相关的 DLL(由 CRichEditCtrl::GetLibraryName()
返回),析构函数包含注释掉的代码以在构造函数中加载它时卸载它。
调用 FreeLibrary()
被注释掉的原因是,无模式对话框之间的交互超出了插件的猜测范围。无论如何,Rich Edit DLL(如果使用)应尽可能靠近 _Module.Init()
的调用加载,并在尽可能靠近 _Module.Term()
被调用的地方卸载。当然,向导不会更改它生成的源文件以外的任何源文件,因此使用了上述的规避方法。如果需要,可以复制粘贴。如果您的类继承自 CPropertyPageImpl
,则属性表负责加载 DLL。更多内容如下……
创建属性表或向导
属性表是对话框的集合,向导是伪装的属性表。您可以在此处选择任意数量的对话框(尽管少于两个可能意义不大),您还可以使用右侧的按钮来移动选定的项目,从而重新排序它们。
在您的属性表类中,将为所有标记的对话框生成嵌入的类。页面顺序将是此处显示的从上到下的顺序。
如果您的任何属性页具有 Rich Edit 控件,则在属性表的构造函数中将加载(如果需要)Rich Edit DLL。
最后,您可以选择属性表的类名。由于表本身不来自资源,因此项目的名称(假定与 .rc 文件名称相同)用于生成类名和文件名。
您还可以决定是否将实现细节移到 .cpp 文件中,以及是生成属性页还是向导。
如果您选择向导,则会生成一些条件代码(取决于 _WIN32_IE
的值)。对于 Wizard97 样式,您还可以为第一页和最后一页选择水印,为所有未选择水印的页面选择一个标题。位图是从活动项目中**所有**的位图资源中选择的。
您还可以生成 DDX 原型映射,其限制与对话框类生成所应用的限制相同。
生成的属性表类
该类有几个嵌入的类
- 一个
CData
类,用于保存属性表及其页面之间共享的所有数据。为每个属性页面中的每个控件创建一个数据项,只要可以合理地猜测默认值,并为编辑框使用CString
。随意删除您不喜欢的内容,这是您的代码!(生成的默认值旨在具有接近 40% 的可用性)。**不**执行重复项检查,因此在多个页面上具有相同 ID 的同类型控件将生成编译时错误(重复标识符)。 - 每个页面的一个对话框类,以
CData
为模板,并包含指向属性表的CData
成员的指针,从而使大多数状态在所有页面(和表)之间共享。 - 属性表的构造函数调用其所有属性页成员上的
AddPage
,并设置它们的CData
指针的值。它还会根据您的选择(是否为向导)设置样式标志。 - 如果至少有一个属性页中包含 Rich Edit 控件,则表的构造函数会确保已加载相关的 DLL。
您需要做什么?将数据从控件移动到 CData
成员,并且,如果 DoModal
返回 IDOK
,则调用一个函数(未生成)来执行有意义的操作。
就是这么简单。
将您的应用程序注册为扩展程序处理程序。
您的程序可能为一种或多种文件类型提供上下文菜单选项,这些文件类型由其扩展名标识,可以是您自己的,也可以与其他程序共享。
例如,Visual Studio 处理多种扩展名:.C, .H, .CPP, .DSP, .DSW, .RC……
如上所述,WTL 类向导的可执行版本还将自身注册为 .RC(资源脚本)文件的处理程序。
此任务足够频繁,值得自动化。
在向导的第一页,您将决定您的程序将处理的扩展名列表。
对于每个扩展名,您可以设置几个选项:其文件类型(可能与多个扩展名相同:例如,.htm 和 .html 扩展名相同),您的应用程序是否会为该扩展名提供图标,以及 DDE 设置。
您可以通过在第一次进入此页面时点击“添加”,然后通过点击“克隆”(将选定项的副本添加到列表中,递增“扩展名”字段中的序列号)、“编辑”(编辑当前选定的项)或“删除”(删除当前选定的项)来编辑列表视图中的记录。
生成的类仅在目标计算机上未找到文件类型和图标设置时使用它们,因此,如果这不是您期望的行为,则必须相应地更改生成的代码(注释掉一对“if
”)。
这仍然是第一个向导页面,编辑器已打开。当您更改“扩展名”字段时,对话框过程将尝试在注册表中查找它,如果找到,其类型将出现在“文档类型”字段中。否则,文档类型将由您的项目名称(从资源文件名获取)、扩展名和序数“1”组成。
在点击“确定”之前,字段不会添加到列表中,因此当编辑器打开时,“下一步”按钮将禁用。
对于您的程序将支持的每个扩展名,您可以添加一个或多个上下文菜单选项。
“标志”字段启用了这种多重性。例如,WTL 类向导的可执行版本向 .rc 文件菜单添加了四个选项(并非偶然,上面显示了这些选项)。
同样,您会看到熟悉的“添加”、“克隆”、“编辑”和“删除”按钮。
第一个添加的处理程序的默认值为“使用 <项目名称> 打开”,并且没有标志。
这个编辑器要简单得多。
一个有趣的特性是,您可以将项目从一个扩展名复制到另一个扩展名,方法是点击“编辑”,从组合框中选择所需的扩展名,然后点击“确定”。
同样,在继续之前,您必须在“确定”和“取消”之间做出选择。
工作原理
在插件版本中,资源脚本基于活动项目定位,活动项目作为 IDE 环境的成员变量传递给插件。
在可执行版本中,必须将资源脚本名称作为命令行参数提供,或者将其拖放到向导的主对话框上。
当执行命令时,资源脚本的对话框将被加载到一个基于 std::map
(作为 WTL::CString
s)的模型中,该模型还包含每个对话框的子控件。
用户(也就是您)可以做出相关选择,最终,如果使用的是插件版本,则会向您的项目中添加一个 .h 文件,或者可选地添加一个 .cpp 文件;在可执行版本中,它们的名称会显示在编辑框中,您可以从中复制。
当然,这些向导存在一些局限性
- 插件仅适用于 Visual Studio 6。如果您使用的是任何其他环境,例如 VS.NET,请使用可执行版本。
- 由于 .rc 文件被读取为文本文件,因此目前注释掉的对话框会显示在要从中选择的对话框列表中,并且资源
#include
s 被忽略。在使用 IDE 生成的资源文件时,这应该不是问题。 - DDX 作为原型映射生成,而不是完整的映射,因为控件类型和 DDX 宏之间没有_一一_对应关系:例如,一个数字编辑框可以映射到一个整数或一个浮点数,无论是否进行边界检查。
- 恐怕我在编写向导时可能忽略了一些 .NET 或 CE 特定的问题。如果有,请通知我(在下方),我很乐意进行任何必要的更改。
亮点
Visual Studio 6 插件
在编写本文时,我发现了一些在为 Visual Studio 6 编写带有 WTL 用户界面的 ATL 插件时可能有所帮助的内容
它像任何其他 WTL 应用程序一样简单!
在开发插件时,一个“奇怪”的部分是测试代码,因为您的调试会话的可执行文件是 IDE 本身。最好在工作区中有两个项目,一个用于插件,另一个用于常规 WTL 应用程序,后者可用于原型设计和初步测试。为了测试插件,您需要安装它,将另一个项目设置为活动项目,并运行相关命令,对插件源代码进行所有相关更改和添加,在 工具/自定义/插件和宏文件 复选列表中取消选中该插件,重新编译(无需关闭 Visual Studio),然后再来一次……
为了获取 OutputDebugString()
(或 ATLTRACE
)输出,需要一个外部工具,网络上有许多此类工具可用。另一方面,消息框就在那里帮助您……
工具和插件
另一方面,开发 VS.NET 插件并非易事。
VS.NET 中的对象模型要强大得多,但因此也远比复杂。例如,它允许访问项目中的资源(我在 VS6 中非常怀念这一点)、菜单、子菜单、输出窗格、几乎屏幕上所有可见内容的上下文菜单:对于专业的插件编写者来说,梦想成真。
但是,对于“普通程序员”来说,想要自动化一些经常性任务,这个工具可能太重了。
而且别忘了,当前项目不一定是 C++ 项目。
一个 VS6 ATL 插件,从生成的那一刻起,其图像列表中就有两个按钮的工具栏,加载第一个按钮的代码,以及当点击该按钮时执行的命令。
比我更懂的人(Oz Solomon,在他的这篇文章中)解释了编写 VS.NET 插件的一些(正面和负面)影响。
对于像我这样试图移植一个特定目的的插件的人来说,学习曲线似乎有点太陡峭了。
另一方面,可执行的独立工具完全独立于 IDE,这意味着它将能抵御 IDE 的大多数更改(除非 .rc 文件格式发生剧烈变化),并且可以被那些使用命令行编译器甚至完全没有 IDE 的人使用。
外部工具的缺点在于它是外部的,它不知道 IDE,所以它无法,例如,从活动项目中推断出活动项目资源文件的名称,或者将生成的文件添加到活动项目中。当然,您可以自己作为文本文件处理 .dsp 或 .vcproj 文件。
一如既往,总有选择的空间。
拖放文件。
这是由一个混入(mixin)完成的,定义在 DropFileHandler.h 中,对对话框、视图或控件都很有用。
头文件(包含在可执行文件的源代码中,查找 DropFileHandler.h)非常明确,但您可以在 将文件拖放到 WTL 窗口中(简单方法) 中阅读更多相关内容。
WTL 宏
对于更简单的任务(例如,为类添加混入,这至少需要两个修改:将其添加到继承列表中并链接到其消息映射),宏是一个更温和但功能较弱的工具。项目源代码中附带了一个小的宏文件。它绝不是杰作,只是一个可能的方向的提示……
您的任务,如果您决定接受
明确地说:这个程序仍有**大量**的增长空间,所以,如果您有任何改进的想法,或想分享类似的工具,我很乐意听取。
我希望您发现这个项目和我在 CodeProject 上找到的许多其他项目一样有用。
编程愉快!
免责声明
作者“按原样”提供向导、代码和信息,并免除任何明示或暗示的保证,包括但不限于适销性和特定用途的适用性暗示保证。在任何情况下,作者均不对因使用本软件而产生的任何直接、间接、偶然、特殊、示范性或后果性损害(包括但不限于采购替代商品或服务;使用、数据或利润损失;或业务中断)负责,无论是由合同、严格责任还是侵权行为(包括疏忽或其他)引起的任何理论引起的,即使已告知可能发生此类损害。
历史
- 2004 年 6 月 - 创建。
- 2004 年 8 月
- 新增功能
- 为扩展程序生成器添加了上下文菜单注册。
- 添加了可执行版本。
- 将本文档的链接添加到插件和可执行文件中,供参考。
- 如果您使用 Windows 2000 或更高版本,版权中的姓名将是“友好名称”格式:否则,仍将是您的登录名。
- 生成的一些代码,特别是在 .CPP 文件中,现在是版本相关的,基于
_MSC_VER
和_ATL_VER
,因为 VC6 和 VC7 在模板方面有不同的方法。
- 修复
CData
(嵌入在生成的属性表中)现在是结构体,而不是类,以便所有成员默认都是公共的。- 修复了生成代码中的一些缩进错误,但仍有相当多的要修复……
- 修复了 Aaron Hudon 提到的由未初始化变量引起的错误。
- 生成的代码在
IDOK
和IDCANCEL
处理程序中不再为属性页调用EndDialog(wID)
。
- 新增功能