diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/AppModel/ComGuids.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/AppModel/ComGuids.cs index b6398fa0e06..28839a472fa 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/AppModel/ComGuids.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/AppModel/ComGuids.cs @@ -15,6 +15,8 @@ internal static class IID public const string EnumObjects = "2c1c7e2e-2d0e-4059-831e-1e6f82335c2e"; /// IID_IFileDialog public const string FileDialog = "42f85136-db7e-439c-85f1-e4075d135fc8"; + /// IID_IFileDialog2 + public const string FileDialog2 = "61744fc7-85b5-4791-a9b0-272276309b13"; /// IID_IFileDialogEvents public const string FileDialogEvents = "973510DB-7D7F-452B-8975-74A85828D354"; /// IID_IFileOpenDialog diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/AppModel/ShellProvider.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/AppModel/ShellProvider.cs index fc75ec3c999..16ddad1bebf 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/AppModel/ShellProvider.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/AppModel/ShellProvider.cs @@ -479,6 +479,72 @@ internal interface IFileDialog : IModalWindow void SetFilter([MarshalAs(UnmanagedType.Interface)] object pFilter); } + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.FileDialog2), + ] + internal interface IFileDialog2 : IFileDialog + { + #region IFileDialog redeclarations + #region IModalWindow redeclarations + [PreserveSig] + new HRESULT Show(IntPtr parent); + #endregion + + new void SetFileTypes(uint cFileTypes, [In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] COMDLG_FILTERSPEC[] rgFilterSpec); + + new void SetFileTypeIndex(uint iFileType); + + new uint GetFileTypeIndex(); + + new uint Advise(IFileDialogEvents pfde); + + new void Unadvise(uint dwCookie); + + new void SetOptions(FOS fos); + + new FOS GetOptions(); + + new void SetDefaultFolder(IShellItem psi); + + new void SetFolder(IShellItem psi); + + new IShellItem GetFolder(); + + new IShellItem GetCurrentSelection(); + + new void SetFileName([MarshalAs(UnmanagedType.LPWStr)] string pszName); + + [return: MarshalAs(UnmanagedType.LPWStr)] + new string GetFileName(); + + new void SetTitle([MarshalAs(UnmanagedType.LPWStr)] string pszTitle); + + new void SetOkButtonLabel([MarshalAs(UnmanagedType.LPWStr)] string pszText); + + new void SetFileNameLabel([MarshalAs(UnmanagedType.LPWStr)] string pszLabel); + + new IShellItem GetResult(); + + new void AddPlace(IShellItem psi, FDAP alignment); + + new void SetDefaultExtension([MarshalAs(UnmanagedType.LPWStr)] string pszDefaultExtension); + + new void Close([MarshalAs(UnmanagedType.Error)] int hr); + + new void SetClientGuid([In] ref Guid guid); + + new void ClearClientData(); + + new void SetFilter([MarshalAs(UnmanagedType.Interface)] object pFilter); + #endregion + + void SetCancelButtonLabel([MarshalAs(UnmanagedType.LPWStr)] string pszLabel); + + void SetNavigationRoot(IShellItem psi); + } + [ ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/Microsoft/Win32/CommonItemDialog.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/Microsoft/Win32/CommonItemDialog.cs index adc345abe58..e870150088c 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/Microsoft/Win32/CommonItemDialog.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/Microsoft/Win32/CommonItemDialog.cs @@ -98,6 +98,49 @@ public override string ToString() //--------------------------------------------------- #region Public Properties + // FOS_DONTADDTORECENT + // Do not add the item being opened or saved to the recent documents list (SHAddToRecentDocs). + // + /// + /// Gets or sets a value indicating whether the dialog box will add the item + /// being opened or saved to the recent documents list. + /// + public bool AddToRecent + { + get + { + return !GetOption(FOS.DONTADDTORECENT); + } + set + { + + SetOption(FOS.DONTADDTORECENT, !value); + } + } + + /// + /// Gets or sets a Guid to associate with the dialog's persisted state. + /// + public Guid? ClientGuid { get; set; } + + /// + /// Gets or sets the initial directory displayed by the file dialog box + /// if there is not a recently used directory value available. + /// + public string DefaultDirectory + { + get + { + // Avoid returning a null string - return String.Empty instead. + return _defaultDirectory.Value == null ? String.Empty : _defaultDirectory.Value; + } + set + { + + _defaultDirectory.Value = value; + } + } + // The actual flag is FOS_NODEREFERENCELINKS (set = do not dereference, unset = deref) - // while we have true = dereference and false=do not dereference. Because we expose // the opposite of the Windows flag as a property to be clearer, we need to negate @@ -137,6 +180,43 @@ public string InitialDirectory } } + /// + /// Gets or sets the initial directory displayed by the file dialog box. + /// + public string RootDirectory + { + get + { + // Avoid returning a null string - return String.Empty instead. + return _rootDirectory.Value == null ? String.Empty : _rootDirectory.Value; + } + set + { + + _rootDirectory.Value = value; + } + } + + // FOS_FORCESHOWHIDDEN + // Include hidden and system items. + // + /// + /// Gets or sets a value indicating whether the dialog box will show + /// Include hidden items regardless of user preferences. + /// + public bool ShowHiddenItems + { + get + { + return GetOption(FOS.FORCESHOWHIDDEN); + } + set + { + + SetOption(FOS.FORCESHOWHIDDEN, value); + } + } + /// /// Gets or sets a string shown in the title bar of the file dialog. /// If this property is null, a localized default from the operating @@ -299,17 +379,43 @@ internal bool MessageBoxWithFocusRestore(string message, private protected virtual void PrepareDialog(IFileDialog dialog) { + if (ClientGuid is Guid guid) + { + dialog.SetClientGuid(ref guid); + } + + if (!string.IsNullOrEmpty(DefaultDirectory)) + { + IShellItem defaultDirectory = ShellUtil.GetShellItemForPath(DefaultDirectory); + if (defaultDirectory != null) + { + dialog.SetDefaultFolder(defaultDirectory); + } + } + if (!string.IsNullOrEmpty(InitialDirectory)) { IShellItem initialDirectory = ShellUtil.GetShellItemForPath(InitialDirectory); if (initialDirectory != null) { // Setting both of these so the dialog doesn't display errors when a remembered folder is missing. - dialog.SetDefaultFolder(initialDirectory); + if (string.IsNullOrEmpty(DefaultDirectory)) + { + dialog.SetDefaultFolder(initialDirectory); + } dialog.SetFolder(initialDirectory); } } + if (!string.IsNullOrEmpty(RootDirectory)) + { + IShellItem rootDirectory = ShellUtil.GetShellItemForPath(RootDirectory); + if (rootDirectory != null && dialog is IFileDialog2 dialog2) + { + dialog2.SetNavigationRoot(rootDirectory); + } + } + dialog.SetTitle(Title); dialog.SetFileName(CriticalItemName); @@ -456,9 +562,13 @@ private void Initialize() _itemNames = null; _title.Value = null; _initialDirectory.Value = null; + _defaultDirectory.Value = null; + _rootDirectory.Value = null; // Set this to an empty list so callers can simply add to it. They can also replace it wholesale. CustomPlaces = new List(); + ClientGuid = null; + } private bool HandleItemOk(IFileDialog dialog) @@ -667,6 +777,8 @@ void IDisposable.Dispose() // that control the appearance of the file dialog box. private SecurityCriticalDataForSet _title; // Title bar of the message box private SecurityCriticalDataForSet _initialDirectory; // Starting directory + private SecurityCriticalDataForSet _defaultDirectory; // Starting directory if no recent + private SecurityCriticalDataForSet _rootDirectory; // Topmost directory // We store the handle of the file dialog inside our class // for a variety of purposes (like getting the title of the dialog diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/Microsoft/Win32/OpenFileDialog.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/Microsoft/Win32/OpenFileDialog.cs index c7c00a8662c..1d2af2f29ca 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/Microsoft/Win32/OpenFileDialog.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/Microsoft/Win32/OpenFileDialog.cs @@ -155,6 +155,25 @@ public override void Reset() //--------------------------------------------------- #region Public Properties + // FOS_FORCEPREVIEWPANEON + // Indicates to the Open dialog box that the preview pane should always be displayed. + // + /// + /// Gets or sets an option flag indicating whether the + /// dialog box forces the preview pane on. + /// + public bool ForcePreviewPane + { + get + { + return GetOption(FOS.FORCEPREVIEWPANEON); + } + set + { + SetOption(FOS.FORCEPREVIEWPANEON, value); + } + } + // FOS_ALLOWMULTISELECT // Enables the user to select multiple items in the open dialog. // @@ -186,17 +205,7 @@ public bool Multiselect /// Gets or sets a value indicating whether the dialog /// contains a read-only check box. /// - public bool ShowReadOnly - { - get - { - return _showReadOnly; - } - set - { - _showReadOnly = false; - } - } + public bool ShowReadOnly { get; set; } #endregion Public Properties @@ -288,9 +297,6 @@ private void Initialize() // //--------------------------------------------------- //#region Private Fields - - private bool _showReadOnly = false; - //#endregion Private Fields } } diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/Microsoft/Win32/SaveFileDialog.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/Microsoft/Win32/SaveFileDialog.cs index 898bcc8ba3b..70b09338c25 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/Microsoft/Win32/SaveFileDialog.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/Microsoft/Win32/SaveFileDialog.cs @@ -134,6 +134,24 @@ public override void Reset() /// public bool CreatePrompt { get; set; } + /// + /// Gets or sets a value indicating whether the dialog box will attempt to create + /// a test file at the selected path (default is true). If this flag is not set, + /// the calling application must handle errors, such as denial of access, + /// discovered when the item is created. + /// + public bool CreateTestFile + { + get + { + return !GetOption(FOS.NOTESTFILECREATE); + } + set + { + SetOption(FOS.NOTESTFILECREATE, !value); + } + } + // Causes our code to generate a message box if the selected file already // exists. The user must confirm whether to overwrite the file. // diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/ref/PresentationFramework.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/ref/PresentationFramework.cs index 59f2bfc355a..7a77e13c7ba 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/ref/PresentationFramework.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/ref/PresentationFramework.cs @@ -14,9 +14,14 @@ protected virtual void CheckPermissionsToShowDialog() { } public abstract partial class CommonItemDialog : Microsoft.Win32.CommonDialog { private protected CommonItemDialog() { } + public bool AddToRecent { get { throw null; } set { } } + public System.Guid? ClientGuid { get; set; } public System.Collections.Generic.IList CustomPlaces { get { throw null; } set { } } + public string DefaultDirectory { get { throw null; } set { } } public bool DereferenceLinks { get { throw null; } set { } } public string InitialDirectory { get { throw null; } set { } } + public string RootDirectory { get { throw null; } set { } } + public bool ShowHiddenItems { get; set; } public string Title { get { throw null; } set { } } public bool ValidateNames { get { throw null; } set { } } protected virtual void OnItemOk(System.ComponentModel.CancelEventArgs e) { } @@ -73,6 +78,7 @@ public static partial class FileDialogCustomPlaces public sealed partial class OpenFileDialog : Microsoft.Win32.FileDialog { public OpenFileDialog() { } + public bool ForcePreviewPane { get; set; } public bool Multiselect { get { throw null; } set { } } public System.IO.Stream OpenFile() { throw null; } public System.IO.Stream[] OpenFiles() { throw null; } @@ -97,6 +103,7 @@ public sealed partial class SaveFileDialog : Microsoft.Win32.FileDialog { public SaveFileDialog() { } public bool CreatePrompt { get { throw null; } set { } } + public bool CreateTestFile { get { throw null; } set { } } public bool OverwritePrompt { get { throw null; } set { } } public System.IO.Stream OpenFile() { throw null; } public override void Reset() { }