שתף באמצעות


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?

Question

Monday, February 5, 2018 4:33 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?

All replies (40)

Wednesday, February 21, 2018 8:59 PM ✅Answered

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. 


Monday, February 5, 2018 6:43 AM

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:49 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:52 AM

Hi Sam

Yes I need help converting to VB.

Thanks in advance


Monday, February 5, 2018 8:36 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 10:13 PM

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?


Tuesday, February 6, 2018 6:09 AM

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:17 PM

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 8:18 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 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.


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)

Tuesday, February 6, 2018 10:22 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:59 PM | 1 vote

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 11:18 PM | 2 votes

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:31 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


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

    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


Wednesday, February 7, 2018 9: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

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.


Wednesday, February 7, 2018 10:17 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


Wednesday, February 7, 2018 10:59 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


Saturday, February 10, 2018 11:13 AM | 1 vote

 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


Sunday, February 11, 2018 4:24 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 10:04 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 11:00 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

Monday, February 12, 2018 5:55 PM

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


Tuesday, February 13, 2018 6:11 AM

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.


Tuesday, February 13, 2018 10:28 AM | 1 vote

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

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


Wednesday, February 14, 2018 4:04 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

OOPS


Friday, February 16, 2018 4:22 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")
        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. 


Friday, February 16, 2018 4:25 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 9:51 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


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?


Wednesday, February 21, 2018 7:38 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 8:03 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:14 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.


Thursday, February 22, 2018 3:36 AM

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 7:28 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 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.


Thursday, February 22, 2018 9:02 PM

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.


Thursday, February 22, 2018 9:32 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