WinDos 工具






4.64/5 (20投票s)
2006年2月20日
9分钟阅读

50823

1583
一个使用属性编辑器执行任何 DOS 命令的工具


引言
这是一个用于构建和执行 DOS 命令的工具。该工具的理念是将任何 DOS 命令构建为 Windows 对话框,并为特定的命令参数提供编辑器/对话框。例如,如果一个 DOS 命令接受一个目录参数,您可以使用一个目录对话框。
这样做的好处是,不必麻烦地创建和保存大量难以维护的 BAT 文件,就能让复杂的 DOS 命令变得简单。还会显示所选命令或参数的帮助信息,最后,命令被组织成类别。命令列表可以保存为 XML 文件或从 XML 文件加载,以便拥有不同的集合并与他人共享常用命令。
用法
使用命令
当您启动该工具时,会显示一个默认的(示例)命令列表以及命令行(DOS)。可以在配置文件中指定一个启动命令列表文件。

您可以从列表中选择一个命令并展开它以显示和编辑其参数。请注意,不同的参数类型有不同的编辑器。
![]() |
单击“运行”按钮在 DOS 中运行该命令。在状态栏中,会显示将要执行的命令的预览。 |
![]() |
“缩放”按钮可用于放大某个命令,或者,如果您已经放大,则返回到列表。 |
![]() |
“编辑”按钮可用于开始编辑当前选定的项。请参阅下一节。 |
![]() |
“打开文件”按钮用于打开一个包含命令的 XML 文件。 |
![]() |
“保存文件”按钮用于将命令列表保存到 XML 文件。 |
![]() |
“描述”按钮显示或隐藏所选项目的描述。 |
标题和标题栏显示当前命令的名称。
编辑命令
要开始编辑命令,请单击“编辑”按钮。会出现第二个属性网格,显示当前命令的属性。下一个屏幕截图说明了这一点(请注意,屏幕截图已放大到命令)。

编辑模式下会出现两个额外的按钮。
![]() |
单击“添加”按钮以添加新命令(在查看命令列表时)或参数(在放大视图中)。 |
![]() |
单击“删除”按钮以删除选定的项。 |
“常规”属性对每个属性都相同。它们主要与显示属性有关,而且有望一目了然。最重要的属性是“类型”,它决定了属性的行为。这包括默认值和属性的编辑器。展开 Type
属性会显示特定于所选类型的可编辑属性。
在示例图片中,Dir
命令的 Directory
属性的类型为 DirectoryPropertyType
,这使其可以通过目录对话框进行选择。Format
属性定义了值如何转换为命令值(在这种情况下,值被加引号)。
属性类型
属性类型是此工具的重要组成部分。它们决定了用户可以输入的数据类型。目前,此工具包含以下属性类型:
简单类型 | |
---|---|
布尔值 |
用户可以选择 true/false。布尔值会被映射到命令字符串。 |
字符串 |
用户可以输入文本。文本可以为命令字符串进行格式化。 |
对话框类型 | |
Directory(目录) |
用户可以选择一个目录。目录路径可以为命令字符串进行格式化。 |
文件 |
用户可以选择一个文件。文件名可以为命令字符串进行格式化。 |
列表类型 | |
列表 |
用户可以从列表中选择一个项目。每个项目都有一个显示值和一个命令值。 |
复选列表 |
用户可以从列表中选择多个项目。每个项目都有一个显示值和一个命令值。有一个格式字符串和一个分隔符字符串。 |
复合类型 | |
命令 |
一个命令包含其他属性。有一个格式字符串和一个分隔符字符串。 |
我希望能够扩大和优化这个列表。最后但同样重要的是,可以复制和粘贴命令。在 Commands
属性网格上单击鼠标右键选择 Copy
或 Paste
。
Copy
会复制选定的属性或命令。Paste
会将复制的属性或命令粘贴到当前的CommandList
。
我希望这能解释基本用法。请随意尝试,感受一下所有东西是如何工作的。请注意,该工具本身并不十分有用,但拥有一个可以经常使用的命令集是很有用的。创建命令需要花费一些时间;好处是您可以一遍又一遍地使用它。我提供了一个默认的集合供您尝试。
Using the Code
我在代码设计方面的一些目标是拥有一个灵活的模型,并限制添加新属性类型所需的代码量。事实上,这个项目确实不需要多少代码。这是因为 .NET 中已经内置了该功能。首先,是一个小图。该图显示了基本设置,包括两种属性类型:命令和目录参数。

CommandList
所有命令和参数的容器是 CommandList
。它实现了 ICustomTypeDescriptor
,以便能够运行时定义我们自己的属性。它通过包装提供的 CommandProperty
实例和一个 CommandPropertyDescriptor
来实现这一点。请注意,在工具中,主 PropertyGrid
显示这些运行时属性。详细信息网格显示选定的 CommandProperty
本身,即作为一个类的标准属性。CommandList
包含命令属性,并存在于不同的函数中:
- 它充当全局命令列表(包含命令)。在最简单的设置中,这是唯一的
CommandList
。 - 它充当命令(包含参数)。
- 它充当复杂的命令参数。
通过嵌套 CommandList
,一个项可以是一个完整的批处理。
CommandProperty
命令的任何部分(无论是命令还是参数)都封装在 CommandProperty
中。这是一个密封类,包含通用属性,如 Name
和 Category
。
最重要的是,它有一个 Type
属性,它定义了实际的行为。该属性必须是 IPropertyType
的子类(更具体地说,是 BasePropertyType
,因为我无法 XML 序列化接口类型)。Type
属性使用一个类型转换器(PropertyTypeConverter
)来显示所有已知类型,因此用户可以从下拉列表中选择一个。一旦做出选择,属性值就会实例化为一个选定类型的新实例。
IPropertyType
IPropertyType
的后代是“发生动作的地方”。此类必须提供以下功能:
Default
值(这也将决定值的类型)。- 用于 DOS 命令行的值(
FormatValue
),基于用户输入的值。
另外,您可以添加:
- 一个值编辑器(
EditorType
),用于对话框或控件。 - 一个值类型转换器(
ConverterType
),用于列表或类型转换。
这听起来可能很复杂,但实际上比看起来要简单。为了证明我的观点,让我们看一下 DirectoryPropertyType
。
public class DirectoryPropertyType: BasePropertyType {
string format = "\"{0}\"";
[Description("Format string for the directory command.")]
public string Format {
get { return format; }
set { format = value; }
}
public override object Default {
get {
return string.Empty;
}
}
public override Type EditorType {
get {
return typeof(DirectoryEditor);
}
}
public override string FormatValue(object value) {
return value == null ? string.Empty : string.Format(Format, value);
}
}
此类有一个 Format
属性,它在其 FormatValue
方法中使用该值来返回要在 DOS 命令中使用的值。此类覆盖了 EditorType
以提供用于选择目录的编辑器。编辑器看起来像这样:
public class DirectoryEditor: UITypeEditor {
public override object EditValue(ITypeDescriptorContext context,
IServiceProvider provider, object value) {
FolderBrowserDialog dialog = new FolderBrowserDialog();
if (value != null && value.ToString().Length > 0) {
string path = Path.GetFullPath(value.ToString());
if (!Directory.Exists(path))
throw new InvalidOperationException();
dialog.SelectedPath = path;
}
if (dialog.ShowDialog() == DialogResult.OK)
value = dialog.SelectedPath;
return value;
}
public override UITypeEditorEditStyle
GetEditStyle(ITypeDescriptorContext context) {
return UITypeEditorEditStyle.Modal;
}
}
这两个类是能够在任何 DOS 命令中进行目录选择所需的所有内容。
以及其余的...
还有许多其他类和功能值得提及。我已尝试在所有类和成员中添加注释,因此您可能会发现将源代码通过 NDoc 运行很有用(浏览起来比源代码更容易)。
关注点
XML 文件是 XML 序列化的 CommandList
。读取旧版本应用程序的 XML 文件可能会在某些类发生更改时导致问题(这是一个普遍问题)。解决方案是提供一个 XSL 样式表来转换为新版本。属性窗体和命令提示符是独立的进程,并像这样运行。如果它们作为一个整体运行(例如,当一个被激活时,两个都出现在前景)会更好。我对此没有任何(优雅的)解决方案。一些设计选择:
- 那些在其他类之外没有用途的类已被制作为私有的内部类。这适用于大多数
ConverterType
和EditorType
类。其中一些内部类与其父类有类型依赖关系。 - 类遵循松耦合规则。这意味着它们具有简单的接口。这也意味着您最终会得到更多的类。
- 设计遵循基本的设计模式原则。
我本来希望使用标准的 verb 机制来显示操作(添加命令,添加参数)。不幸的是,PropertyGrid
在运行时不显示 verbs。
演变和鸣谢
我经常使用 CodeProject,您的文章曾多次帮助我,包括构建这个工具。所以,谢谢 CodeProject,谢谢互联网 ;-)
最初,我的命令提示符是一个与隐藏命令提示符通信的文本框,类似于 S. Senthil Kumar 的 ShellControl 的设置。他有一个出色的文本框控件,用于捕获输入/输出。我对此进行了一些重写,以使进程保持运行,从而使命令上下文保持活动(例如当前目录),并使用线程进行异步处理。但后来我遇到了各种各样的问题,试图精确地模拟命令提示符的行为(例如,看似微不足道的任务,如处理 CTRL-C 等特殊键)。
对我来说,首要任务是拥有精确的功能,而这比我预期的要困难得多。最终,我厌倦了,决定最佳方向是使用现有的命令提示符。这使我的问题简化为向(单独的)命令提示符发送命令。当前的解决方案可能不会赢得任何美誉奖,但至少它只有几行代码(因此易于维护)。
对于属性编辑器逻辑,我参考了 Tony Allowatt 的优秀文章 Bending the .NET PropertyGrid to Your Will。同样,这并非我想要的全部,但它帮助我理解了一些关键点。最后但同样重要的是,我要感谢我的同事兼朋友 Koen Muilwijk。他帮助完成了这个小练习的许多部分,因为他是一个挑剔的人。;-)
已知bug
在某些机器上,启动时会生成一个异常,其中访问了进程的 MainWindowHandle
。消息是“Couldn't get process information from remote machine”,这是由 System.Diagnostics.PerformanceMonitor.GetData(String item)
行引起的。Process
使用 PerformanceCounter
来确定许多进程属性。异常发生是因为帐户没有访问此计数器的适当权限。我还没有解决这个问题的方法,只能尝试“升级”您的帐户。如果发生这种情况,应用程序将退出。
历史
这是第一个版本,所以我将称之为 1.0 beta。该工具的历史长度很可能取决于我收到的反馈。我很感激任何建设性的评论或代码改进。我个人的“愿望清单”包括:
- 命令管理
- 与命令提示符更好地集成
- 更多/改进的 PropertyTypes
- 用于验证和替换的正则表达式
再次,欢迎评论。感谢您的阅读和/或尝试。
- 2006 年 2 月 20 日 -- 发布原始版本
- 2007 年 10 月 26 日 -- 更新了演示和源代码下载