-1

In My case

I Try to start and stop explorer.exe But when I run below code I get an exception saying "Cannot process request because the process has exited."

So How do I find The Explorer Window that opened and Close it from within the Program

And How do I trigger an event on When the opened explorer window is getting closed from outside of my program.


  public partial class Form1 : Form

{
    private readonly Process proc = new Process();
    public Form1()
    {
        InitializeComponent();
        button2.Enabled = false;
    }

    private void button1_Click(object sender, EventArgs e)
    {
        proc.StartInfo = new ProcessStartInfo {
            FileName = Environment.GetFolderPath(Environment.SpecialFolder.Windows) + "/explorer.exe",
            Arguments = @"D:\",
            UseShellExecute = false
        };
        proc.Start();
        button1.Enabled = false;
        button2.Enabled = true;
    }


    private void button2_Click(object sender, EventArgs e)
    {
        proc.Kill();
        button1.Enabled = true;
        button2.Enabled = false;
    }

    private void button3_Click(object sender, EventArgs e)
    {
        Process[]  Findit = Process.GetProcessesByName("Explorer");
        int a = Findit.Length;            
    }         
      
}
Hennie
  • 19
  • 5
  • Comments are not for extended discussion; this conversation has been [moved to chat](https://chat.stackoverflow.com/rooms/221540/discussion-on-question-by-hennie-how-to-close-a-file-explorer-window-started-fro). – Samuel Liew Sep 16 '20 at 01:07

1 Answers1

0

I have solved for now the problem myself. (thnx Jimi for all the tips :-) )

Be aware the code presented is only to share my progress so far in solving the problem and is in no way complete. failproof crash resistant sanitized or whatever.

The example starts an Automation Event Handler that checks every WindowOpenedEvent for having class name CabinetWClass and Name ":D\"

If it finds it, it Stores The ProcessID and the NativeWindowHandle in an object of a customclass AutoEle Together with the representation for the AutomationElement.

This combination should present a sort of unique identifier for the Opened File Explorer window.

The code uses the same Automation Event Handler on every WindowClosedEvent It tests if the AutoMationElement saved in autoele is still there on every WindowClosedEvent

if not the file explorer window must have been closed outside of the program.

To close the Window programmaticly I use the Windows API functions: SendMessage(); and use WM_CLOSE (set as a constant)

SendMessagege(Handle, WM_CLOSE, IntPtr.Zero, IntPtr.Zero); 

Button1 is available at start and when clicked opens a file browser on path D:\

Button 1 is getting disabled thenand button2 wil be enabled.

When either the opened browser window is close with Button2 OR from outside, the program button 2 is disabled again and button1 enabled. I am sure there are better ways and i look forward seeing some better code . I am just starting with this so everything is new :-)

    using System;
    using System.Windows.Forms;
    using System.Diagnostics;
    using System.Windows.Automation;
    using System.Runtime.InteropServices;
    
    namespace ExplorerOpenClose
    {
        //Class created to store a asomewhat unique identifier for the explorer window that opened  (Combinaton ProcessID and NativeWindowHandle
    public class AutoEle
    {
        public AutomationElement src;
        public int ProcesId=0;
        public int NativeWindowHandle=0;
    }
    public partial class Form1 : Form

    {
        private  Process proc = new Process();
        private AutoEle AutoEle = new AutoEle();
        public Form1()
        {
            InitializeComponent();
            button2.Enabled = false;
            // Start a Automation EventHanlder on window open and window close
            AutomationElement This = AutomationElement.RootElement.FindFirst(TreeScope.Subtree, Condition.TrueCondition);
            RegisterForAutomationEvents(This);
         }

        // Button1 Opens a Explorer on path "D:\  
        private void button1_Click(object sender, EventArgs e)
        {
            proc.StartInfo = new ProcessStartInfo
            {
                FileName = Environment.GetFolderPath(Environment.SpecialFolder.Windows) + "/explorer.exe",
                Arguments = @"D:\",
                UseShellExecute = false
            };
            proc.Start();           
            button1.Enabled = false;
            button2.Enabled = true;
        }

        //With Button 2 Closes The browser that opened with  Explorer on path "D:\  
        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        private static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
        private void button2_Click(object sender, EventArgs e)
        {
            button1.Enabled = true;
            button2.Enabled = false;            
            const UInt32 WM_CLOSE = 0x0010;
            // Check That the Native WindowHandle is Still the one we found before belonging to the same process 
            // And close the Window
            try
            {
                if (AutoEle.src.Current.ProcessId == AutoEle.ProcesId & AutoEle.src.Current.NativeWindowHandle == AutoEle.NativeWindowHandle)
                {
                    SendMessage(new IntPtr(AutoEle.NativeWindowHandle), WM_CLOSE, IntPtr.Zero, IntPtr.Zero);
                    AutoEle.ProcesId = 0;
                    AutoEle.NativeWindowHandle = 0;
                }
            }
            catch (ElementNotAvailableException)
            {
                // The window was allready closed. which is strang that i would end up here because i check for that 
            }
        }

        protected override void OnFormClosed(FormClosedEventArgs e)
        {
            Automation.RemoveAllEventHandlers();
            base.OnFormClosed(e);
        }

        private void RegisterForAutomationEvents(AutomationElement targetControl)
        {
            AutomationEventHandler eventHandler = new AutomationEventHandler(OnWindowOpenOrClose);
            Automation.AddAutomationEventHandler(WindowPattern.WindowClosedEvent, targetControl, TreeScope.Subtree,eventHandler);
            Automation.AddAutomationEventHandler(WindowPattern.WindowOpenedEvent, targetControl, TreeScope.Subtree, eventHandler);
        }        

        private void OnWindowOpenOrClose(object src, AutomationEventArgs e)
        {
            // Make sure the element still exists. Elements 
            // can disappear before the event is processed.
            AutomationElement sourceElement;
            try
            {
                sourceElement = src as AutomationElement;
            }
            catch (ElementNotAvailableException)
            {
                return;
            }
            if (e.EventId == WindowPattern.WindowOpenedEvent)
            {
                try
                {
                    // check if it is ClassName CabinetWClass and the drive D:\    is the name 
                    if (sourceElement.Current.ClassName == "CabinetWClass" & sourceElement.Current.Name == @"D:\")
                    {
                        // FOUND !!!!  return sourceElement.Current.ProcessId;
                    
                        // NativeWindowHandle = new IntPtr(sourceElement.Current.NativeWindowHandle);
                        //ProcessId = Process.GetProcessById(sourceElement.Current.ProcessId);
                        //ProcessId = sourceElement.Current.ProcessId;
                        //ProcToKill.Exited += new EventHandler (myProcess_Exited);   
                        AutoEle.ProcesId = sourceElement.Current.ProcessId;
                        AutoEle.NativeWindowHandle = sourceElement.Current.NativeWindowHandle;
                        AutoEle.src = sourceElement;
                    }
                }
                catch (ElementNotAvailableException)
                {

                }
                return;
            }
            if (e.EventId == WindowPattern.WindowClosedEvent)
            {
                try
                {
                    if (AutoEle.ProcesId > 0)
                    {
                        try
                        {  // Tis will provoke am exception if the process does not exist anymore which means it was closed :-) 
                            if (AutoEle.src.Current.ProcessId == AutoEle.ProcesId & AutoEle.src.Current.NativeWindowHandle == AutoEle.NativeWindowHandle);
                        }
                        catch (ElementNotAvailableException)
                        {                            
                            AutoEle.ProcesId = 0;
                            AutoEle.NativeWindowHandle = 0;
                            Invoke(new MethodInvoker(() =>
                            {
                                button1.Enabled = true;
                                button2.Enabled = false;
                            }));
                        }
                    }                       
                }
                catch (ElementNotAvailableException)
                {

                }
                return;
            }
        }        
    }
    
}
Hennie
  • 19
  • 5