Hide extensions in Vista/Windows 7 WPF FileDialog.Filter

后端 未结 4 789
半阙折子戏
半阙折子戏 2021-01-05 10:47

I am using the WPF OpenFileDialog and SaveFileDialog in my .NET 4 WPF application. I use the Filter property to allow the user to set different file filters. In .NET 4, this

相关标签:
4条回答
  • 2021-01-05 11:18

    I didn’t like the GUI of neither GetOpenFileName nor WinForm’s dialog with AutoUpgradeEnabled=false.

    To fix the WPF’s dialog, I’ve wrote a small class which implements IDisposable, in constructor I check if HideFileExt value is set to 0 under HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced registry key, if it’s 0 I write 1 there, keep the key open in a readonly field, and restore 0 when the class is disposed.

    Usage example:

    bool result;
    using( var hfe = new HideExplorerExtensions() )
        result = ofd.ShowDialog( ownerWindow ) ?? false;
    

    The cleaner way is patch RegGetValueW or whatever else API comdlg32.dll!CFileOpenSave::Show(struct HWND__ *) method uses to read that value, with e.g. MinHook so only the dialog hosted in the current process sees 1 in that registry value. It was much more complex to do however.

    0 讨论(0)
  • 2021-01-05 11:24

    You're on the right track. There are effectively 2 ways to display an open file dialog. The newer method uses IFileOpenDialog (which extends IFileDialog). With this method, the filter descriptions and file specifications are defined using the COMDLG_FILTERSPEC structure. This keeps the separated into their own fields, which is more nature.

    If you wanted to remove the file specs from the combo box using this method, then you'd have to either add your own custom control or manipulate the combo box control on the dialog. This would get messy though, but should be doable.

    The old school method uses GetOpenFileName and the OPENFILENAME structure. The trick with this one, is that is can display a dialog with the old look or the new look. The look is determined by the settings in the OPENFILENAME structure, as described here.

    The problem with the WinForms OpenFileDialog is that they either use IFileOpenDialog when say AutoUpgradeEnabled is true, and GetOpenFileName with the older look when AutoUpgradeEnabled is false.

    The WPF version doesn't give you a choice, but still uses the same logic as the WinForms one, but does it automatically as needed. This is true for WPF in .NET 4, in previous versions it would just use GetOpenFileName with the old look.

    Paint is most likely using GetOpenFileName with the new look. Here is a C# example:

    private delegate IntPtr WndProc(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
    
    private const int OFN_ALLOWMULTISELECT = 0x00000200;
    private const int OFN_CREATEPROMPT = 0x00002000;
    private const int OFN_DONTADDTORECENT = 0x02000000;
    private const int OFN_ENABLEHOOK = 0x00000020;
    private const int OFN_ENABLEINCLUDENOTIFY = 0x00400000;
    private const int OFN_ENABLESIZING = 0x00800000;
    private const int OFN_ENABLETEMPLATE = 0x00000040;
    private const int OFN_ENABLETEMPLATEHANDLE = 0x00000080;
    private const int OFN_EXPLORER = 0x00080000;
    private const int OFN_EXTENSIONDIFFERENT = 0x00000400;
    private const int OFN_FILEMUSTEXIST = 0x00001000;
    private const int OFN_FORCESHOWHIDDEN = 0x10000000;
    private const int OFN_HIDEREADONLY = 0x00000004;
    private const int OFN_LONGNAMES = 0x00200000;
    private const int OFN_NOCHANGEDIR = 0x00000008;
    private const int OFN_NODEREFERENCELINKS = 0x00100000;
    private const int OFN_NOLONGNAMES = 0x00040000;
    private const int OFN_NONETWORKBUTTON = 0x00020000;
    private const int OFN_NOREADONLYRETURN = 0x00008000;
    private const int OFN_NOTESTFILECREATE = 0x00010000;
    private const int OFN_NOVALIDATE = 0x00000100;
    private const int OFN_OVERWRITEPROMPT = 0x00000002;
    private const int OFN_PATHMUSTEXIST = 0x00000800;
    private const int OFN_READONLY = 0x00000001;
    private const int OFN_SHAREAWARE = 0x00004000;
    private const int OFN_SHOWHELP = 0x00000010;
    
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    public class OPENFILENAME_I {
        public int lStructSize;
        public IntPtr hwndOwner;
        public IntPtr hInstance;
        public string lpstrFilter;
        public IntPtr lpstrCustomFilter;
        public int nMaxCustFilter;
        public int nFilterIndex;
        public IntPtr lpstrFile;
        public int nMaxFile = 260;
        public IntPtr lpstrFileTitle;
        public int nMaxFileTitle = 260;
        public string lpstrInitialDir;
        public string lpstrTitle;
        public int Flags;
        public short nFileOffset;
        public short nFileExtension;
        public string lpstrDefExt;
        public IntPtr lCustData;
        public WndProc lpfnHook;
        public string lpTemplateName;
        public IntPtr pvReserved;
        public int dwReserved;
        public int FlagsEx;
    }
    
    [DllImport("comdlg32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    private static extern bool GetOpenFileName([In, Out] OPENFILENAME_I ofn);
    
    private void ShowOpenFileDialog() {
        OPENFILENAME_I ofn = new OPENFILENAME_I();
        ofn.lStructSize = Marshal.SizeOf(typeof(OPENFILENAME_I));
        ofn.lpstrFilter = "Text Files (*.txt)\0*.txt\0All Files\0*.*\0\0";
        ofn.nFilterIndex = 0;
        //ofn.Flags = OFN_EXPLORER | OFN_ENABLEHOOK | OFN_ENABLESIZING | OFN_NODEREFERENCELINKS | OFN_HIDEREADONLY | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
        ofn.Flags = OFN_ENABLESIZING | OFN_NODEREFERENCELINKS | OFN_HIDEREADONLY | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
        GetOpenFileName(ofn);
    }
    

    You can try adding the OFN_EXPLORER and/or OFN_ENABLEHOOK flags back in, and it will revert to the old look. But as-is, the code above will display an open file dialog with All Files not showing it's file spec.

    0 讨论(0)
  • 2021-01-05 11:31

    You might want to head here...

    Hide Extensions

    0 讨论(0)
  • 2021-01-05 11:34

    After a bunch of testing, I got the following result: The FileDialog in WPF calls the native IFileDialog::SetFileTypes method with the strings as defined by the filter. Depending on the Windows option to hide the extension on known file types (in the Windows Explorer folder settings), the extensions are automatically added or not.

    Now the only question remains is how Paint is able to not show the extensions for "Image files" in its open file dialog.

    0 讨论(0)
提交回复
热议问题