命令提示符小工具






3.50/5 (9投票s)
2007年1月30日
9分钟阅读

118494

2411
一个侧边栏小工具,允许您执行通常在命令提示符窗口中完成的操作。
引言
这个小工具试图通过使其可以通过侧边栏访问,并提供更易于自定义的界面来改进这个旧的 Windows 工具 - 命令提示符,同时尽可能保留其功能。如果 Linux 至少有十几个命令提示符替代品,为什么 Windows 只有一个?而且那个命令提示符在新的 Vista Aero 界面中看起来很不搭调……
解决方案分析
在定义要解决的问题之后,第一步也是正常的一步是检查是否有人已经解决了这个问题。我的研究揭示了在这方面有两个努力。
-
嵌入真正的命令提示符
Pavel Zolnikov 在他的 CommandBar 文章 中使用了这种方法。对优点和缺点进行简要分析是合适的。这种方法显然保留了最大的功能;我认为几乎所有的命令提示符功能都得到了保留,但代价是必须使用本地 API。尽管本地 API 可以在侧边栏小工具中使用(请参阅我的 另一个小工具),但为了简单起见,.NET 解决方案更可取。此外,这种方法并未实现我们项目的另一个目标:提供一个易于自定义的界面。是的,旧的命令提示符停留在其标准的字体和背景,这在短期内不会改变。
-
运行带参数和输出重定向的进程
另一个可行的选择是使用 .NET 框架类来运行进程(我们当然会运行著名的 cmd.exe)。当我们运行程序时,我们可以发送参数(我们要执行的命令)。输出将被捕获并显示给用户。这个解决方案由 Senthil Kumar 在 他的文章 中发明,它为界面提供了比前一种方案更多的灵活性,但在功能方面,它有所损失,因为我们无法使用诸如自动完成(上/下箭头、Tab 等)之类的功能。此外,在运行连续命令时会遇到很多问题,例如
>> cd c: >> dir
原始命令提示符会列出 C: 驱动器的内容,但我们的程序不会。因为每个命令都发出给一个新的 cmd.exe 进程,所以这会打印出原始文件夹的内容,而不是 C: 的内容。这个问题可以通过创建一个 .bat 文件来解决,该文件列出直到当前命令的所有命令,然后运行此脚本而不是仅运行当前命令;您猜对了,这样做效率不高。
-
使用 .NET 函数模拟 MS-DOS 命令
这种方法根本不使用原始的 cmd.exe。我们使用 .NET 框架功能来编写 MS-DOS 命令。显然,这涉及大量工作,但这是可以完成的。真正的问题是我们失去了所有可扩展性。比方说,我安装了 Windows PowerShell。用这种方法构建的命令提示符替换将无法使用其中的任何命令。
我的方法 - 输入输出重定向
考虑到目标(保留尽可能多的功能,使用 .NET 进行 UI 灵活性),我在 MSDN 文档中搜索了与命令行应用程序进行双向通信的机制。隐藏在其中的是关于 输入输出重定向 的说明。看起来,在启动进程时,可以使用一个处理程序异步接收输出,同时将输入同步发送给程序。首先,我们启用重定向(commandPromptProcess
是允许运行外部可执行文件的 Process
类的实例)
commandPromptProcess.StartInfo.UseShellExecute = false;
然后我们声明我们想要重定向输出并设置接收它的函数
commandPromptProcess.StartInfo.RedirectStandardOutput = true;
commandPromptProcess.OutputDataReceived += new DataReceivedEventHandler
(OutputHandler);
要指定输入更简单,我们只需调用
commandPromptWriter.WriteLine(MSDOScommand);
但是,我们如何显示输出呢?请记住,处理程序是从 UI 所在的另一个线程调用的,所以我们必须使用某种线程间通信,如下所示
public delegate void UpdateTextCallback(string text);
private void UpdateText(string text)
{
outputBox.AppendText(text+System.Environment.NewLine) ;
outputBox.ScrollToCaret();
}
ScrollToCaret
函数只是为了确保我们能够实际看到最后一行输出(如果需要,它会滚动 richtextBox
)。从另一个线程访问文本框的全部魔力在于调用 updateText
函数
outputBox.Invoke(new UpdateTextCallback(UpdateText), new object[]
{ outLine.Data });
所以,到目前为止,我们已经为进程设置了输入/输出重定向。现在我们只需要启动它,如下所示
commandPromptProcess.StartInfo.FileName = "cmd.exe";
commandPromptProcess.Start();
但随后我们发现我们仍然看到命令提示符窗口;这完全合乎逻辑,因为我们只重定向了输出和输入。创建的 Windows 仍然存在。我们不希望显示此窗口,所以我们编写
commandPromptProcess.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
commandPromptProcess.StartInfo.CreateNoWindow =true;
使用代码创建小工具
小工具实际上就是网页,最简单的形式就是 HTML 文档。所以我们将不得不将上述代码打包成可以从 HTML 文件访问的方式。我们已经创建了一个 Windows Forms UserControl
,现在我们将通过分配一个唯一的 ID(称为 GUID)来使其可从 HTML 访问,该 ID 唯一标识它;然后我们需要通过设置相应的属性使其可见
[Guid("85BECB98-B07E-11DB-BA8B-428B56D89593")]
[ComVisible(true)]
public partial class CommandPromptUsercontrol : UserControl
{
然后,从主小工具文件实例化它
<object id="command"
classid="clsid:85BECB98-B07E-11DB-BA8B-428B56D89593"
style="background-color:Transparent;" >
</object>
我们创建的东西称为 ActiveX
控件。
透明背景技巧
正如您在屏幕截图中看到的,小工具是一个图标,它延伸到侧边栏之外。这样做的目的是,您无需右键单击侧边栏,单击“属性”,单击“查看列表...”然后单击“删除”即可删除该小工具。只需将鼠标悬停在其上片刻,关闭按钮就会出现。为什么按钮只在该时候出现?答案是 Windows 在鼠标位于小工具上方时知道鼠标在小工具上(“while MouseOver
”),但我们整个小工具是一个 ActiveX
控件,所以 Windows 永远不会显示关闭按钮。这就是为什么我使用带有透明度的背景图像(.PNG 支持透明度),并且将图像的图标角部不完全透明;因此,mouseover
事件会出现,关闭按钮也会出现。这个角部还用于让我们将小工具拖出侧边栏。
扩展功能
拖放
由于我们在 Forms 2.0 中创建了这个简单而有效的 UI,因此我们自动添加了对标准快捷方式的剪切和粘贴的支持。我在旧的命令提示符中错过的另一个功能是拖放。我想将一个文件拖到命令提示符中以便运行它,但这是不可能的。嗯,在 C# 中实现这个很简单。确保目标控件的 AllowsDrop
属性设置为 true
,然后实现这两个函数
void CommandPromptUsercontrol_DragEnter(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(DataFormats.Text)) e.Effect =
DragDropEffects.Move;
}
void CommandPromptUsercontrol_DragDrop(object sender, DragEventArgs e)
{
commandInput.Text += e.Data.GetData(DataFormats.Text).ToString();
}
DragEnter
在您将某物拖过控件时运行,DragDrop
在您释放拖过的任何内容到控件上时运行。就这么简单!
高亮显示
由于侧边栏的空间很小,可能会使事情难以理解,因此我决定实现简单的突出显示,以使过去的命令在输出中更可见。正如您在此屏幕截图中看到的,命令被着色为蓝色。还请注意,用于拖动的图标位于窗口后面,因此它不会影响文本的可见性。
可调整大小的小工具
由于侧边栏的空间很小,我决定在小工具未停靠时将其变大。这通过一段用 JavaScript 编写的小脚本完成,如下所示
function largeGadget()
{
var crtWidth=System.Gadget.Settings.read("width");
var crtHeight=System.Gadget.Settings.read("height");
if ((crtWidth!="") && (crtHeight!=""))
{
resizeGadget(crtHeight,crtWidth);
command.style.width=crtWidth-20;
command.style.height=crtHeight;
bkg.style.width=crtWidth;
bkg.style.height=crtHeight;
}
else
{
resizeGadget(350,500);
command.style.width=480;
bkg.style.width=150;
bkg.style.height=350;
}
}
正如您所见,代码使用了设置对话框中的 width
和 height
,因此您可以自行决定在取消停靠时小工具的大小。command 变量实际上是我们的 ActiveX
控件的 ID。控件上的自动调整大小发生是因为 textBox
被停靠在控件的底部(停靠意味着将控件“滑向”其容器的相应边框),而 richtextBox
被锚定(也就是说,它与容器的所需边框保持恒定的距离)
如果您还没有 Vista
您仍然可以使用此应用程序。我制作了一个独立的 .NET 2.0 应用程序,所以您甚至不必安装 .NET 3.0;2.0 版本就足够了。下载演示项目并安装。
结论
我认为,列出我解决方案的优缺点是一个好主意
Good | 错误 |
|
|
据我所知,我的方法至少是创新的;我没有在其他地方找到这种与命令行实用程序交互的方式,它证明了包装任何控制台应用程序的可靠解决方案。在考虑它保留的功能时,它会做出妥协,但这些会通过它提供的改进得到补偿。
参考文献和发布说明
理解具体问题所需的所有材料都已在文章中介绍。提供的代码可免费用于非商业用途。如果您想将其用于商业应用程序(或重定向 .NET 的想法用于相同目的),请在此处留言。代码是我的个人财产(MSDN 的评论在需要的地方完整保留),所有附加文件也是如此,除了我在 DC 网络上找到的图标,我已尽一切努力识别其版权但未成功。为了更好地体验小工具,您应该使用 Consolas 字体。文章顶部有一个下载链接。这是程序员的最佳字体,直接来自微软实验室。
从命令提示符的原始功能来看,有些不起作用(Tab、向上箭头等),但使用 .NET 框架启用了某些附加功能(复制粘贴、拖放等)。
历史
- 更新 2007/1/31:添加了安装程序、独立应用程序、高亮显示、可调整大小的取消停靠、修复