1

In a WPF C# app, users can launch the "explorer.exe" process from a given menu.

This is achieved as usual, with

Process.Start("explorer.exe");

However, I need to restrict the explorer quantity of simultaneous processes to one instance, instead of as many instances as the user starts by clicking on a button.

So the usual way is to count how many instance of the given process, "explorer.exe" are actually running and if there is more than one, then block the Process.Start().

The issue is that I'm stucked in the counting function. here is what I wrote:

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

Then I invoke the function as this:

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

However after build and execute, the app gets stucked when opening the given process. Indeed, Visual Studio does not give any debug feedback.

How can this function be refactored to be 1) operational, 2) efficient.

digitai
  • 1,870
  • 2
  • 20
  • 37

1 Answers1

2

Why there is while loop in CountProcess method? It should be simple if.

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

=== UPDATE ===

Ok, I'm starting to realize what is your problem.

If this wasn't explorer.exe - this code should work:

    private static Process proc { get; set; }

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

It checks whether Process was ever created (if first time - allow processing, if not - deny starting a new one) If he clicks for the second time, the process is not null but it SHOULD BE as proc.HasExited == false (if you didn't close it)

But if you run this code - probably starting new explorer window will be possible because this newly created process is being closed immediately. And this is because:

The reason that WaitForSingleObject returns immediately is that Explorer is a single-instance program (well, limited-instance)

You can try modifying the registry as proposed here :

Open explorer window and wait for it to close

But if this to be client application to be installed on others computer, I wouldn't advise changing programmatically someone registry.

=== UPDATE 2 ====

This solution below works - but with some restrictions (You must add com reference: "Microsoft Internet Controls") It allows to open one explorer window - and then checks whether window with the same "start folder path" as the base is already opened (watch out for slash and backslash difference in two different places of the code)

    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:\");
        }
    }

So if you choose your base path (which will be sent as argument to explorer.exe") to be C:/, after clicking button once again, it will check whether there is ANY explorer window containing such path (opened by you or not)

Compare here: Start explorer.exe without creating a window C#

And here: Is there a way to close a particular instance of explorer with C#?

=== UPDATE 3 ====

After some thoughts - i've managed to come to working solution:

    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;
        }
    }
Piotr
  • 1,155
  • 12
  • 29
  • The issue with this solution is that the value is always 1, Why? as defualt, there is always one explorer.exe process running, however, when launching more processes, the count value is the same, 1. Using .length or .Count(). – digitai Aug 01 '17 at 17:03
  • really appreciate your answer however, it allows the user to launch as many as processes as he wants. I need to call just one explorer.exe process, one after the default running process, so by counting processes, one should call the process when there is just one, and not call the process where there are more than 1. However the .Length or .Count() methods, always return the value of 1, no matter how many explorer.exe process are running. – digitai Aug 01 '17 at 20:40
  • I've added "update 2" It is working right now. At least partially. – Piotr Aug 01 '17 at 21:38