delphidelphi-2007readonly-attributetsavedialog

Delphi 2007 - Allowing a Read-only file to be selected in a TSaveDialog


I have a need for a user to be able to select an existing read-only file from a save dialog. I thought you could do this with a judicious selection of the TSaveDialog options but I can't make it happen. If I select a R/O file, as soon as I hit the Save button I get the message:

    Read-only.txt
    This file is set to read-only.
    Try again with a different file name.

I imagined the option bit ofNoReadOnlyReturn would control this, but it seems to have no effect.

What am I missing?

program Project1;

uses
  Forms,
  Unit1 in 'Unit1.pas' {Form1};

{$R *.res}

begin
  Application.Initialize;
  Application.MainFormOnTaskbar := True;
  Application.CreateForm(TForm1, Form1);
  Application.Run;
end.

-

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    SaveDialog1: TSaveDialog;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
if SaveDialog1.Execute then
    begin
    Windows.Beep (1000, 300) ;
    end ;
end ;

end.

-

object Form1: TForm1
  Left = 0
  Top = 0
  Caption = 'Form1'
  ClientHeight = 69
  ClientWidth = 195
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'Tahoma'
  Font.Style = []
  OldCreateOrder = False
  PixelsPerInch = 96
  TextHeight = 13
  object Button1: TButton
    Left = 56
    Top = 18
    Width = 75
    Height = 25
    Caption = 'Button1'
    TabOrder = 0
    OnClick = Button1Click
  end
  object SaveDialog1: TSaveDialog
    FileName = 'Read-only.txt'
    InitialDir = 'C:\Users\Ross\Documents\RAD Studio\Projects'
    Options = [ofHideReadOnly, ofNoReadOnlyReturn, ofEnableSizing]
    Left = 16
    Top = 16
  end
end

Solution

  • The issue is not with TSaveDialog itself, but with the underlying Win32 GetSaveFileName()/IFileSaveDialog APIs that TSaveDialog uses internally. They simply do not allow a read/only file to be the result of a "save" dialog.

    That being said, IFileSaveDialog does provide a possible (albeit ugly) workaround. If you enable the dialog's FOS_OVERWRITEPROMPT flag, then selecting an existing file will prompt the user if the file can be overwritten before closing the dialog. The IFileDialogEvents interface has an OnOverwrite event, which is fired before that prompt appears (and can return FDESVR_ACCEPT to skip the prompt completely). So, in that event, you could remove the file's FILE_ATTRIBUTE_READONLY attribute before the dialog is closed. However, the dialog will still display the same "This file is set to read-only" error message and refuse to close (presumably because it has checked the attribute before firing the OnOverwrite event), but if you then select the same file again, the attribute will have been cleared and the dialog will accept the file (that is the ugly part - you would have to train your managers to ignore that error and retry).

    GetSaveFileName() has an ofOverwritePrompt flag, but no event for overwrite prompting.

    That being said, TSaveDialog does not expose access to the IFileSaveDialog.OnOverwrite event when it uses IFileSaveDialog internally, but you can use TFileSaveDialog instead, which does.