启动流程而不会窃取焦点(C#)

时间:2010-01-23 03:07:26

标签: c# winapi process frameworks

我需要能够启动进程(控制台和窗口)而不会窃取焦点。我发现在.NET框架中执行此操作的唯一方法是使用Microsoft.VisualBasic.AppWinStyle的Microsoft.VisualBasic.Interaction.Shell。[Minimized | Normal] NoFocus(映射到SW_SHOWMINNOACTIVE / SW_SHOWMA传递给ShellExecute)。 / p>

在我的代码的当前版本中(它确实窃取焦点),我正在使用System.Diagnostics.Process,并依赖于我提供的一些功能,而Interaction.Shell方法则没有。

2个问题(一个严肃,一个让我感到沮丧,我真的不希望得到一个好的答案)

1。)我是否正确,我别无选择,只能自己包装CreateProcess或ShellExecuteEx,或者我错过了其他一些解决方案?我真的希望避免这种情况,因为除了这种疏忽之外,Process是一个完整而有用的包装器,并且会有很多功能要实现,P / Invoke调试调用以及各种各样的痛苦。

2.。)为什么Microsoft的一个团队会创建这样一个(否则)完整的包装器,然后从ProcessWindowStyle中排除一半可能的值,而另一个团队创建了一个类似的包装器,它完全不那么完整,但提供了所有有用的窗口样式?

2 个答案:

答案 0 :(得分:12)

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;
    }
}

答案 1 :(得分:2)

看看这里:

System.Diagnostics.ProcessStartInfo procInfo = new System.Diagnostics.ProcessStartInfo();
procInfo.CreateNoWindow = true;
procInfo.UseShellExecute = true;
procInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
System.Diagnostics.Process proc = new System.Diagnostics.Process();
proc.StartInfo = procInfo;
proc.EnableRaisingEvents = true;
proc.Exited += new EventHandler(proc_Exited);
proc.OutputDataReceived += new DataReceivedEventHandler(proc_OutputDataReceived);
proc.Start(...)
// Do something with proc.Handle...
void  proc_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
   /* Do something here... */
}

void  proc_Exited(object sender, EventArgs e)
{
/* Do something here... */
}

编辑:我修改了代码以显示引发事件和处理它们的方法,同时,我已经展示了Handle属性的用法,它是进程的句柄正在运行。