复制Windows取消隐藏文件夹和文件功能

Replicate Windows Unhide folders and files function

我正在重新访问我不久前在 VB.Net 中为我的服务台团队编写的工具,并想添加几个复选框来复制 Windows 用于显示隐藏的文件和文件夹/重新隐藏,以及受保护的操作系统文件。

我知道我可以通过编辑注册表项并重新启动 explorer.exe 来完成此操作,但这会关闭所有打开的资源管理器 Windows,我不希望这样。

有谁知道 Windows 如何通过简单地点击一个复选框来做到这一点以及我如何能够在 VB.net 中对其进行编码?

提前非常感谢对此的任何意见。


编辑:看来我找到了一种刷新方法,可以刷新 Windows 资源管理器/文件资源管理器,可以应用于下面的 Drarig 的回答 但我将其转换为 VB.net 时遇到问题,因为原始示例在 C# 中。

'Original at 

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

当我将 itemType 设置为 Type = [=45 时,我得到一个异常 对象引用未设置到对象的实例 =]() 以上。我不知道哪个对象没有被创建。当我单步执行代码时,它看起来像 windowsType 包含一个对象 windows。有人对此有任何想法吗?一旦解决了这个问题,我就可以将其应用于下面的 Drarig 解决方案。

除了浏览器的刷新,这里有一个解决方案。 我已经翻译了代码,但我无法找到如何在不重新启动的情况下刷新 explorer/desktop。

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

我有一些刷新桌面的想法:

  • 将密钥发送到 运行 进程。我试过了 (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
    
    • 刷新使用 SHChangeNotify (source),
    • 刷新广播一条WM_SETTINGCHANGE消息(source),
    • 等等

我认为您将不得不手动刷新或重新启动资源管理器。

好吧我希望我能早点把这个给你,但是最近工作很忙。我今天花了一点时间来解决这个问题,因为我喜欢深入研究我以前没有做过的事情。这是一个新项目的全部 class;没有时间将其包装在一个单独的 class 中。我相信这将为您提供所需的东西。获得正确的句柄然后发送命令比我想象的要难一些,但我明白了。我希望你觉得它有用。

P.S。您可以省略一些东西,特别是用于加载的布尔值,这样我就可以在加载时拉回当前值,或者 check/uncheck CheckBox.

注意:这已经在 Windows 7、8 和 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