| File: System\Windows\Forms\Dialogs\CommonDialogs\SaveFileDialog.cs | Web Access |
| Project: src\winforms\src\System.Windows.Forms\System.Windows.Forms.csproj (System.Windows.Forms) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.ComponentModel; using Windows.Win32.System.Com; using Windows.Win32.UI.Controls.Dialogs; using static Windows.Win32.UI.Controls.Dialogs.OPEN_FILENAME_FLAGS; using static Windows.Win32.UI.Shell.FILEOPENDIALOGOPTIONS; namespace System.Windows.Forms; /// <summary> /// Represents common dialog box that allows the user to specify options for saving a /// file. This class cannot be inherited. /// </summary> [Designer($"System.Windows.Forms.Design.SaveFileDialogDesigner, {Assemblies.SystemDesign}")] [SRDescription(nameof(SR.DescriptionSaveFileDialog))] public sealed partial class SaveFileDialog : FileDialog { /// <summary> /// Gets or sets a value indicating whether the dialog box verifies if the creation of the specified file will /// be successful. If this flag is not set, the calling application must handle errors, such as denial of access, /// discovered when the item is created. /// </summary> [SRCategory(nameof(SR.CatBehavior))] [DefaultValue(true)] [SRDescription(nameof(SR.SaveFileDialogCheckWriteAccess))] public bool CheckWriteAccess { get => !GetOption(OFN_NOTESTFILECREATE); set => SetOption(OFN_NOTESTFILECREATE, !value); } /// <summary> /// Gets or sets a value indicating whether the dialog box prompts the user for /// permission to create a file if the user specifies a file that does not exist. /// </summary> [SRCategory(nameof(SR.CatBehavior))] [DefaultValue(false)] [SRDescription(nameof(SR.SaveFileDialogCreatePrompt))] public bool CreatePrompt { get => GetOption(OFN_CREATEPROMPT); set => SetOption(OFN_CREATEPROMPT, value); } /// <summary> /// Gets or sets a value indicating whether the dialog box is always opened in the expanded mode. /// </summary> [SRCategory(nameof(SR.CatBehavior))] [DefaultValue(true)] [SRDescription(nameof(SR.SaveFileDialogExpandedMode))] public bool ExpandedMode { get => _dialogOptions.HasFlag(FOS_DEFAULTNOMINIMODE); set => _dialogOptions.ChangeFlags(FOS_DEFAULTNOMINIMODE, value); } /// <summary> /// Gets or sets a value indicating whether the Save As dialog box displays a warning if the user specifies /// a file name that already exists. /// </summary> [SRCategory(nameof(SR.CatBehavior))] [DefaultValue(true)] [SRDescription(nameof(SR.SaveFileDialogOverWritePrompt))] public bool OverwritePrompt { get => GetOption(OFN_OVERWRITEPROMPT); set => SetOption(OFN_OVERWRITEPROMPT, value); } /// <summary> /// Opens the file with read/write permission selected by the user. /// </summary> public Stream OpenFile() { string filename = FileNames[0]; filename.ThrowIfNullOrEmpty(); return new FileStream(filename, FileMode.Create, FileAccess.ReadWrite); } /// <summary> /// Prompts the user with a <see cref="MessageBox"/> when a file is about to be created. This method is /// invoked when the <see cref="CreatePrompt"/> property is true and the specified file does not exist. A /// return value of <see langword="false"/> prevents the dialog from closing. /// </summary> private bool PromptFileCreate(string fileName) => MessageBoxWithFocusRestore( string.Format(SR.FileDialogCreatePrompt, fileName), DialogCaption, MessageBoxButtons.YesNo, MessageBoxIcon.Warning); /// <summary> /// Prompts the user when a file is about to be overwritten. This method is invoked when the /// <see cref="OverwritePrompt"/> property is true and the specified file already exists. A return value /// of <see langword="false"/> prevents the dialog from closing. /// </summary> private bool PromptFileOverwrite(string fileName) => MessageBoxWithFocusRestore( string.Format(SR.FileDialogOverwritePrompt, fileName), DialogCaption, MessageBoxButtons.YesNo, MessageBoxIcon.Warning); private protected override bool PromptUserIfAppropriate(string fileName) { if (!base.PromptUserIfAppropriate(fileName)) { return false; } // Note: Vista dialog mode automatically prompts for overwrite. if (_fileNameFlags.HasFlag(OFN_OVERWRITEPROMPT) && !UseVistaDialogInternal && FileExists(fileName) && !PromptFileOverwrite(fileName)) { return false; } if (_fileNameFlags.HasFlag(OFN_CREATEPROMPT) && !FileExists(fileName) && !PromptFileCreate(fileName)) { return false; } return true; } /// <summary> /// Resets all dialog box options to their default values. /// </summary> public override void Reset() { base.Reset(); _dialogOptions |= FOS_DEFAULTNOMINIMODE; SetOption(OFN_OVERWRITEPROMPT, true); } private protected override unsafe bool RunFileDialog(OPENFILENAME* ofn) { bool result = PInvoke.GetSaveFileName(ofn); if (!result) { // Something may have gone wrong - check for error condition switch (PInvoke.CommDlgExtendedError()) { case COMMON_DLG_ERRORS.FNERR_INVALIDFILENAME: throw new InvalidOperationException(string.Format(SR.FileDialogInvalidFileName, FileName)); } } return result; } private protected override unsafe string[] ProcessVistaFiles(IFileDialog* dialog) { using ComScope<IShellItem> item = new(null); dialog->GetResult(item); return item.IsNull ? [] : [GetFilePathFromShellItem(item)]; } private protected override unsafe ComScope<IFileDialog> CreateVistaDialog() { HRESULT hr = PInvokeCore.CoCreateInstance( CLSID.FileSaveDialog, pUnkOuter: null, CLSCTX.CLSCTX_INPROC_SERVER | CLSCTX.CLSCTX_LOCAL_SERVER | CLSCTX.CLSCTX_REMOTE_SERVER, out IFileDialog* fileDialog); Debug.Assert(hr.Succeeded); return new(fileDialog); } }