Windows 10 打开文件对话框。文件夹怎么不显示?

Windows 10 打开文件对话框。文件夹怎么不显示?

在 Windows 10 标准打开文件对话框中,我已将视图设置为按日期顺序显示大图标缩略图。

有没有办法可以防止显示任何子文件夹?

在 Windows 的文件资源管理器中,在“查看”下有一个“按修改日期分组”选项,可将文件夹推到列表底部。在“打开文件”中是否有类似的选项,或者可能有其他方法?

答案1

您可以使用打开 - 保存对话框进行搜索以仅显示文件:

隐藏文件夹

  • 在搜索框中输入NOT kind:folder
  • 虽然左下角有一个“隐藏文件夹”开关,但它会将显示限制为单身的正义线文本,从而隐藏文件及其图标,还有……不是一般都是有用的。

答案2

在 Windows 的文件资源管理器中,在“查看”下有一个“按修改日期分组”选项,可将文件夹推到列表底部。在“打开文件”中是否有类似的选项

在常用对话框中,Sort by可以Group by在文件夹窗口背景上下文菜单中找到:

在此处输入图片描述

有没有办法可以防止显示任何子文件夹?

是的,借助一点脚本魔法。探索者保存其自身和常用对话框的视图设置:

  • HKCU\Softare\Classes\LocalSettings\Microsoft\Windows\Shell\Bags

    在此处输入图片描述

FFlags条目包含以下成员FolderFlags 枚举控制视图的各个方面,其中之一是FWF_NoSubfolders0x80),它抑制文件夹窗格中子文件夹的显示,但不禁止通过导航窗格导航到这些子文件夹或在地址栏中键入内容。

它很容易操作探索者观点,因为这一点电源外壳将切换显示所有当前打开的探索者窗口。您可以复制并粘贴到电源外壳控制台并按enter执行;然后Up Arrow重复enter并撤消更改:

@((New-Object -com shell.application).Windows()).ForEach{
    $_.Document.FolderFlags = ($_.Document.FolderFlags -bxor 0x80)
    $_.Refresh()
}

如果您关闭设置了标志的窗口,它将在下次显示文件夹时生效,因为它是已保存的视图设置的一部分。

但遗憾的是,对话框并不那么容易。我们无法像使用 shell com 对象那样访问活动对话框视图,但如果FFlags输入之前保存过视图被修改,将在下次显示对话框时使用。但每次关闭对话框并保存其视图设置时,FFlags都会重置为 0x01,这意味着子文件夹将在下次显示对话框时可见。

因此,为了在对话框中隐藏子文件夹并使其保留,我们在编辑注册表项后拒绝修改该项的权限。不幸的是,这也会锁定已保存视图的所有其他方面,因此您需要确保图标模式、列选择等符合您的喜好,然后再隐藏子文件夹。当我们想要恢复正常显示时,我们首先删除权限Deny,然后将默认值恢复为FFlags

因此电源外壳代码应保存为.ps1您选择的目录中的文件。然后,通过 dot-sourcing 执行脚本:

. <PathTofile>\<FileName>.ps1

这将在注册表中创建必要的上下文菜单项,并且该选项将通过背景上下文菜单或 FolderItem 上下文菜单提供。

#####################################################################################################################################################
#   
#   Context menu syntax:
#    - Directory backgrund:
#   powershell -NoLogo -NoProfile -ExecutionPolicy Bypass -File <pathToThisScript> "%V" Show|Hide Background
#    - Directory (selected item):
#   powershell -NoLogo -NoProfile -ExecutionPolicy Bypass -File <pathToThisScript> "%V" Show|Hide
#
#####################################################################################################################################################

#############################################################################################
#
#   Pinvoke and wrapper function for SHGetNameFromIDList(). This facilitates traversing
#    the BagMRU index to deterimine the property bag of the view for the target directory.
#
#   Wrapper syntax: [string] GetFolderName(Byte[] IDL)
#
Add-Type @"
using System;
using System.Runtime.InteropServices;
using System.Text;

public class API
{
    [DllImport("shell32.dll", SetLastError=true, CharSet=CharSet.Unicode)]
    [return: MarshalAs(UnmanagedType.Error)]
    static extern int SHGetNameFromIDList(IntPtr pidl, uint sigdnName, out StringBuilder ppszName);

    static public string GetFolderName(Byte[] IDL) {
        GCHandle pinnedArray = GCHandle.Alloc(IDL, GCHandleType.Pinned);
        IntPtr PIDL          = pinnedArray.AddrOfPinnedObject();
        StringBuilder name   = new StringBuilder(2048);
        int result           = SHGetNameFromIDList(PIDL, 0x0, out name);
        pinnedArray.Free();
        return name.ToString();
    }
}
"@ # End Add-Type

#############################################################################################
#
#   Get-NSPath: Determine the fully-qualified path within the shell namespace. In essence,
#       a human-readable IDL that generally mirrors the Address bar text.
#
Function Get-NSPath ($comFolder) {
    If ($comFolder.ParentFolder)        {
        $ParentPath     = Get-NSPath $comFolder.ParentFolder
        ###   Return from subfolder recursion:
        '{0}\{1}'       -f $ParentPath , $comFolder.Title
    } Else {
        ###   Return from Desktop:
        $comFolder.Title
    }
}
#############################################################################################
#   
#   Get-BagNumber: With the NSPath, locate the MRU node for the target folder and return
#   the correspoinding NodeSLot (Bag #).
#
Function Get-BagNumber ($NSPath) {
    $BagMRU            = 'HKCU:\Software\Classes\Local Settings\Software\Microsoft\Windows\Shell\BagMRU'
    $MRUNode           = Get-Item $BagMRU 
    [Byte[]]$parentIDL = [Byte[]]@()

    If ($NSPath -match '\\') {
        $NSPath        = $NSPath -replace '^Desktop\\'
        $FolderNames   = $NSPath.Split('\')
        ForEach ($folderName in @($FolderNames)) {
            $node          = @($MRUNode.GetValueNames() -match '\d+').Where{[API]::GetFolderName($parentIDL + $MRUNode.GetValue($_)) -eq $folderName}[0]
            $idl           = $MRUNode.GetValue($node)
            $MRUNode       = $MRUNode.OpenSubKey($node)
            $parentIDL     = $parentIDL + [Byte[]]($idl[0..($idl.Length-3)])
        }
    }
    ###   Return value:
    $MRUNode.GetValue('NodeSlot')
}
#############################################################################################
#   
#   Set-NoSubfolders: Sets or clears the FWF_NoSubfolders flag and modifies permissions
#    for any ComDLg subkeys under the specified bag.
#   
Function Set-NoSubfolders ([String]$BagNum , [Bool]$NoSubfolders) {
    $Bags       = 'HKCU:\Software\Classes\Local Settings\Software\Microsoft\Windows\Shell\Bags'
    $dlgCount   = 0
    Get-ChildItem "$Bags\$BagNum" -Recurse | where Name -match 'ComDlg\w*\\' | ForEach {
        $dlgCount += 1
        Write-Verbose   ('{3,-15}: {0}\{1}\{2}' -f ($_.PSParentPath.Split('\')[9..11] + 'Dialog view'))
        $splat = @{
            'Name'    = 'FFlags'
            'Value'   = $(If ($NoSubfolders) {0x81} Else {0x01})
        }
        If ($NoSubfolders) {   ###   Set the flag and then deny SetValue permission
            Lock-KeyValues $_.PSParentPath $false
            $_ | Set-ItemProperty @splat
            Lock-KeyValues $_.PSParentPath $true
            Write-Verbose "`tFWF_NoSubfolders set."
        } Else {   ###   Remove "deny SetValue" permission and clear flag 
            Lock-KeyValues $_.PSParentPath $false
            $_ | Set-ItemProperty @splat
            Write-Verbose "`tFWF_NoSubfolders cleared."
        }
    }
    If ($dlgCount -eq 0) {
        Write-Warning "`n`tNo dialog views saved yet for this folder.`n"
    }
}
#############################################################################################
#   
#   Function Lock-KeyValues: Adds or removes a "Deny SetValue" rule to the ACL of the modified key.
#   The rule is added when subfolders are hidden to prevent the FFlags value from being reset to the default.
#   The rule is removed when the NoSubfolders flag is cleared.
#   All aspects of the view are frozen when the rule is added, so best to customize other aspects of the dialog view before hiding subfolders.
#   
Function Lock-KeyValues ($keyPath , [Bool]$lock) {
    $DenySetValue   = [Security.AccessControl.RegistryAccessRule]::new("$env:UserDomain\$env:UserName","SetValue","ContainerInherit","InheritOnly","Deny")
    $kacl           = Get-Acl $keyPath
    If ($Lock) {
        $kacl.AddAccessRule($DenySetValue) | out-null
    }
    Else {
        $kacl.RemoveAccessRule($DenySetValue) | out-null
    }
    Set-Acl -Path $keyPath -AclObject $kAcl 
}
#############################################################################################
###   Main
#############################################################################################

If ($Args) {   ###   Invoked from context menu
    $VerbosePreference   = 'continue'
    $folderPath          = $Args[0]
    $Shell               = New-Object -com shell.application
    If ($Args.Count -eq 3) {
        Write-Verbose      'Invoked from folder background...'
        Write-Verbose      ('{1,-15}:"{0}"' -f $folderPath, 'Folder path')
        $win             = @($shell.windows() | where $folderPath -eq $_.Document.Folder.Self.Path)[0]
        $NSPath          = Get-NSPath $win.Document.Folder
    } Else {
        Write-Verbose      'Invoked from FolderItem...'
        Write-Verbose      ('{1,-15}:"{0}"' -f $folderPath, 'folderPath')
        $win             = @($shell.windows() | where $folderPath -eq $_.Document.FocusedItem.Path)[0]
        $NSPath          = '{0}\{1}' -f (Get-NSPath $win.Document.Folder) , (Split-Path $folderPath -Leaf)
    }
    Write-Verbose          ('{1,-15}: "{0}"' -f $win.Document.Folder.Title , 'Window title')
    Write-Verbose          ('{1,-15}: "{0}"' -f $NSPath , 'Namespace path')
    $TargetBag           = Get-BagNumber $NSPath
    Write-Verbose          ('{1,-15}: {0}' -f $TargetBag , 'Target bag')
    If ($TargetBag) {
        Write-Verbose      ('{1,-15}: "{0}"' -f $Args[1], 'Action')
        Set-NoSubfolders $TargetBag ($Args[1] -eq 'Hide')
    }
    Read-Host "`n`tDone. Press <enter> to close this window.`n"

###   End context menu invocation

} Else {   ###   Invoked with no arguments triggers context menu item creation
    If ($PSCommandPath) {
        $MenuText       = '&Hide/show subfolders in dialogs'
        $keyRoot        = 'HKCU:\SOFTWARE\Classes\Directory'
        $HideShow       = @{
                    '1' = 'Hide'
                    '2' = 'Show'
        }
        $menuItemProps      = [PSCustomObject]@{
            'MuiVerb'       =   $MenuText
            'SubCommands'   =   ''
        }
        ###   Registry key/entry creation loop
        'Background' , $null | ForEach {$_} -pv pvISBackground | ForEach {
            (mkdir (Join-Path $keyRoot $_ | Join-Path -CHildPath 'shell\HSDS') -Force).PSPath
        } -pv pvMenuItem | ForEach {
            Set-ItemProperty -Path $_ -InputObject $menuItemProps
            '1' , '2' | ForEach {
                $subCmdPath     = (mkdir (Join-Path $pvMenuItem "Shell\$_") -Force).PSPath
                Set-ItemProperty -Path $subCmdPath -Name MuiVerb -Value "&$($HideShow[$_])"
                $splat              = @{
                        'Path'      = $subCmdPath
                        'Name'      = 'Command'
                        'Value'     = ('powershell -NoLogo -NoProfile -ExecutionPolicy Bypass -File "{0}" "%V" {1} {2}' -f $PSCommandPath , $HideShow[$_] , $pvISBackground).Trim()
                        'Type'      = 'ExpandString'
                }
                New-Item @splat -Force
            }
        }
        Write-HOst 'Context menu entries created.'
    } Else {
        Write-Warning "`n`tSave this script to a .ps1 file and then invoke via dot-sourcing to install as context menu item.`n"
    }
}
#############################################################################################

相关内容