有没有一种方法可以在后台运行进程?

3

有没有任何命令行或.NET方法可以在后台运行进程,隐藏它尝试打开的任何窗口?

已经尝试过:

 var process = new Process()
 {
      StartInfo = new ProcessStartInfo()
      {
          CreateNoWindow = true,
          WindowStyle = ProcessWindowStyle.Hidden,
          FileName = TheRealExecutableFileNameHere
      }
 }
 process.Start();

目前为止没有成功


可能会有帮助告诉我们你正在尝试运行哪个进程。 - Noldorin
是的,你有一个 process.Start() 的调用吗?我没有看到你在哪里分配进程和命令行参数。 - jjxtra
@Dave 为了澄清而编辑。窗口出现了,我希望它消失。 - Jader Dias
2
嗯,我刚试了一下完全相同的代码,使用 notepad.exe 作为可执行文件,运行良好,所以问题可能出在你要运行的进程上。也许它会强制显示其窗口? - Sean
1
@Jader:matlab.exe是您在.NET中尝试运行的控制台应用程序,然后它会生成一个窗口化进程吗? - Abhijeet Patel
显示剩余7条评论
14个回答

15
我查看了我的代码,它看起来和你的代码几乎一模一样:
ProcessStartInfo psi = new ProcessStartInfo(fileName, arguments)
{
   CreateNoWindow = true,
   WindowStyle = ProcessWindowStyle.Hidden,
   UseShellExecute = false,
   RedirectStandardOutput = true                                               
};

Process process = Process.Start(psi);

唯一显著的区别(除了格式和我们选择的PSI构造函数),是我使用了UseShellExecute和RedirectStandardOutput,因为我需要读取运行进程的结果。

我发现上面的代码在XP和Vista上始终运行隐藏进程。但是,我还发现,您可能会遇到同样的问题,即隐藏进程可能会启动默认情况下不隐藏的另一个进程。换句话说,如果您启动了隐藏的A进程,并且A进程又启动了B进程,则无法控制B进程的显示方式。您无法控制的窗口可能会被显示出来。

希望这能有所帮助。祝你好运。


该死!尝试得很好,但Matlab非常坚持......它没有起作用。 - Jader Dias
抱歉,这是我能提供的最好的翻译。期待看到问题的解决。 - Ben Griswold
以上代码对我有效。我正在使用7zip.exe压缩文件,并且不想显示7z.exe的命令行窗口。谢谢。 - Mehdi Anis

6

请查看Matlab Engine

如果这种方法符合您的需求,甚至有一篇有趣的文章在CodeProject上。


1
除了没有回答标题问题外,这是我问题的最佳解决方案。我应该放弃错误的方法。 - Jader Dias
除此之外,我见过有人使用WinAPI的FindWindow和SendMessage与CS_MINIMIZE或类似的东西,如果你真的想尝试一下的话。 - Kenan E. K.
4
在后台运行进程的一种方法是使用Matlab引擎。我一定漏掉了什么。 - bohdan_trotsenko
@modosansreves:请查看整个线程和评论,实际上这种情况归结为Matlab。 - Kenan E. K.
@jader dias:除非我漏掉了什么,否则你应该“接受”这个答案,因为你认为它是迄今为止最好的答案。 - Liao

5

3
更具体地说,将Process.Start(exe, args)替换为Process.Start("cmd.exe", string.Format("/c start "notitle" /B "{0}" {1}", exe, args)。如果您不想让命令窗口闪现出来,则可以使用ProcessStartInfo,并设置UseShellExecute = false。 - yoyo

3

目前我不知道没有一种纯粹的.Net方式来实现这个。

然后我想到了内核作业对象,但在UI限制中没有找到类似的选项。

所以,下一个(尚未经过验证)想法是创建一个挂起的进程,创建一个Windows钩子,然后监视CallWndProc并过滤出WM_SHOW消息。(然后,当然,恢复进程,在单独的线程中等待它终止,删除钩子)


2
我知道这个问题已经有答案了,但你可以通过调用FindWindow和ShowWindow函数来强制隐藏一个窗口。
[DllImport("user32.dll")]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

[DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);

psi = new ProcessStartInfo(); // etc..
some_process = Process.Start(psi);
System.Threading.Thread.Sleep(50); // need give the window a chance to be created
IntPtr hWnd = FindWindow(null, "name of the window");
if (hWnd != IntPtr.Zero) ShowWindow(hWnd, 0); // 0 = SW_HIDE

相当笨拙。

+1. 我认为这是一个非常简单而有效的解决方案,但我不需要Sleep(50),因为some_process.WaitToEnd()会完成。 - Jader Dias

2

如果你还没有尝试过,可以考虑使用 .Net Framework 中的 BackgroundWorker 类。它能在单独的线程上执行长时间运行的过程,以防止它们影响用户界面。建议你了解一下。


1
public Form1()
    {
        InitializeComponent();
        Form1 fm = new Form1();
        fm.ShowInTaskbar = false;
        fm.Visible = fm.ShowInTaskbar = false;
    }

非常好!


这会隐藏它自己的窗口,但不会隐藏任意进程的窗口。 - Nathan Tuggy

1

我注意到,如果CreateNoWindow = false并且Filename指向Windows可执行文件,则不会有任何作用。 如果您可以访问winform应用程序的源代码,则可以提供一个命令行参数来控制表单的默认可见性,并在Winform应用程序启动代码中执行类似以下操作:

static void Main(string[] args)
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Form1 form1 = new Form1();

        form1.Load += new EventHandler((s,o) =>
            {
              //check if the form should be shown based on command line arg
                if (args.Contains("dontShowWindow"))
                {
                    //hide it
                    form1.ShowInTaskbar = false;
                    form1.Visible = form1.ShowInTaskbar = false;
                }
            }
        );
        Application.Run(form1);
    }

在您的调用代码中,您现在可以指定“dontShowWindow”作为进程参数:
 ProcessStartInfo info = new ProcessStartInfo
        {
            CreateNoWindow = false, 
            WindowStyle = ProcessWindowStyle.Hidden,
            UseShellExecute = false, 
            FileName = @"C:\temp\testWinForm.exe",
            Arguments = "dontShowWindow"
        };
        Process.Start(info);

希望这能有所帮助


1
在问题评论中回答了您的评论。 - Jader Dias

1

这取决于您是否希望启动应用程序时将其最小化,但允许在需要时与用户交互,或者您是否希望无论发生什么情况都禁止用户访问。

如果是后者,您可以在不同的桌面上下文中运行进程以针对当前用户。

例如,登录对话框和Vista UAC使用不同的桌面上下文-在一个桌面上下文中发生的任何事情都独立于其他桌面上下文。

虽然这可能是解决问题的一种过度方法。


我想禁止用户的所有访问,无论发生什么情况。 - Jader Dias
我找不到关于“.NET桌面上下文”的文章,你能帮我找到吗? - Jader Dias
我没有找到我想要的确切页面,但是找到了一个介绍一些通常存在的标准桌面的页面。从这里开始(http://msdn.microsoft.com/en-us/library/aa375994(VS.85).aspx),四处看看,你应该能找到你需要的东西。 - Bevan
我尝试以另一个用户身份运行该进程,但这并没有解决问题。 - Jader Dias

1

实现这一点的一种非常简单的方法是创建一个服务帐户,并通过Windows任务计划程序在服务帐户用户的上下文中运行可执行文件。

您可以使用此CodeProject设置定期任务:

http://www.codeproject.com/KB/cs/tsnewlib.aspx

你可以很容易地使用C#在域或本地机器上以编程方式创建服务帐户。

http://www.codeproject.com/KB/system/OSUserMangement.aspx http://support.microsoft.com/kb/306273

作为计划任务运行的进程,除非该用户已登录,否则不会以交互方式显示在另一个用户的上下文中;因此需要使用服务帐户。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接