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

4
我正在重新审视我以前为我的帮助台团队编写的VB.Net工具,并希望添加一些复选框来复制Windows使用的同一功能,以显示隐藏文件和文件夹/重新隐藏以及受保护的操作系统文件。

我知道我可以通过编辑注册表项并重新启动explorer.exe来实现这一点,但这会关闭所有打开的资源管理器窗口,我不想这样做。

有人知道Windows如何通过简单的复选框单击来实现这一点,以及我如何在VB.net中编写它吗?

非常感谢您提前提供任何关于此的意见。


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

'Original at https://dev59.com/e3E95IYBdhLWcg3wCJXk

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 = item.GetType() 时,出现了一个异常: 对象引用未设置为对象的实例。我无法确定哪个对象没有被创建。当我逐步执行代码时,看起来 windowsType 包含了 windows 的一个对象。有人对此有什么想法吗?一旦解决了这个问题,我就可以应用Drarig下面的解决方案。

你可以使用此链接:http://www.askvg.com/create-simple-script-to-show-hide-hidden-files-and-folders-in-windows-xp-vista-and-7/并在vb.net中运行它,或将其翻译成vb.net。 - Drarig29
这太棒了Drarig29,我昨晚实际上找到了完全相同的文章。虽然谢谢你的验证 :)一旦我将其翻译成VB.net,我将在此线程中更新答案。 - ganjeii
我也很感兴趣,也许我会处理这段代码并发布一个答案。 - Drarig29
如果您喜欢我的回答,可以点赞支持! - Drarig29
嘿,Drarig,我已经做了,但有人给你的回答点了个踩。 - ganjeii
谢谢。我讨厌那些不说原因就给我点踩的人! - Drarig29
2个回答

1
好的,我希望我能早些把这个给你,但最近工作很忙。今天我花了点时间来解决这个问题,因为我喜欢挖掘我以前没有做过的事情。这是一个新项目的整个类; 没有时间将其封装在单独的类中。我相信这会让你得到你所需要的。获取正确的句柄然后发送命令比我想象的要难一些,但我做到了。希望你觉得这很有用。

附言:你可以略去其中一些内容,特别是用于加载的布尔值,这样我就可以在加载时将当前值拉回并检查/取消检查复选框。

注意:已在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

1
非常感谢您在这方面的努力!这看起来就是我要找的东西,我正在把它整理成一个类,并将其标记为答案,一旦我让它正常工作。你节省了我很多时间!我无法强调,你在这里做得很好。我正在努力将此帖子中的答案从C#翻译过来,结果导致了可怕的头痛。 - ganjeii
1
它活了!!适用于Win7-10。再次感谢您的帮助!我还是很菜鸟,所以学习这样的新东西非常令人兴奋! - ganjeii
欢迎,这有点让人头疼,但我搞定了。 - Trevor

-1

这里有一个除了刷新资源管理器以外的解决方案。 我已经翻译了代码,但是我无法找到如何在不重启计算机的情况下刷新资源管理器/桌面。

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),
    • 等等。

我认为你将被迫手动刷新或重启资源管理器。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接