简体   繁体   English

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

[英]Starting a process without stealing focus (C#)

I need to be able to start processes (both console and windowed) without it stealing focus. 我需要能够启动进程(控制台和窗口)而不会窃取焦点。 The only way within the .NET framework that I found to do this is Microsoft.VisualBasic.Interaction.Shell with Microsoft.VisualBasic.AppWinStyle.[Minimized|Normal]NoFocus (which map to SW_SHOWMINNOACTIVE/SW_SHOWMA being passed through to ShellExecute). 我发现在.NET框架中执行此操作的唯一方法是使用Microsoft.VisualBasic.AppWinStyle的Microsoft.VisualBasic.Interaction.Shell。[Minimized | Normal] NoFocus(映射到SW_SHOWMINNOACTIVE / SW_SHOWMA传递给ShellExecute)。

In the current version of my code (which does steal focus), I am using System.Diagnostics.Process, and relying on some of the functionality that gives me, which the Interaction.Shell method does not. 在我的代码的当前版本(它确实窃取焦点),我使用System.Diagnostics.Process,并依赖于我提供的一些功能,Interaction.Shell方法没有。

2 questions (one serious, and one venting my frustration that I don't really expect a good answer to) 2个问题(一个严重,一个让我感到沮丧,我真的不希望得到一个好的答案)

1.) Am I correct that I have no choice but to wrap CreateProcess or ShellExecuteEx myself, or am I missing some other solution? 1.)我是否正确,我别无选择,只能自己包装CreateProcess或ShellExecuteEx,或者我错过了其他一些解决方案? I was really hoping to avoid this, as Process is such a complete and useful wrapper other than this oversight, and there would be so much functionality to implement, P/Invoke calls to debug, and all sorts of assorted pain. 我真的希望避免这种情况,因为除了这种疏忽之外,Process是一个完整而有用的包装器,并且会有很多功能要实现,P / Invoke调试调用以及各种各样的痛苦。

2.) Why would one team at Microsoft create such a (otherwise) complete wrapper, and then exclude half of the possible values from ProcessWindowStyle, while another team created a similar wrapper that was much less complete, but provided all the useful window styles? 2.)为什么Microsoft的一个团队会创建这样一个(否则)完整的包装器,然后从ProcessWindowStyle中排除一半可能的值,而另一个团队创建了一个类似的包装器,它不太完整,但提供了所有有用的窗口样式?

The VB.Net team has done much more to ease things for the developer regarding instrumentation of windows, and I see no problem adding a reference to a VB dll and use that in your C# program. VB.Net团队已经做了很多工作来为开发人员提供有关Windows工具的简化方法,我发现添加VB dll的引用并在C#程序中使用它没有问题。

It's two teams with different focus, that's all. 这是两支不同重点的球队,就是这样。 And you shouldn't feel bad about using Microsoft.VisualBasic.Interaction.Shell if it solves your issue. 如果它解决了你的问题,你应该对使用Microsoft.VisualBasic.Interaction.Shell感到不舒服。

You can also use Reflector to see the actual implementation and implement the code yourself if you don't want to reference the dll. 如果您不想引用dll,也可以使用Reflector查看实际实现并自己实现代码。

[Edit - added code example after comment to show you can combine Interaction.Shell and Process] [编辑 - 在评论后添加代码示例,表明您可以组合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();

Here I use the Shell method to kick off the process, get a handle to the process from the pid, and hook on events. 在这里,我使用Shell方法启动进程,从pid获取进程的句柄,并挂钩事件。 You can even do p.Kill() in order to abort the process. 您甚至可以执行p.Kill()以中止该过程。

[Edit - workaround for cmd.exe] [编辑 - cmd.exe的解决方法]

It's starting to become a bit hackish to my taste, but it works. 它开始变得有点像我的味道,但它的作用。 Replace "NEWWINDOW" with a random guid or something to make it unique. 用随机guid或其他东西替换“NEWWINDOW”以使其独特。

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

Have a look here: 看看这里:

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... */
}

Edit: I have modified the code to show the means of raising events and handling them, also, I have shown the usage of the Handle property which is the handle of the process that is running. 编辑:我已修改代码以显示引发事件和处理它们的方法,另外,我已经显示了Handle属性的用法,它是正在运行的进程的句柄。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM