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
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.