none
How Do I detect if a window (a Directory window) is open in Windows Explorer and then close it (close the window) using Visual Basic 2013? RRS feed

  • Question

  • Hi. I'm trying to figure out how to detect if a directory is open (in explorer.exe) and close it.

    I designed a routine to open two folders when a button is pressed.  The problem is that I only want one instance of the folders to be open but each time the program executes it opens the folders so I get multiples of the same folders open on the screen.

    I am using the expression "Process.Start("explorer.exe", FolderToOpen)" to open the folder.

    Here is my test code:

        Private Sub btnOpenFolders_Click(sender As Object, e As EventArgs) Handles btnOpenFolders.Click
    
            Dim FolderToOpen As String = "F:\ZZTestn\Tstn 4 Opening Folders\Opened this folder"
            Dim FolderToOpenChr As String
            Dim FolderToOpenSubString As String
            Dim x As Int16
            Dim StringPointer As Int16
    
            StringPointer = 0
            x = 0
            'Parse out the folder strings here
            For x = 0 To (Len(FolderToOpen) - 1) Step 1
                FolderToOpenChr = FolderToOpen.Substring(x, 1)
                If FolderToOpenChr = "\" Then
                    StringPointer = x
                End If
            Next
            FolderToOpenSubString = FolderToOpen.Substring(0, StringPointer)
    
            Try
                Process.Start("explorer.exe", FolderToOpen)
                Process.Start("explorer.exe", FolderToOpenSubString)
    
            Catch ex As Exception
    
            End Try
    
        End Sub
    

    Does anyone know how to detect if a folder is open in WindowsExplorer and how to close that folder if it is open?

    Monday, February 5, 2018 4:33 AM

Answers

  • So after working on this for several weeks, and with the help of others that have posted here, I have finalized my example solution.  I am posting my working example here and will try to explain why I did what I did in order to get it to work as I needed. 

    First of all I needed to open Folders in Windows Explorer without generating duplicates of the same open folder.  This turned out to be easy as I simply used the statement " Process.Start(FolderToOpen) " where FolderToOpen is the fully qualified path as a string.  See the code segment for Button5.

    I also needed to be able to reliably get the fully qualified paths of all open Explorer Windows.  I needed this in my real project to determine what parts of my code I needed to execute based on what folders were open in windows explorer.  The code segment in the Sub that handles Button10 with the comment " 'To List Open Windows In text box " is that code.  Member RLWA32 provided code segments that would cull out Internet Explorer Windows an issue I had within my original code.

    Finally I needed to close certain Windows Folders in my real project depending on what code I was executing.  The example code segment for Button11 with the comment " 'To Close Open Folder Windows by handles " is that code.  Again with help from member RLWA32 and a few hours of debugging my old code I was able to put together this code segment that reliably closes open windows.

    Here is my sample code.  I hope this helps anyone else that is in need of these features in their project.

    Option Strict Off
    
    Imports System.IO
    Imports System.Runtime.InteropServices
    Imports SHDocVw
    Imports Shell32
    
    
    
    Public Class Form1
        Private MyExplorerHandles() As IntPtr
        Private Const WM_CLOSE As Integer = &H10
        Dim myprocess As Process
        Dim OpenFolder1 As String = "C:\ZZZTstn\OpenFolder1"
        Dim OpenFolder2 As String = "C:\ZZZTstn\OpenFolder2"
        Dim OpenFolder3 As String = "C:\ZZZTstn\OpenFolder3"
        Dim OpenFolder4 As String = "C:\ZZZTstn\OpenFolder4"
        Dim OpenFolder5 As String = "C:\ZZZTstn\OpenFolder5"
    
    
        Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
            ' Set the default directory of the folder browser to the current directory.
            'FolderBrowserDialog1.SelectedPath = My.Computer.FileSystem.CurrentDirectory
    
        End Sub
    
        Private Sub btnExit_Click(sender As Object, e As EventArgs) Handles btnExit.Click
            End
    
        End Sub
    
    
    
        <DllImport("user32.dll", EntryPoint:="SendMessageW")>
        Public Shared Function SendMessageW(ByVal hWnd As IntPtr, ByVal Msg As UInteger, ByVal wParam As UInteger, ByVal lParam As Integer) As Integer
        End Function
    
    
    
        Private Sub Button7_Click(sender As Object, e As EventArgs) Handles Button7.Click 'Clears the Text Box
            filesListBox.Items.Clear()
            filesListBox.Refresh()
        End Sub
    
        Private Sub Button5_Click(sender As Object, e As EventArgs) Handles Button5.Click  'To Open  Windows
            Process.Start(OpenFolder1)
            Process.Start(OpenFolder2)
            Process.Start(OpenFolder3)
            Process.Start(OpenFolder4)
            Process.Start(OpenFolder5)
        End Sub
    
    
        Private Sub Button10_Click(sender As Object, e As EventArgs) Handles Button10.Click 'To List Open Windows In text box
            Dim ItemCount As Integer
            Dim objShell As Shell32.Shell = New Shell32.Shell()
            ItemCount = 0
            filesListBox.Items.Clear()
            For Each ie As InternetExplorer In objShell.Windows()
                Dim sfv As ShellFolderView = TryCast(ie.Document, IShellFolderViewDual2)
                If Not IsNothing(sfv) Then ' If sfv is nothing the InternetExplorer object is not browsing file system
                    Dim loc As Uri = New Uri(ie.LocationURL)
                    Dim path As String = loc.LocalPath
                    ItemCount += 1
                    filesListBox.Items.Add("ItemCount " & ItemCount & "  " & path)
                End If
            Next
        End Sub
    
        Private Sub Button11_Click(sender As Object, e As EventArgs) Handles Button11.Click 'To Close Open Folder Windows by handles
            Dim objShell As Shell32.Shell = New Shell32.Shell()
            Dim ItemCount As Integer
            Dim HWNDcount As Integer
            Dim FoldersToDelete As Boolean
            Dim FolderHWNDs(50) As Long
    
            FoldersToDelete = False
            ItemCount = 0
            HWNDcount = 0
            For Each ie As InternetExplorer In objShell.Windows() 'Loop to get the HWNDs
                Dim sfv As ShellFolderView = TryCast(ie.Document, IShellFolderViewDual2)
                If Not IsNothing(sfv) Then ' If sfv is nothing the InternetExplorer object is not browsing file system
                    Dim loc As Uri = New Uri(ie.LocationURL)
                    Dim path As String = loc.LocalPath
                    ItemCount += 1
                    filesListBox.Items.Add("ItemCount " & ItemCount & "  " & path)
                    Select Case path
                        Case OpenFolder1, OpenFolder2, OpenFolder3, OpenFolder4, OpenFolder5
                            FolderHWNDs(HWNDcount) = ie.HWND
                            FoldersToDelete = True
                            filesListBox.Items.Add("Got HWND and need to close item " & ItemCount & " with HWND " & FolderHWNDs(HWNDcount) & "  " & path)
                            HWNDcount += 1
                    End Select
                End If
            Next
            If FoldersToDelete = True Then 'Close all folders in the FolderHWNDs Array
                For ItemCount = 0 To HWNDcount - 1
                    filesListBox.Items.Add("Closing " & FolderHWNDs(ItemCount))
                    SendMessageW(FolderHWNDs(ItemCount), WM_CLOSE, 0, 0)
                Next
            End If
        End Sub
    
    End Class
    

    I realized that I should have perhaps split this question into the three parts and try to address each issue I was having separately.  

    That being said, and with the understanding that I could have only got to this point by incorporating elements from everyone that spent the time to reply to this question, I am going to mark this as the Answer. 




    • Marked as answer by TJBlues Wednesday, February 21, 2018 9:05 PM
    • Edited by TJBlues Thursday, February 22, 2018 9:30 PM To provide a better solution
    Wednesday, February 21, 2018 8:59 PM

All replies

  • First you need to understand that Internet Explorer is a part of Windows and that the "Windows Explorer" and "Internet Explorer" are combined together quite closely. You must understand that otherwise you will think this cannot possibly be correct.

    Add a reference for SHDocVw.dll then try the following. Be sure to try it with both a Windows Explorer window open and an Internet Explorer window open. You will get an item for each Windows Explorer window and Internet Explorer window. I don't see a clean way to determine which items are for Windows Explorer except to use the FullName property.

    SHDocVw.ShellWindows ShellWindows = new SHDocVw.ShellWindows();
    foreach (dynamic w in ShellWindows)
    {
        SHDocVw.InternetExplorer ie = w as SHDocVw.InternetExplorer;
        Console.WriteLine($"{ie.FullName} | {ie.LocationName}");
    }
    



    Sam Hobbs
    SimpleSamples.Info

    Monday, February 5, 2018 6:43 AM
  • Sorry, I was not going to post C# code since this is VB but then I forgot and posted C#. Let me know if you heed help converting that to VB.Net.


    Sam Hobbs
    SimpleSamples.Info

    Monday, February 5, 2018 6:49 AM
  • Hi Sam

    Yes I need help converting to VB.

    Thanks in advance

    Monday, February 5, 2018 6:52 AM
  • Dim ShellWindows As New SHDocVw.ShellWindows()
    For Each w As Object In ShellWindows
    	Dim ie As SHDocVw.InternetExplorer = TryCast(w, SHDocVw.InternetExplorer)
    	Console.WriteLine($"{ie.FullName} | {ie.LocationName}")
    Next w
    



    Sam Hobbs
    SimpleSamples.Info

    Monday, February 5, 2018 8:36 AM
  • Hi Sam.

    Thanks for your suggestion.  I worked on this and finally figured out how to add the SHDocVw.dll as a reference to the project.  I think that the "Console.WriteLine($"{ie.FullName} | {ie.LocationName}")" statement is a C# statement so I converted it to VB and the code now looks like this:

            Dim ShellWindows As New SHDocVw.ShellWindows()
            For Each w As Object In ShellWindows
                Dim ie As SHDocVw.InternetExplorer = TryCast(w, SHDocVw.InternetExplorer)
                Console.WriteLine(ie.FullName & "   " & ie.LocationName)
            Next w

    This gives me the ability to detect open explorer.exe windows. However I was looking for the complete path name for the window but instead I only get part of the path.  For instance for the folder : "F:\ZZTestn\Tstn 4 Opening Folders\Opened this folder" I get "Opened this folder" from ie.LocationName and I don't see a property for the full path.  ie.path gives me "C:\Windows" and ie.LocationURL gives me "file:///F:/ZZTestn/Tstn%204%20Opening%20Folders/Opened%20this%20folder"

    Also, how can I use this to also close those windows?






    • Edited by TJBlues Tuesday, February 6, 2018 5:11 AM
    Monday, February 5, 2018 10:13 PM
  • Hi TJBlues,

    If you want to get the full path, you can take a look the following code:

     Public Sub GetListOfSelectedFilesAndFolderOfWindowsExplorer()
            Dim filename As String
            Dim selected As ArrayList = New ArrayList()
            Dim shell = New Shell32.Shell()
            For Each window As SHDocVw.InternetExplorer In New SHDocVw.ShellWindows()
                filename = Path.GetFileNameWithoutExtension(window.FullName).ToLower()
                If filename.ToLowerInvariant() = "explorer" Then
                    Dim items As Shell32.FolderItems = (CType(window.Document, Shell32.IShellFolderViewDual2)).SelectedItems()
                    For Each item As Shell32.FolderItem In items
                        MessageBox.Show(item.Path.ToString())
                        selected.Add(item.Path)
                    Next
                End If
            Next
    
              End Sub

    Best Regards,

    Cherry


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Tuesday, February 6, 2018 6:09 AM
    Moderator
  • Hi Cherry.

    Thanks for the suggestion but this code does not work.  The line: "Dim items As Shell32.FolderItems = (CType(window.Document, Shell32.IShellFolderViewDual2)).SelectedItems()" Only selects a path in an open folder that has sub path or file highlighted.  IF nothing is highlighted in that open folder then nothing is displayed.


    Tuesday, February 6, 2018 6:17 PM
  • When it comes to shell programming it is often easier to work in C++ because a good number of heavily used shell interfaces and functions are not readily available to VB.Net or C#.  Yes, you can use p/invoke and manually create interface code using <ComImport> but this can be time consuming and prone to error.  If you are willing to entertain a native C++ solution I would be happy to help in that regard.
    Tuesday, February 6, 2018 8:18 PM
  • Thanks for the suggestion and offer of help but my program is tens of thousands of lines long and has multiple forms.  Not practical to convert for just this issue.
    Tuesday, February 6, 2018 9:20 PM
  • Thanks for the suggestion and offer of help but my program is tens of thousands of lines long and has multiple forms.  Not practical to convert for just this issue.

    I wasn't suggesting rewriting all your code.  What it really comes down to is what do you want to achieve?  Find all explorer windows open to a particular folder?  Close all of them?  Find only the first one and close that?  This kind of thing could be achieved through either a DLL that can be called from VB.net (p/infoke) or through a COM object that is accessible through interop.

    Of course the best option is if someone comes back with a method to provide you with a well-formed, fully qualified path string through VB.NET.  But if that doesn't happen...

    If the problem is that you are opening two explorer windows when only one is desired then change your posted code -

                Process.Start("explorer.exe", FolderToOpen)
                Process.Start("explorer.exe", FolderToOpenSubString)


    • Edited by RLWA32 Tuesday, February 6, 2018 9:31 PM
    Tuesday, February 6, 2018 9:30 PM
  • Thanks for the suggestion and offer of help but my program is tens of thousands of lines long and has multiple forms.  Not practical to convert for just this issue.

    I wasn't suggesting rewriting all your code.  What it really comes down to is what do you want to achieve?  Find all explorer windows open to a particular folder?  Close all of them?  Find only the first one and close that?  This kind of thing could be achieved through either a DLL that can be called from VB.net (p/infoke) or through a COM object that is accessible through interop.

    Of course the best option is if someone comes back with a method to provide you with a well-formed, fully qualified path string through VB.NET.  But if that doesn't happen...

    If the problem is that you are opening two explorer windows when only one is desired then change your posted code -

                Process.Start("explorer.exe", FolderToOpen)
                Process.Start("explorer.exe", FolderToOpenSubString)


    Hi RLWA32.

    To answer your question "what do you want to achieve?" :

    I want to achieve the following two things:

    1.  I want to open folders but only if they are not already open.  So in my example I am using the following two lines to open example folders:

                Process.Start("explorer.exe", FolderToOpen)
                Process.Start("explorer.exe", FolderToOpenSubString)

    However if they are already open, I don't want to open them again (which produces multiple identical windows and is the issue in my code).  To do that I need to discover what folder windows  are already open and then write my conditional statement around the two statements above.  Hence the question I have about the discovery of open folders.

    2. The second thing I am trying to accomplish is to close windows.  In my program, once I have completed execution of certain parts of the code I want to close the forms and windows associated with that part of the code.  In my case I close a form (and return control back to a main form) and now need to figure out how to close the folder windows (that I have opened in item #1 above).  I ask this question because there is no such command "Process.Close()" or "Process.End()"

    I had been thinking of writing a separate program in C++ just to handle items like this and then use "Process.Start" to run it but I have never done that and have never passed arguments back and forth between programs.  A .dll would be good but there does not seem to be a way to generate a class library in C++ (or at least I don't see "Class Library" in the new project options in Visual C++).

    I have been trying to come up with a fix for a month now, so ya, I'm open to any suggestions or help. 

         

    Tuesday, February 6, 2018 10:22 PM
  • Once you open an explore window there is no guarantee that it will remain open since it can easily be closed by the user.  Similarly, the user can navigate in the explorer away from the folder of interest.  So working with explorer windows in this fashion can be pretty fragile.

    So that raises the question - what are you using the explorer windows to accomplish and is there a more robust way to proceed?

    Tuesday, February 6, 2018 10:59 PM
  • I don't know what you want to do with your opened folders, but maybe it could be better to embed 2 Explorer windows (with ExplorerBrowser (I has posted a basic sample in another thread, that can be improved))
    on which you will have the control because they will be inside your application.
    Tuesday, February 6, 2018 11:18 PM
  • Yes the Windows API can be frustrating. They do illogical things sometimes.

    When I was writing the code i posted previously I tried using ShellWindows similar to what Cherry suggested but it was getting exceptions. After I gave up I rem3embered that sometimes we need to use a "STAThread" instead of "MRAThread". Don't ask me what the difference is. Some applications are STAThread by default  but not console programs so that is why I was getting exceptions. So any way try the following and note that [STAThread] is necessary for this.

    using System;
    
    namespace csConsole
    {
    
        class Program
        {
            [STAThread]
            static void Main(string[] args)
            {
                try
                {
                    var shell = new Shell32.Shell();
                    foreach (SHDocVw.InternetExplorer window in shell.Windows())
                    {
                        Console.WriteLine($"{window.FullName} | {window.Path} | {window.LocationName}");
                        Shell32.FolderItems items = ((Shell32.IShellFolderViewDual2)window.Document).SelectedItems();
                        foreach (Shell32.FolderItem item in items)
                        {
                            Console.WriteLine($"\t{item.Name} | {item.Path}");
                        }
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine("Error");
                    return;
                }
            }
        }
    }
    



    Sam Hobbs
    SimpleSamples.Info

    Tuesday, February 6, 2018 11:31 PM
  •  You have not mentioned what is suppose to happen in the case of the user navigating one or both explorer windows to other folder(s).  Do you want the explorer windows to be closed in that case?

     Also,  as has been asked,  what exactly are these two explorer windows needed for?  There may very well be a much easier and/or better way to go about doing whatever it is you are doing.

     

     If you want both of the explorer windows to be closed even if one or both have been navigated away from the folder you opened them to,  then you can try the below example.  It is a bit of a hack but,  it seems to work half way decent.  However,  you would want to test it out thoroughly in your situation.

     It works by first getting all the existing explorer window handles that the user might have opened.  Then it opens the two explorer windows.  Last it compares the existing explorer window handles obtained before opening your two,  with the explorer window handles that are currently opened and finds the two handles that did not exist before you open your two.

     There is a small chance it could grab a third or fourth explorer window handle if by some crazy chance another explorer window or two just happened to be opened between the time the code gets the existing window handles and the time it compares them to find the new explorer window handles.

    Imports System.Runtime.InteropServices
    Imports SHDocVw

    Public Class Form1
        Private MyExplorerHandles() As IntPtr
        Private Const WM_CLOSE As Integer = &H10

        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            Dim ExistingExplorerHandles() As IntPtr = GetExplorerHandles()
            Process.Start("C:\Users\User1234\Pictures\Desktop Pictures")
            Process.Start("C:\")
            Threading.Thread.Sleep(1000)
            MyExplorerHandles = GetExplorerHandles.Where(Function(x) Not ExistingExplorerHandles.Contains(x)).ToArray
        End Sub

        Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
            For Each hwnd As IntPtr In MyExplorerHandles
                SendMessageW(hwnd, WM_CLOSE, 0, 0)
            Next
        End Sub

        Private Function GetExplorerHandles() As IntPtr()
            Return (From ie As Object In New ShellWindows Select New IntPtr(CType(ie, InternetExplorer).HWND)).ToArray
        End Function

        <DllImport("user32.dll", EntryPoint:="SendMessageW")>
        Public Shared Function SendMessageW(ByVal hWnd As IntPtr, ByVal Msg As UInteger, ByVal wParam As UInteger, ByVal lParam As Integer) As Integer
        End Function
    End Class
     

     


    If you say it can`t be done then i`ll try it

    • Edited by IronRazerz Wednesday, February 7, 2018 2:10 AM
    Wednesday, February 7, 2018 2:09 AM
  •  You have not mentioned what is suppose to happen in the case of the user navigating one or both explorer windows to other folder(s).  Do you want the explorer windows to be closed in that case?

     Also,  as has been asked,  what exactly are these two explorer windows needed for?  There may very well be a much easier and/or better way to go about doing whatever it is you are doing.

     

     If you want both of the explorer windows to be closed even if one or both have been navigated away from the folder you opened them to,  then you can try the below example.  It is a bit of a hack but,  it seems to work half way decent.  However,  you would want to test it out thoroughly in your situation.

     It works by first getting all the existing explorer window handles that the user might have opened.  Then it opens the two explorer windows.  Last it compares the existing explorer window handles obtained before opening your two,  with the explorer window handles that are currently opened and finds the two handles that did not exist before you open your two.

     There is a small chance it could grab a third or fourth explorer window handle if by some crazy chance another explorer window or two just happened to be opened between the time the code gets the existing window handles and the time it compares them to find the new explorer window handles.

    Imports System.Runtime.InteropServices
    Imports SHDocVw

    Public Class Form1
        Private MyExplorerHandles() As IntPtr
        Private Const WM_CLOSE As Integer = &H10

        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            Dim ExistingExplorerHandles() As IntPtr = GetExplorerHandles()
            Process.Start("C:\Users\User1234\Pictures\Desktop Pictures")
            Process.Start("C:\")
            Threading.Thread.Sleep(1000)
            MyExplorerHandles = GetExplorerHandles.Where(Function(x) Not ExistingExplorerHandles.Contains(x)).ToArray
        End Sub

        Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
            For Each hwnd As IntPtr In MyExplorerHandles
                SendMessageW(hwnd, WM_CLOSE, 0, 0)
            Next
        End Sub

    If you say it can`t be done then i`ll try it

    Hey IronRazerz. 

    Thanks for this nice piece of code.  It solves one of the problems I had in that I now do not get multiple identical windows opening.  The statement "Process.Start("C:\Users\User1234\Pictures\Desktop Pictures")" ( or in my case "Process.Start(FolderToOpen)") only allows for one open window even if it is called multiple times.  Go ahead and try that on your example.  So that solves my first problem.  I made that change to my code and tested it and confirmed that it fixed my first problem of multiple identical windows opening.

    However, the closing of the folder windows does not exactly match your description.  After pressing Button 1 I can open or close any numbers of windows and it makes no difference to closing those two windows (and only those two windows) when I press Button 2 UNLESS I had pressed Button 1 for a second time.  In that case Button 2 will not close those windows.


    • Edited by TJBlues Wednesday, February 7, 2018 9:33 PM
    Wednesday, February 7, 2018 9:31 PM
  • .... After pressing Button 1 I can open or close any numbers of windows and it makes no difference to closing those two windows (and only those two windows) when I press Button 2 UNLESS I had pressed Button 1 for a second time.  In that case Button 2 will not close those windows.

     Well,  you can take the easier route and just close the windows before opening them like this...

    Imports System.Runtime.InteropServices
    Imports SHDocVw
    
    Public Class Form1
        Private MyExplorerHandles() As IntPtr = {}
        Private Const WM_CLOSE As Integer = &H10
    
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            CloseMyExplorerWindows()
            Dim ExistingExplorerHandles() As IntPtr = GetExplorerHandles()
            Process.Start("C:\Users\User1234\Pictures\Desktop Pictures")
            Process.Start("C:\")
            Threading.Thread.Sleep(1000)
            MyExplorerHandles = GetExplorerHandles.Where(Function(x) Not ExistingExplorerHandles.Contains(x)).ToArray
        End Sub
    
        Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
            CloseMyExplorerWindows()
        End Sub
    
        Private Sub CloseMyExplorerWindows()
            For Each hwnd As IntPtr In MyExplorerHandles
                SendMessageW(hwnd, WM_CLOSE, 0, 0)
            Next
        End Sub
    
        Private Function GetExplorerHandles() As IntPtr()
            Return (From ie As Object In New ShellWindows Select New IntPtr(CType(ie, InternetExplorer).HWND)).ToArray
        End Function
    
        <DllImport("user32.dll", EntryPoint:="SendMessageW")>
        Public Shared Function SendMessageW(ByVal hWnd As IntPtr, ByVal Msg As UInteger, ByVal wParam As UInteger, ByVal lParam As Integer) As Integer
        End Function
    End Class

     


    If you say it can`t be done then i`ll try it

    • Edited by IronRazerz Wednesday, February 7, 2018 11:38 PM
    Wednesday, February 7, 2018 10:17 PM
  •  Here is another example that would be better than closing the window before opening them again as the last example does.  This keeps track of the handles in a List instead of an Array.  Instead of assigning the newly found handles to the class scoped array directly like in the last example,  it detects if one of the previously opened explorer windows has been closed first.  If one or the other has been closed,  the closed window handle(s) are removed from the list before adding the newly found handle(s),  if there are any.

     
    Imports System.Runtime.InteropServices
    Imports SHDocVw
    
    Public Class Form1
        Private MyExplorerHandles As New List(Of IntPtr)
        Private Const WM_CLOSE As Integer = &H10
    
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            Dim ExistingExplorerHandles() As IntPtr = GetExplorerHandles()
            Process.Start("C:\Users\User1234\Pictures\Desktop Pictures")
            Process.Start("C:\")
            Threading.Thread.Sleep(1000)
            Dim NewExplorerHandles() As IntPtr = GetExplorerHandles.Where(Function(x) Not ExistingExplorerHandles.Contains(x)).ToArray
            If NewExplorerHandles.Length > 0 Then
                If MyExplorerHandles.Count > 1 Then
                    If Not IsWindow(MyExplorerHandles(1)) Then MyExplorerHandles.RemoveAt(1)
                    If Not IsWindow(MyExplorerHandles(0)) Then MyExplorerHandles.RemoveAt(0)
                End If
                MyExplorerHandles.AddRange(NewExplorerHandles)
            End If
        End Sub
    
        Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
            For Each hwnd As IntPtr In MyExplorerHandles
                SendMessageW(hwnd, WM_CLOSE, 0, 0)
            Next
        End Sub
    
        Private Function GetExplorerHandles() As IntPtr()
            Return (From ie As Object In New ShellWindows Select New IntPtr(CType(ie, InternetExplorer).HWND)).ToArray
        End Function
    
        <DllImport("user32.dll", EntryPoint:="SendMessageW")>
        Private Shared Function SendMessageW(ByVal hWnd As IntPtr, ByVal Msg As UInteger, ByVal wParam As UInteger, ByVal lParam As Integer) As Integer
        End Function
    
        <DllImport("user32.dll")> Private Shared Function IsWindow(ByVal hWnd As IntPtr) As <MarshalAs(UnmanagedType.Bool)> Boolean
        End Function
    End Class


    If you say it can`t be done then i`ll try it

    • Edited by IronRazerz Wednesday, February 7, 2018 11:38 PM
    Wednesday, February 7, 2018 10:59 PM
  •  So... how did my last example or two work out for you?

    If you say it can`t be done then i`ll try it

    Saturday, February 10, 2018 11:13 AM
  •  So... how did my last example or two work out for you?

    If you say it can`t be done then i`ll try it

    Hi IronRazer.

    Thanks for all the effort you have put into exploring the issue and providing some unique suggestions. Exploring your suggestions has helped me better understand what is going on with windows explorer and how to get information for the open windows.  The issue is that you are starting out the process by first opening the two folders then checking for handles.  But I need to know what is open in windows before opening anything from my program.  The only way to do that is to get the fully qualified path of all open explorer windows and compare that to the folders I want to open. 

    The only thing I have come across that will give me something close to the fully qualified path is something like the following code:

            Dim ShellWindows As New SHDocVw.ShellWindows()
            Dim FolderURL as string
            Dim FolderToOpen As String = "F:\ZZTestn\Tstn 4 Opening Folders\Opened this folder"
            For Each w As Object In ShellWindows
                Dim ie As SHDocVw.InternetExplorer = TryCast(w, SHDocVw.InternetExplorer)
                FolderURL = ie.LocationURL
               'Write code to replace %20 with a space in the FolderURL string
                If FolderURL.Contains(FolderToOpen) Then
                    'Perform what I need to do if this is true
                End If
            Next w

    In the mean time, since I needed to get my code released, I simply used the "Process.Start(FolderToOpen)" statement to open .  This is a stop gap measure as I still need a way to close those windows when I close the application.  I may end up using some of my code to get things opened and then coupled with your suggestions to track the handles and use that to close the windows.  I'll be working on that this week.

    Sunday, February 11, 2018 4:24 AM
  • This is a stop gap measure as I still need a way to close those windows when I close the application.  I may end up using some of my code to get things opened and then coupled with your suggestions to track the handles and use that to close the windows.  I'll be working on that this week.

    As it has been said, it is simpler to embed explorer inside your application.
    Sunday, February 11, 2018 10:04 AM
  •  So... how did my last example or two work out for you?


    If you say it can`t be done then i`ll try it

    Hi IronRazer.

    Thanks for all the effort you have put into exploring the issue and providing some unique suggestions. Exploring your suggestions has helped me better understand what is going on with windows explorer and how to get information for the open windows.  The issue is that you are starting out the process by first opening the two folders then checking for handles.  But I need to know what is open in windows before opening anything from my program.  The only way to do that is to get the fully qualified path of all open explorer windows and compare that to the folders I want to open. 

    The only thing I have come across that will give me something close to the fully qualified path is something like the following code:

            Dim ShellWindows As New SHDocVw.ShellWindows()
            Dim FolderURL as string
            Dim FolderToOpen As String = "F:\ZZTestn\Tstn 4 Opening Folders\Opened this folder"
            For Each w As Object In ShellWindows
                Dim ie As SHDocVw.InternetExplorer = TryCast(w, SHDocVw.InternetExplorer)
                FolderURL = ie.LocationURL
               'Write code to replace %20 with a space in the FolderURL string
                If FolderURL.Contains(FolderToOpen) Then
                    'Perform what I need to do if this is true
                End If
            Next w

    In the mean time, since I needed to get my code released, I simply used the "Process.Start(FolderToOpen)" statement to open .  This is a stop gap measure as I still need a way to close those windows when I close the application.  I may end up using some of my code to get things opened and then coupled with your suggestions to track the handles and use that to close the windows.  I'll be working on that this week.


        Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
            Dim objShell As Shell32.Shell = New Shell32.Shell()
            For Each ie As InternetExplorer In objShell.Windows()
                Dim sfv As ShellFolderView = TryCast(ie.Document, IShellFolderViewDual2)
                If Not IsNothing(sfv) Then ' If sfv is nothing the InternetExplorer object is not browsing file system
                    Dim loc As Uri = New Uri(ie.LocationURL)
                    Dim path As String = loc.LocalPath
                End If
            Next
        End Sub
    

    Sunday, February 11, 2018 11:00 AM
  • Hi. I'm trying to figure out how to detect if a directory is open (in explorer.exe) and close it.

    I designed a routine to open two folders when a button is pressed.  The problem is that I only want one instance of the folders to be open but each time the program executes it opens the folders so I get multiples of the same folders open on the screen.

    I am using the expression "Process.Start("explorer.exe", FolderToOpen)" to open the folder.

    Here is my test code:

        Private Sub btnOpenFolders_Click(sender As Object, e As EventArgs) Handles btnOpenFolders.Click
    
            Dim FolderToOpen As String = "F:\ZZTestn\Tstn 4 Opening Folders\Opened this folder"
            Dim FolderToOpenChr As String
            Dim FolderToOpenSubString As String
            Dim x As Int16
            Dim StringPointer As Int16
    
            StringPointer = 0
            x = 0
            'Parse out the folder strings here
            For x = 0 To (Len(FolderToOpen) - 1) Step 1
                FolderToOpenChr = FolderToOpen.Substring(x, 1)
                If FolderToOpenChr = "\" Then
                    StringPointer = x
                End If
            Next
            FolderToOpenSubString = FolderToOpen.Substring(0, StringPointer)
    
            Try
                Process.Start("explorer.exe", FolderToOpen)
                Process.Start("explorer.exe", FolderToOpenSubString)
    
            Catch ex As Exception
    
            End Try
    
        End Sub

    Does anyone know how to detect if a folder is open in WindowsExplorer and how to close that folder if it is open?

    Yes. I didn't read most of the rest of the thread.

    Add a ListBox, 2 Buttons to your Form and alter the path and folder name u want to test with, and use the below code. Use windows explorer to open the test folder and the ListBox will display open folders for each explorer running. I figure once you test it you can alter it for your requirement.

    Also Razerz and them don't knows nuttin, Razerz can't even read his email. I would've posted this earlier but my smart phones Google and Chrome don't work with this site. Imagine that.

    And Razerz I wasn't let off the nut farm I escaped from the nut farm. Least that's what TommyTwoTrain told me on the phone yesterday. :)

    Below is old code and doesn't work with Option Strict set to on which I didn't bother attempting to correct. Maybe Razerz and them can help you fix that!

    Option Strict Off
    
    Imports Shell32 ' Add ref com, Microsoft Shell Controls and Automatiom
    Imports SHDocVw ' Add reference browse C:\Windows\System32\ShDocVw.Dll or Com Microsoft Internet Controls
    
    Public Class Form1
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            Me.CenterToScreen()
        End Sub
    
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            ListBox1.Items.Clear()
            Dim MShell As New Shell
            Dim TempStorage As New List(Of String)
            Dim SBW As ShellBrowserWindow
    
            On Error Resume Next
    
            For Each Item In MShell.Windows
                SBW = Item
                If SBW.LocationURL.ToString.Contains("file:///") Then
                    Dim Temp As String = SBW.LocationURL.ToString
                    Temp = Temp.Replace("file:///", "")
                    Temp = Temp.Replace("%20", " ")
                    TempStorage.Add(Temp)
                End If
            Next
            For Each Item In TempStorage
                ListBox1.Items.Add(Item.ToString)
            Next
        End Sub
    
        Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
            Dim MyFolder As String = "C:\Users\John\Desktop\Test"
            Dim OpenFolder As Object = CreateObject("shell.application")
            For Each Item In OpenFolder.Windows
                If Item.Document.Folder.Self.Path = MyFolder Then
                    Item.Quit()
                End If
            Next
        End Sub
    
    End Class


    La vida loca



    • Edited by Mr. Monkeyboy Monday, February 12, 2018 11:26 PM
    • Marked as answer by TJBlues Wednesday, February 14, 2018 4:04 AM
    • Unmarked as answer by TJBlues Friday, February 16, 2018 3:38 PM
    Monday, February 12, 2018 5:55 PM

  • Does anyone know how to detect if a folder is open in WindowsExplorer and how to close that folder if it is open?

    Yes. I didn't read most of the rest of the thread.

    Add a ListBox, 2 Buttons to your Form and alter the path and folder name u want to test with, and use the below code. Use windows explorer to open the test folder and the ListBox will display open folders for each explorer running. I figure once you test it you can alter it for your requirement.

    Also Razerz and them don't knows nuttin, Razerz can't even read his email. I would've posted this earlier but my smart phones Google and Chrome don't work with this site. Imagine that.

    And Razerz I wasn't let off the nut farm I escaped from the nut farm. Least that's what TommyTwoTrain told me on the phone yesterday. :)

    Below is old code and doesn't work with Option Strict set to on which I didn't bother attempting to correct. Maybe Razerz and them can help you fix that!

    Option Strict Off
    
    Imports Shell32 ' Add ref com, Microsoft Shell Controls and Automatiom
    Imports SHDocVw ' Add reference browse C:\Windows\System32\ShDocVw.Dll or Com Microsoft Internet Controls
    
    Public Class Form1
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            Me.CenterToScreen()
        End Sub
    
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            ListBox1.Items.Clear()
            Dim MShell As New Shell
            Dim TempStorage As New List(Of String)
            Dim SBW As ShellBrowserWindow
    
            On Error Resume Next
    
            For Each Item In MShell.Windows
                SBW = Item
                If SBW.LocationURL.ToString.Contains("file:///") Then
                    Dim Temp As String = SBW.LocationURL.ToString
                    Temp = Temp.Replace("file:///", "")
                    Temp = Temp.Replace("%20", " ")
                    TempStorage.Add(Temp)
                End If
            Next
            For Each Item In TempStorage
                ListBox1.Items.Add(Item.ToString)
            Next
        End Sub
    
        Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
            Dim MyFolder As String = "C:\Users\John\Desktop\Test"
            Dim OpenFolder As Object = CreateObject("shell.application")
            For Each Item In OpenFolder.Windows
                If Item.Document.Folder.Self.Path = MyFolder Then
                    Item.Quit()
                End If
            Next
        End Sub
    
    End Class


    La vida loca



    Hi Loca.

    At first glance it worked but I get an error.  See above for the error.  You also point out (as I had finally figured out above), the only way to get a fully qualified path for the open windows is to use  '??.LocationURL.ToSting' and then parse out the extraneous characters.  I admit that I am still working through how you close the windows but this seems to contain everything I need to solve my problem.  Thanks.


    • Marked as answer by TJBlues Tuesday, February 13, 2018 6:12 AM
    • Unmarked as answer by TJBlues Wednesday, February 14, 2018 4:04 AM
    • Edited by TJBlues Friday, February 16, 2018 4:28 PM Found an error
    Tuesday, February 13, 2018 6:11 AM
  • OK this is what I was looking for.  You also point out (as I had finally figured out above), the only way to get a fully qualified path for the open windows is to use  '??.LocationURL.ToSting' and then parse out the extraneous characters.

    I guess you didn't notice my earlier post -

        Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
            Dim objShell As Shell32.Shell = New Shell32.Shell()
            For Each ie As InternetExplorer In objShell.Windows()
                Dim sfv As ShellFolderView = TryCast(ie.Document, IShellFolderViewDual2)
                If Not IsNothing(sfv) Then ' If sfv is nothing the InternetExplorer object is not browsing file system
                    Dim loc As Uri = New Uri(ie.LocationURL)
                    Dim path As String = loc.LocalPath
                End If
            Next
        End Sub

    • Proposed as answer by Mr. Monkeyboy Wednesday, February 14, 2018 7:43 AM
    Tuesday, February 13, 2018 10:28 AM
  • You're welcome. But why did you mark your own post as the answer? 🤤 Also RLWA32 HAS A METHOD TO CONVERT URL TO PATH. See the code in his or her If statement at the bottom of the displayed code window. Then mark that post and my post as the answers or something.

    La vida loca


    Tuesday, February 13, 2018 1:41 PM
  • You're welcome. But why did you mark your own post as the answer? 🤤 Also RLWA32 HAS A METHOD TO CONVERT URL TO PATH. See the code in his or her If statement at the bottom of the displayed code window. Then mark that post and my post as the answers or something.

    La vida loca


    OOPS
    Wednesday, February 14, 2018 4:04 AM
  • Below is old code and doesn't work with Option Strict set to on which I didn't bother attempting to correct. Maybe Razerz and them can help you fix that!

    Option Strict Off
    
    Imports Shell32 ' Add ref com, Microsoft Shell Controls and Automatiom
    Imports SHDocVw ' Add reference browse C:\Windows\System32\ShDocVw.Dll or Com Microsoft Internet Controls
    
    Public Class Form1
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            Me.CenterToScreen()
        End Sub
    
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            ListBox1.Items.Clear()
            Dim MShell As New Shell
            Dim TempStorage As New List(Of String)
            Dim SBW As ShellBrowserWindow
    
            On Error Resume Next
    
            For Each Item In MShell.Windows
                SBW = Item
                If SBW.LocationURL.ToString.Contains("file:///") Then
                    Dim Temp As String = SBW.LocationURL.ToString
                    Temp = Temp.Replace("file:///", "")
                    Temp = Temp.Replace("%20", " ")
                    TempStorage.Add(Temp)
                End If
            Next
            For Each Item In TempStorage
                ListBox1.Items.Add(Item.ToString)
            Next
        End Sub
    
        Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
            Dim MyFolder As String = "C:\Users\John\Desktop\Test"
            Dim OpenFolder As Object = CreateObject("shell.application")
            For Each Item In OpenFolder.Windows
                If Item.Document.Folder.Self.Path = MyFolder Then
                    Item.Quit()
                End If
            Next
        End Sub
    
    End Class



    La vida loca

    Hey MonkeyBoy.  At first glance this seemed to work but after using it for a while I found that it causes an error in the following Sub:

        Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
            Dim MyFolder As String = "C:\Users\John\Desktop\Test"
            Dim OpenFolder As Object = CreateObject("shell.application")
            For Each Item In OpenFolder.Windows
                If Item.Document.Folder.Self.Path = MyFolder Then
                    Item.Quit()
                End If
            Next
        End Sub
    

    The error is that if there is an Internet Explorer window open I get the following error:  "Public member 'Folder' on type 'HTMLDocumentClass' not found."  So I guess I need to check if "Item" is not an HTMLDocumentClass or just use a try - catch in the code. 

    • Edited by TJBlues Friday, February 16, 2018 4:25 PM
    Friday, February 16, 2018 4:22 PM
  • The error is that if there is an Internet Explorer window open I get the following error:  "Public member 'Folder' on type 'HTMLDocumentClass' not found."  So I guess I need to check if "Item" is not an HTMLDocumentClass or just use a try - catch in the code. 


    And for the third time - See my prior suggestion which solves the above problem as well as returning a proper path string -

        Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
            Dim objShell As Shell32.Shell = New Shell32.Shell()
            For Each ie As InternetExplorer In objShell.Windows()
                Dim sfv As ShellFolderView = TryCast(ie.Document, IShellFolderViewDual2)
                If Not IsNothing(sfv) Then ' If sfv is nothing the InternetExplorer object is not browsing file system
                    Dim loc As Uri = New Uri(ie.LocationURL)
                    Dim path As String = loc.LocalPath
                End If
            Next
        End Sub

    Friday, February 16, 2018 4:25 PM
  • Below is old code and doesn't work with Option Strict set to on which I didn't bother attempting to correct. Maybe Razerz and them can help you fix that!

    Option Strict Off
    
    Imports Shell32 ' Add ref com, Microsoft Shell Controls and Automatiom
    Imports SHDocVw ' Add reference browse C:\Windows\System32\ShDocVw.Dll or Com Microsoft Internet Controls
    
    Public Class Form1
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            Me.CenterToScreen()
        End Sub
    
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            ListBox1.Items.Clear()
            Dim MShell As New Shell
            Dim TempStorage As New List(Of String)
            Dim SBW As ShellBrowserWindow
    
            On Error Resume Next
    
            For Each Item In MShell.Windows
                SBW = Item
                If SBW.LocationURL.ToString.Contains("file:///") Then
                    Dim Temp As String = SBW.LocationURL.ToString
                    Temp = Temp.Replace("file:///", "")
                    Temp = Temp.Replace("%20", " ")
                    TempStorage.Add(Temp)
                End If
            Next
            For Each Item In TempStorage
                ListBox1.Items.Add(Item.ToString)
            Next
        End Sub
    
        Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
            Dim MyFolder As String = "C:\Users\John\Desktop\Test"
            Dim OpenFolder As Object = CreateObject("shell.application")9
            For Each Item In OpenFolder.Windows
                If Item.Document.Folder.Self.Path = MyFolder Then
                    Item.Quit()
                End If
            Next
        End Sub
    
    End Class



    La vida loca

    Hey MonkeyBoy.  At first glance this seemed to work but after using it for a while I found that it causes an error in the following Sub:

        Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
            Dim MyFolder As String = "C:\Users\John\Desktop\Test"
            Dim OpenFolder As Object = CreateObject("shell.application")
            For Each Item In OpenFolder.Windows
                If Item.Document.Folder.Self.Path = MyFolder Then
                    Item.Quit()
                End If
            Next
        End Sub

    The error is that if there is an Internet Explorer window open I get the following error:  "Public member 'Folder' on type 'HTMLDocumentClass' not found."  So I guess I need to check if "Item" is not an HTMLDocumentClass or just use a try - catch in the code. 

    Well windows explorer is not internet explorer. The code I provided is to detect if windows explorer has a folder open only.

    Also if rlwa32's coe works try it. And rlwa32's code using uri for the qualified path will auto parse the path out. You can also try disposing of the 'OpenFolder object after using it in case that mey resolve any issues. I only have a smart phone and have to drive 16 miles to the library to upload tested code so I can't assist much further really.


    La vida loca

    Friday, February 16, 2018 9:51 PM

  •     Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
            Dim objShell As Shell32.Shell = New Shell32.Shell()
            For Each ie As InternetExplorer In objShell.Windows()
                Dim sfv As ShellFolderView = TryCast(ie.Document, IShellFolderViewDual2)
                If Not IsNothing(sfv) Then ' If sfv is nothing the InternetExplorer object is not browsing file system
                    Dim loc As Uri = New Uri(ie.LocationURL)
                    Dim path As String = loc.LocalPath
                End If
            Next
        End Sub

    Thanks.  This does provide another way of providing a list of open windows but the question remains, how do I close a window?

    • Edited by TJBlues Wednesday, February 21, 2018 7:27 PM
    Wednesday, February 21, 2018 7:26 PM

  •     Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
            Dim objShell As Shell32.Shell = New Shell32.Shell()
            For Each ie As InternetExplorer In objShell.Windows()
                Dim sfv As ShellFolderView = TryCast(ie.Document, IShellFolderViewDual2)
                If Not IsNothing(sfv) Then ' If sfv is nothing the InternetExplorer object is not browsing file system
                    Dim loc As Uri = New Uri(ie.LocationURL)
                    Dim path As String = loc.LocalPath
                End If
            Next
        End Sub

    Thanks.  This does provide another way of providing a list of open windows but the question remains, how do I close a window?

    Same as before.  Get the HWND from the InternetExplorer object and send it a WM_CLOSE message.
    Wednesday, February 21, 2018 7:38 PM
  • Also if rlwa32's coe works try it. And rlwa32's code using uri for the qualified path will auto parse the path out. You can also try disposing of the 'OpenFolder object after using it in case that mey resolve any issues. I only have a smart phone and have to drive 16 miles to the library to upload tested code so I can't assist much further really.


    La vida loca

    OK and thanks for all your help. You have given me a few ideas.  With your help and the help of others that have posted here I have written some code that will open Folder Windows and list out all folder windows that are open in Windows Explorer.  Unfortunately I had to write some pretty convoluted code to reliably close Folder Windows.   In all cases I had to use a try and catch to ensure I didn't get an unhandled error when the user also has an Internet Explorer window open.
    Wednesday, February 21, 2018 8:03 PM
  •  Unfortunately I had to write some pretty convoluted code to reliably close Folder Windows.   In all cases I had to use a try and catch to ensure I didn't get an unhandled error when the user also has an Internet Explorer window open.
    If you think about the code I posted that culls out Internet Explorer browsers from file system Explorer windows you should be able to use the same concept to ensure that you only attempt to close an InternetExplorer object that is looking at the file system.
    Wednesday, February 21, 2018 8:14 PM
  • So after working on this for several weeks, and with the help of others that have posted here, I have finalized my example solution.  I am posting my working example here and will try to explain why I did what I did in order to get it to work as I needed. 

    First of all I needed to open Folders in Windows Explorer without generating duplicates of the same open folder.  This turned out to be easy as I simply used the statement " Process.Start(FolderToOpen) " where FolderToOpen is the fully qualified path as a string.  See the code segment for Button5.

    I also needed to be able to reliably get the fully qualified paths of all open Explorer Windows.  I needed this in my real project to determine what parts of my code I needed to execute based on what folders were open in windows explorer.  The code segment in the Sub that handles Button10 with the comment " 'To List Open Windows In text box " is that code.  Member RLWA32 provided code segments that would cull out Internet Explorer Windows an issue I had within my original code.

    Finally I needed to close certain Windows Folders in my real project depending on what code I was executing.  The example code segment for Button11 with the comment " 'To Close Open Folder Windows by handles " is that code.  Again with help from member RLWA32 and a few hours of debugging my old code I was able to put together this code segment that reliably closes open windows.

    Here is my sample code.  I hope this helps anyone else that is in need of these features in their project.

    Option Strict Off
    
    Imports System.IO
    Imports System.Runtime.InteropServices
    Imports SHDocVw
    Imports Shell32
    
    
    
    Public Class Form1
        Private MyExplorerHandles() As IntPtr
        Private Const WM_CLOSE As Integer = &H10
        Dim myprocess As Process
        Dim OpenFolder1 As String = "C:\ZZZTstn\OpenFolder1"
        Dim OpenFolder2 As String = "C:\ZZZTstn\OpenFolder2"
        Dim OpenFolder3 As String = "C:\ZZZTstn\OpenFolder3"
        Dim OpenFolder4 As String = "C:\ZZZTstn\OpenFolder4"
        Dim OpenFolder5 As String = "C:\ZZZTstn\OpenFolder5"
    
    
        Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
            ' Set the default directory of the folder browser to the current directory.
            'FolderBrowserDialog1.SelectedPath = My.Computer.FileSystem.CurrentDirectory
    
        End Sub
    
        Private Sub btnExit_Click(sender As Object, e As EventArgs) Handles btnExit.Click
            End
    
        End Sub
    
    
    
        <DllImport("user32.dll", EntryPoint:="SendMessageW")>
        Public Shared Function SendMessageW(ByVal hWnd As IntPtr, ByVal Msg As UInteger, ByVal wParam As UInteger, ByVal lParam As Integer) As Integer
        End Function
    
    
    
        Private Sub Button7_Click(sender As Object, e As EventArgs) Handles Button7.Click 'Clears the Text Box
            filesListBox.Items.Clear()
            filesListBox.Refresh()
        End Sub
    
        Private Sub Button5_Click(sender As Object, e As EventArgs) Handles Button5.Click  'To Open  Windows
            Process.Start(OpenFolder1)
            Process.Start(OpenFolder2)
            Process.Start(OpenFolder3)
            Process.Start(OpenFolder4)
            Process.Start(OpenFolder5)
        End Sub
    
    
        Private Sub Button10_Click(sender As Object, e As EventArgs) Handles Button10.Click 'To List Open Windows In text box
            Dim ItemCount As Integer
            Dim objShell As Shell32.Shell = New Shell32.Shell()
            ItemCount = 0
            filesListBox.Items.Clear()
            For Each ie As InternetExplorer In objShell.Windows()
                Dim sfv As ShellFolderView = TryCast(ie.Document, IShellFolderViewDual2)
                If Not IsNothing(sfv) Then ' If sfv is nothing the InternetExplorer object is not browsing file system
                    Dim loc As Uri = New Uri(ie.LocationURL)
                    Dim path As String = loc.LocalPath
                    ItemCount += 1
                    filesListBox.Items.Add("ItemCount " & ItemCount & "  " & path)
                End If
            Next
        End Sub
    
        Private Sub Button11_Click(sender As Object, e As EventArgs) Handles Button11.Click 'To Close Open Folder Windows by handles
            Dim objShell As Shell32.Shell = New Shell32.Shell()
            Dim ItemCount As Integer
            Dim HWNDcount As Integer
            Dim FoldersToDelete As Boolean
            Dim FolderHWNDs(50) As Long
    
            FoldersToDelete = False
            ItemCount = 0
            HWNDcount = 0
            For Each ie As InternetExplorer In objShell.Windows() 'Loop to get the HWNDs
                Dim sfv As ShellFolderView = TryCast(ie.Document, IShellFolderViewDual2)
                If Not IsNothing(sfv) Then ' If sfv is nothing the InternetExplorer object is not browsing file system
                    Dim loc As Uri = New Uri(ie.LocationURL)
                    Dim path As String = loc.LocalPath
                    ItemCount += 1
                    filesListBox.Items.Add("ItemCount " & ItemCount & "  " & path)
                    Select Case path
                        Case OpenFolder1, OpenFolder2, OpenFolder3, OpenFolder4, OpenFolder5
                            FolderHWNDs(HWNDcount) = ie.HWND
                            FoldersToDelete = True
                            filesListBox.Items.Add("Got HWND and need to close item " & ItemCount & " with HWND " & FolderHWNDs(HWNDcount) & "  " & path)
                            HWNDcount += 1
                    End Select
                End If
            Next
            If FoldersToDelete = True Then 'Close all folders in the FolderHWNDs Array
                For ItemCount = 0 To HWNDcount - 1
                    filesListBox.Items.Add("Closing " & FolderHWNDs(ItemCount))
                    SendMessageW(FolderHWNDs(ItemCount), WM_CLOSE, 0, 0)
                Next
            End If
        End Sub
    
    End Class
    

    I realized that I should have perhaps split this question into the three parts and try to address each issue I was having separately.  

    That being said, and with the understanding that I could have only got to this point by incorporating elements from everyone that spent the time to reply to this question, I am going to mark this as the Answer. 




    • Marked as answer by TJBlues Wednesday, February 21, 2018 9:05 PM
    • Edited by TJBlues Thursday, February 22, 2018 9:30 PM To provide a better solution
    Wednesday, February 21, 2018 8:59 PM
  • If you think about the code I posted that culls out Internet Explorer browsers from file system Explorer windows you should be able to use the same concept to ensure that you only attempt to close an InternetExplorer object that is looking at the file system.
    Thanks but I have no idea what you mean by that.
    Thursday, February 22, 2018 3:36 AM

  • Thanks.  This does provide another way of providing a list of open windows but the question remains, how do I close a window?

    Same as before.  Get the HWND from the InternetExplorer object and send it a WM_CLOSE message.

    Thanks this does do a good job of culling out the internet Explorer Windows but does not fix the issue of having the convoluted code because it does not reliably close windows. Just like my previous example I have to loop through to close windows, then check to see if they were closed and go back and try again until all the folders of interest are closed.  Here is my example using the WM_CLOSE message

        Private Sub Button9_Click(sender As Object, e As EventArgs) Handles Button9.Click 'Close open folders
            Dim ItemCount As Integer
            Dim objShell As Shell32.Shell = New Shell32.Shell()
            Dim MyHWND As Long
            Dim FoldersToDelete As Boolean
    
            FoldersToDelete = True
            ItemCount = 0
            While FoldersToDelete = True
                For Each ie As InternetExplorer In objShell.Windows() 'Loop to close folders
                    FoldersToDelete = False
                    Dim sfv As ShellFolderView = TryCast(ie.Document, IShellFolderViewDual2)
                    If Not IsNothing(sfv) Then ' If sfv is nothing the InternetExplorer object is not browsing file system
                        Dim loc As Uri = New Uri(ie.LocationURL)
                        Dim path As String = loc.LocalPath
                        ItemCount += 1
                        filesListBox.Items.Add("ItemCount " & ItemCount & "  " & path)
                        Select Case path
                            Case OpenFolder1, OpenFolder2, OpenFolder3, OpenFolder4, OpenFolder5
                                MyHWND = ie.HWND
                                SendMessageW(MyHWND, WM_CLOSE, 0, 0)
                                filesListBox.Items.Add("Closing folder " & MyHWND & "  " & path)
                        End Select
                    End If
                Next
                For Each ie As InternetExplorer In objShell.Windows() 'Loop to Check if the folders were closed
                    Dim sfv As ShellFolderView = TryCast(ie.Document, IShellFolderViewDual2)
                    If Not IsNothing(sfv) Then ' If sfv is nothing the InternetExplorer object is not browsing file system
                        Dim loc As Uri = New Uri(ie.LocationURL)
                        Dim path As String = loc.LocalPath
                        Select Case path
                            Case OpenFolder1, OpenFolder2, OpenFolder3, OpenFolder4, OpenFolder5
                                FoldersToDelete = True
                        End Select
                    End If
                Next
            End While
        End Sub
    

    Thursday, February 22, 2018 7:28 AM

  • Same as before.  Get the HWND from the InternetExplorer object and send it a WM_CLOSE message.

    Thanks this does do a good job of culling out the internet Explorer Windows but does not fix the issue of having the convoluted code because it does not reliably close windows. Just like my previous example I have to loop through to close windows, then check to see if they were closed and go back and try again until all the folders of interest are closed.

    I don't know what you mean by "does not reliably close windows."

    It seems you are suggesting that after you obtain a valid window handle that the window does not close after it receives a WM_CLOSE message.  Are you suggesting that you have discovered a bug in Windows?

    I commented early in this thread that trying to work with Explorer windows in this fashion is inherently fragile. I also asked what purpose opening and closing Explorer windows served with a view towards identifying a different, controllable and robust way to achieve your objectives.  Others also asked the same question.  So far, that question remains unanswered.
    • Edited by RLWA32 Thursday, February 22, 2018 12:00 PM
    Thursday, February 22, 2018 11:52 AM

  • Same as before.  Get the HWND from the InternetExplorer object and send it a WM_CLOSE message.

    Thanks this does do a good job of culling out the internet Explorer Windows but does not fix the issue of having the convoluted code because it does not reliably close windows. Just like my previous example I have to loop through to close windows, then check to see if they were closed and go back and try again until all the folders of interest are closed.

    I don't know what you mean by "does not reliably close windows."

    It seems you are suggesting that after you obtain a valid window handle that the window does not close after it receives a WM_CLOSE message.  Are you suggesting that you have discovered a bug in Windows?

    I commented early in this thread that trying to work with Explorer windows in this fashion is inherently fragile. I also asked what purpose opening and closing Explorer windows served with a view towards identifying a different, controllable and robust way to achieve your objectives.  Others also asked the same question.  So far, that question remains unanswered.

    I am absolutely not suggesting there is a bug in Windows where it does not close a window after it receives a WM_CLOSE message.  I am suggesting that the code does not send all the close messages it needs to send.  Let me explain:

    After a few hours of debugging and working with the code I had posted (the Button9 code above) I found that something strange happens if you are closing windows while trying to determine what folders are open.  It took me a while to grasp what may be happening as the numbers of open folders are reduced.  This is what I think is happening in the Button9 code:

    • In my test case I have 10 folders open and 5 of these are the ones I want to close.
    • The conditional statement for looping through to detect open windows and closing them is "For Each ie As InternetExplorer In objShell.Windows() 'Loop to close folders"
    • When the program executes it loops and detects a window that needs it to close and sends the WM_CLOSE message and Windows closes the window associated with that handle.  It then evaluates if it has examined all the open windows.  The code will execute a couple of these loops and the numbers of open windows will reduce.  Some where in its evaluation of "For Each is As......" which I interpret as 'have I examined all ie objects' it determines it has completed examining all open windows and exits.  This happens after 1, 2, 3 or 4 windows have been closed and is somewhat random.  Thus the need for the outer loop to detect if all the open folder windows of interest were actually closed.

    So with that in mind I thought that a better way to accomplish what I want is to split the code into 2 parts. The first part detects what folders are open that I want to close and records the handle in an array and the second part loops through that array and sends the WM_CLOSE message.   The example code looks like this:

        Private Sub Button11_Click(sender As Object, e As EventArgs) Handles Button11.Click
            Dim objShell As Shell32.Shell = New Shell32.Shell()
            Dim ItemCount As Integer
            Dim HWNDcount As Integer
            Dim FoldersToDelete As Boolean
            Dim FolderHWNDs(50) As Long
    
            FoldersToDelete = False
            ItemCount = 0
            HWNDcount = 0
            For Each ie As InternetExplorer In objShell.Windows() 'Loop to get the HWNDs
                Dim sfv As ShellFolderView = TryCast(ie.Document, IShellFolderViewDual2)
                If Not IsNothing(sfv) Then ' If sfv is nothing the InternetExplorer object is not browsing file system
                    Dim loc As Uri = New Uri(ie.LocationURL)
                    Dim path As String = loc.LocalPath
                    ItemCount += 1
                    filesListBox.Items.Add("ItemCount " & ItemCount & "  " & path)
                    Select Case path
                        Case OpenFolder1, OpenFolder2, OpenFolder3, OpenFolder4, OpenFolder5
                            FolderHWNDs(HWNDcount) = ie.HWND
                            FoldersToDelete = True
                            filesListBox.Items.Add("Got HWND and need to close item " & ItemCount & " with HWND " & FolderHWNDs(HWNDcount) & "  " & path)
                            HWNDcount += 1
                    End Select
                End If
            Next
            If FoldersToDelete = True Then 'Close all folders in the FolderHWNDs Array
                For ItemCount = 0 To HWNDcount - 1
                    filesListBox.Items.Add("Closing " & FolderHWNDs(ItemCount))
                    SendMessageW(FolderHWNDs(ItemCount), WM_CLOSE, 0, 0)
                Next
            End If
        End Sub

    So with your help I was able to get a better way of listing out open Windows Folders (by culling out the Internet Explorer windows) and reliably closing those folders that I want to close.  Thanks for your help.


    • Edited by TJBlues Thursday, February 22, 2018 9:05 PM
    Thursday, February 22, 2018 9:02 PM
  • If you are interested, following alternative will directly open an Explorer window to a specified file system path and enable you to directly associate the resulting InternetExplorer object with its HWND.  Consequently, you would have no need to use the shell windows collection.

    Error checking is completely omitted

    Public Class Form1
        <DllImport("User32.dll", CallingConvention:=CallingConvention.StdCall)>
        Public Shared Function PostMessage(ByVal hwnd As IntPtr, msg As UInt16, wparam As Integer, lparam As Integer) As Integer
        End Function
    
        Dim ShellBrowser As Guid = New Guid("c08afd90-f2a1-11d1-8455-00a0c91f3880")
        Dim hwnd As IntPtr
        Dim WM_CLOSE As Integer = &H10
    
        Private Sub OnOpen(sender As Object, e As EventArgs) Handles Button1.Click
            Dim objShellBrowser As Object
            Dim IE As InternetExplorer
            Dim url As Uri = New Uri("C:\Users\RLWA32\Documents")
            objShellBrowser = Activator.CreateInstance(Type.GetTypeFromCLSID(ShellBrowser))
            IE = objShellBrowser
            IE.Navigate2(url.AbsoluteUri)
            IE.Visible = True
            hwnd = IE.HWND
        End Sub
    
        Private Sub OnClose(sender As Object, e As EventArgs) Handles Button2.Click
            PostMessage(hwnd, WM_CLOSE, 0, 0)
        End Sub
    End Class
    

    Thursday, February 22, 2018 9:32 PM