我需要能够在不窃取焦点的情况下启动进程(控制台和窗口)。我发现在 .NET 框架内执行此操作的唯一方法是 Microsoft.VisualBasic.Interaction.Shell 和 Microsoft.VisualBasic.AppWinStyle.[Minimized|Normal]NoFocus(映射到 SW_SHOWMINNOACTIVE/SW_SHOWMA 并传递给 ShellExecute)。
在我的代码的当前版本中(确实窃取了焦点),我正在使用 System.Diagnostics.Process,并依赖于提供给我的一些功能,而 Interaction.Shell 方法没有。
2 个问题(一个很严肃,一个是发泄我的沮丧,我真的不希望得到一个好的答案)
1.) 我别无选择只能自己包装 CreateProcess 或 ShellExecuteEx 是正确的,还是我错过了其他一些解决方案?我真的希望避免这种情况,因为 Process 是一个如此完整和有用的包装器,除了这个疏忽之外,还有太多的功能要实现,P/Invoke 调用调试,以及各种各样的痛苦。
2.) 为什么 Microsoft 的一个团队会创建这样一个(否则)完整的包装器,然后从 ProcessWindowStyle 中排除一半的可能值,而另一个团队创建了一个不太完整的类似包装器,但提供了所有有用的窗口样式?
最佳答案
VB.Net 团队为简化开发人员有关 Windows 检测的工作做了很多工作,我认为添加对 VB dll 的引用并在您的 C# 程序中使用它没有问题。
这是两个侧重点不同的团队,仅此而已。如果 Microsoft.VisualBasic.Interaction.Shell 可以解决您的问题,您应该不会感到难过。
如果不想引用dll,也可以使用Reflector查看实际实现,自行实现代码。
[编辑 - 在注释后添加代码示例以显示您可以组合 Interaction.Shell 和 Process]
int pid = Interaction.Shell("notepad.exe", AppWinStyle.NormalFocus);
Process p = Process.GetProcessById(pid);
p.Exited += ((o, e) => Console.WriteLine("Exit"));
p.EnableRaisingEvents = true;
Console.ReadLine();
在这里,我使用 Shell 方法启动进程,从 pid 获取进程的句柄,并挂接事件。您甚至可以执行 p.Kill() 以中止进程。
[编辑 - cmd.exe 的解决方法]
它开始变得有点不符合我的口味,但它确实有效。将“NEWWINDOW”替换为随机 guid 或其他内容以使其独一无二。
Microsoft.VisualBasic.Interaction.Shell(@"cmd.exe /c ""start cmd.exe /k title NEWWINDOW""", AppWinStyle.NormalFocus);
foreach (var process in Process.GetProcessesByName("cmd"))
{
if (process.MainWindowTitle.EndsWith("NEWWINDOW"))
{
process.Exited += ((o, e) => Console.WriteLine("Exit"));
process.EnableRaisingEvents = true;
}
}
关于c# - 在不窃取焦点的情况下启动进程 (C#),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2121911/