Condition Process.Start到给定进程的实例数

时间:2017-08-01 16:06:22

标签: c# wpf windows process

在WPF C#应用程序中,用户可以从给定菜单启动“explorer.exe”进程。

通过

照常实现
Process.Start("explorer.exe");

但是,我需要将同步进程的资源管理器数量限制为一个实例,而不是通过单击按钮将用户启动的实例数量限制为。

所以通常的方法是计算给定进程的实例数,“explorer.exe”实际上正在运行,如果有多个,则阻止Process.Start()。

问题在于我被困在计数功能中。这是我写的:

static bool CountProcess(string name) {
   return false; // by defualt it returns false.
   int counter = 0;

   while(true) {
     counter = Process.GetProcessesByName(name).length; // get the quantity of processes for a given name.
    if(counter > 1) {
       return true;
       break;
    }
  }
}

然后我调用这个函数:

 if(countProcess("explorer")) {
     // Do nothing.
 } else {
     Process p = Process.Start("explorer.exe");    
 }

然而,在构建和执行之后,应用程序在打开给定进程时会被卡住。实际上,Visual Studio不提供任何调试反馈。

如何将此功能重构为1)操作,2)有效。

1 个答案:

答案 0 :(得分:2)

为什么在CountProcess方法中有while循环?如果这应该很简单。

 if(Process.GetProcessByName("explorer").Length == 0) 
 {
    Process.Start("explorer.exe");
 }

=== UPDATE ===

好的,我开始意识到你的问题是什么。

如果这不是explorer.exe - 此代码应该有效:

    private static Process proc { get; set; }

    private void button1_Click(object sender, EventArgs e)
    {
        if (proc == null || proc.HasExited)
        {
            proc = Process.Start("explorer.exe");
        }
    }

它检查是否曾创建过程(如果是第一次 - 允许处理,如果没有 - 拒绝开始新的)如果他第二次点击,则该过程不为null但它应该是proc.HasExited ==假(如果你没有关闭它)

但是如果你运行这段代码 - 可能会启动新的资源管理器窗口,因为这个新创建的进程会立即关闭。这是因为:

  

WaitForSingleObject立即返回的原因是Explorer是一个单实例程序(好吧,有限实例)

您可以尝试按照此处的建议修改注册表:

Open explorer window and wait for it to close

但是如果这是要在其他计算机上安装的客户端应用程序,我不建议以编程方式更改某个注册表。

===更新2 ====

以下解决方案有效 - 但有一些限制(您必须添加com参考:" Microsoft Internet Controls")它允许打开一个资源管理器窗口 - 然后检查窗口是否具有相同的"启动文件夹路径"因为基础已经打开(注意代码的两个不同位置的斜杠和反斜杠差异)

    using SHDocVw;
    public bool ExistOpenedWindow()
    {
        ShellWindows _shellWindows = new SHDocVw.ShellWindows();
        string processType;

        foreach (InternetExplorer ie in _shellWindows)
        {
            //this parses the name of the process
            processType = Path.GetFileNameWithoutExtension(ie.FullName).ToLower();

            //this could also be used for IE windows with processType of "iexplore"
            if (processType.Equals("explorer") && ie.LocationURL.Contains("C:/"))
            {
                return true;
            }
        }
        return false;
    }

    private void button1_Click(object sender, EventArgs e)
    {

        if (proc == null || !ExistOpenedWindow())
        {
            proc = Process.Start("explorer.exe", @"C:\");
        }
    }

因此,如果您选择基本路径(将作为参数发送到explorer.exe")为C:/,再次单击按钮后,将检查是否存在包含此类路径的任何资源管理器窗口(你是否打开过)

在此比较:Start explorer.exe without creating a window C#

在这里:Is there a way to close a particular instance of explorer with C#?

===更新3 ====

经过一番思考 - 我已经设法找到了解决方案:

    public bool ExistOpenedWindow()
    {
        var currentlyOpenedWindows = GetAllOpenedExplorerWindow();
        return currentlyOpenedWindows.Any(t => t.HWND == ActiveOpenedWindowHwnd);
    }

    public List<InternetExplorer> GetAllOpenedExplorerWindow()
    {
        List<InternetExplorer> windows = new List<InternetExplorer>();

        ShellWindows _shellWindows = new SHDocVw.ShellWindows();
        string processType;

        foreach (InternetExplorer ie in _shellWindows)
        {                
            //this parses the name of the process
            processType = Path.GetFileNameWithoutExtension(ie.FullName).ToLower();

            //this could also be used for IE windows with processType of "iexplore"
            if (processType.Equals("explorer"))
            {
                windows.Add(ie);
            }
        }
        return windows;
    }

    public static int ActiveOpenedWindowHwnd;        

    private void button1_Click(object sender, EventArgs e)
    {
        var currentlyOpenedWindows = GetAllOpenedExplorerWindow();
        if (ActiveOpenedWindowHwnd == 0 || !ExistOpenedWindow())
        {
            Process.Start("explorer.exe");
            ShellWindows windows;
            while ((windows = new SHDocVw.ShellWindows()).Count <= currentlyOpenedWindows.Count)
            {
                Thread.Sleep(50);
            }
            var currentlyOpenedWindowsNew = GetAllOpenedExplorerWindow();
            var openedWindow = currentlyOpenedWindowsNew.Except(currentlyOpenedWindows).Single();
            ActiveOpenedWindowHwnd = openedWindow.HWND;
        }
    }