4

I'm re-visiting a tool that I wrote in VB.Net for my helpdesk team a while back and want to add a couple of checkboxes to replicate the same function that Windows uses to show hidden files and folders / re-hide, as well as protected operating system files.

I know I can do this by editing a registry entry and restarting explorer.exe, but that closes all open Explorer Windows and I don't want that.

Does anyone know how Windows is able to do this by a simple click of a checkbox and how I may be able to code it in VB.net?

Any input on this is greatly appreciated in advance.


EDIT: So it looks like I have found a refresh method that works to refresh Windows Explorer / File Explorer which can be applied to Drarig's answer below but I am having trouble converting it to VB.net as the original example is in C#.

'Original at http://stackoverflow.com/questions/2488727/refresh-windows-explorer-in-win7

Private Sub refreshExplorer(ByVal explorerType As String)
    Dim CLSID_ShellApplication As Guid = Guid.Parse("13709620-C279-11CE-A49E-444553540000")
    Dim shellApplicationType As Type = Type.GetTypeFromCLSID(CLSID_ShellApplication, True)
    Dim shellApplication As Object = Activator.CreateInstance(shellApplicationType)
    Dim windows As Object = shellApplicationType.InvokeMember("Windows", Reflection.BindingFlags.InvokeMethod, Nothing, shellApplication, New Object() {})
    Dim windowsType As Type = windows.GetType()
    Dim count As Object = windowsType.InvokeMember("Count", Reflection.BindingFlags.GetProperty, Nothing, windows, Nothing)

    For i As Integer = 0 To CType(count, Integer)
        Dim item As Object = windowsType.InvokeMember("Item", Reflection.BindingFlags.InvokeMethod, Nothing, windows, New Object() {i})
        Dim itemType As Type = item.GetType()

        'Only fresh Windows explorer Windows
        Dim itemName As String = CType(itemType.InvokeMember("Name", Reflection.BindingFlags.GetProperty, Nothing, item, Nothing), String)
        If itemName = explorerType Then
            itemType.InvokeMember("Refresh", Reflection.BindingFlags.InvokeMethod, Nothing, item, Nothing)
        End If
    Next
End Sub

I am getting an exception Object reference not set to an instance of an object when I set itemType as Type = item.GetType() above. I can't figure out which object isn't being created. When I step through the code it looks like windowsType contains an object for windows. Does anyone have any idea on this? Once this is worked out I can then apply it to Drarig's solution below.

6
  • You could use this : askvg.com/… And run it with vb.net, or translate it in vb.net.
    – Drarig29
    Commented Aug 27, 2015 at 9:54
  • This is awesome Drarig29, I actually found this exact same article last night. Thank you for the verification though :) I will update this thread with an answer once I have translated it to VB.net.
    – ganjeii
    Commented Aug 27, 2015 at 11:03
  • It interests me too, I'll maybe work on the code and post an answer.
    – Drarig29
    Commented Aug 27, 2015 at 13:43
  • If you like my answer, you can upvote it !
    – Drarig29
    Commented Aug 27, 2015 at 19:45
  • Hey Drarig, I did but someone gave u a downvote
    – ganjeii
    Commented Aug 27, 2015 at 20:16

2 Answers 2

1

Alright I wish I could have got this to you sooner, but busy lately at work. I took a little time today to figure this out as I love digging into something I have not done before. This is the whole class from a new project; didn't have time to wrap it up in a separate class. I am sure this will get you what you need. It was a little harder than I thought as getting the correct handle and then send the command, but I got it. I hope you find it useful.

P.S. Some of the things you can leave out, specifically the boolean used for loading, this was so I can pull the current value back on load and either check/uncheck the CheckBox.

Note: This is tried and tested on Windows 7, 8 and 10

Imports Microsoft.Win32
Imports System.Reflection
Imports System.Runtime.InteropServices

Public Class Form1

    <Flags()> _
    Public Enum KeyboardFlag As UInteger
        KEYBOARDF_5 = &H74
    End Enum

    <DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
    Private Shared Function GetWindow(ByVal hl As Long, ByVal vm As Long) As IntPtr
    End Function

    <DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
    Private Shared Function PostMessage(ByVal hWnd As IntPtr, ByVal Msg As UInteger, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Boolean
    End Function

    <DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
    Private Shared Function FindWindow(ByVal lpClassName As String, ByVal lpWindowName As String) As IntPtr
    End Function

    Private blnLoading As Boolean = False

    Private Sub CheckBox1_CheckedChanged(sender As Object, e As EventArgs) Handles CheckBox1.CheckedChanged
        Form1.HideFilesExtension(Me.CheckBox1.Checked)
        If Not blnLoading Then NotifyFileAssociationChanged()
        RefreshExplorer()
    End Sub

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Dim name As String = "Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced"
        Dim key As RegistryKey = Registry.CurrentUser.OpenSubKey(name, False)

        blnLoading = True
        Me.CheckBox1.Checked = CBool(key.GetValue("Hidden"))
        key.Close()

        blnLoading = False
    End Sub

    Private Shared Sub HideFilesExtension(ByVal Hide As Boolean)
        Dim name As String = "Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced"
        Dim key As RegistryKey = Registry.CurrentUser.OpenSubKey(name, True)
        key.SetValue("Hidden", If(Hide, 1, 0))
        key.Close()
    End Sub

    Public Shared Sub RefreshExplorer()
        Dim clsid As New Guid("13709620-C279-11CE-A49E-444553540000")
        Dim typeFromCLSID As Type = Type.GetTypeFromCLSID(clsid, True)
        Dim objectValue As Object = Activator.CreateInstance(typeFromCLSID)
        Dim obj4 As Object = typeFromCLSID.InvokeMember("Windows", BindingFlags.InvokeMethod, Nothing, objectValue, New Object(0 - 1) {})
        Dim type1 As Type = obj4.GetType
        Dim obj2 As Object = type1.InvokeMember("Count", BindingFlags.GetProperty, Nothing, obj4, Nothing)
        If (CInt(obj2) <> 0) Then
            Dim num2 As Integer = (CInt(obj2) - 1)
            Dim i As Integer = 0
            Do While (i <= num2)
                Dim obj5 As Object = type1.InvokeMember("Item", BindingFlags.InvokeMethod, Nothing, obj4, New Object() {i})
                Dim type3 As Type = obj5.GetType
                Dim str As String = CStr(type3.InvokeMember("Name", BindingFlags.GetProperty, Nothing, obj5, Nothing))
                If (str = "File Explorer") Then
                    type3.InvokeMember("Refresh", BindingFlags.InvokeMethod, Nothing, obj5, Nothing)
                End If
                i += 1
            Loop
        End If

    End Sub

    Public Shared Sub NotifyFileAssociationChanged()
        'Find the actual window...
        Dim hwnd As IntPtr = FindWindow("Progman", "Program Manager")

        'Get the window handle and refresh option...
        Dim j = GetWindow(hwnd, 3)

        'Finally post the message...
        PostMessage(j, 256, KeyboardFlag.KEYBOARDF_5, 3)
    End Sub


End Class
3
  • 1
    thank you so much for your effort on this! This looks like it is exactly what I am looking for I am currently tying it up nicely into a class and will mark this as an answer as soon as I have it working. You saved me so much time! I can't stress enough, you did great work here. I was working on translating the answer in this post from C# and it literally caused a horrible headache
    – ganjeii
    Commented Aug 29, 2015 at 14:09
  • 1
    IT'S ALIVEEE!! Works on Win7 -10. Thanks again for your help! I'm still pretty junior so learning new stuff like this is exciting!
    – ganjeii
    Commented Aug 29, 2015 at 14:34
  • Welcome it was a bit of a headache but I got it.
    – Trevor
    Commented Aug 29, 2015 at 19:41
-1

Here's a solution for everything excepting the refreshing of the explorer. I've translated the code, but I'm unable to find how to refresh the explorer/desktop without restarting it.

Const keyName As String = "HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced"
Const Hidden As String = "Hidden"
Const SHidden As String = "ShowSuperHidden"

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    Dim St As Integer = GetRegValue(Hidden)

    If St = 2 Then
        SetRegValue(Hidden, 1)
        SetRegValue(SHidden, 1)
    Else
        SetRegValue(Hidden, 2)
        SetRegValue(SHidden, 0)
    End If
End Sub

Private Function GetRegValue(valueName As String) As Integer
    Return CInt(My.Computer.Registry.GetValue(keyName, valueName, 0))
End Function

Private Sub SetRegValue(valueName As String, value As Integer)
    My.Computer.Registry.SetValue(keyName, valueName, value, Microsoft.Win32.RegistryValueKind.DWord)
End Sub

I have a few ideas to refresh the desktop :

  • Send a key to a running process. I tried this (source) :

    Dim pp As Process() = Process.GetProcessesByName("explorer")
    
    If pp.Length > 0 Then
        For Each p In pp
            AppActivate(p.Id)
            SendKeys.SendWait("{F5}")
        Next
    End If
    
    • Refresh using SHChangeNotify (source),
    • Refresh broadcasting a WM_SETTINGCHANGE message (source),
    • etc.

I think you'll be forced to manually refresh or restart the explorer.

0

Not the answer you're looking for? Browse other questions tagged or ask your own question.