Using the standard VCL TFileStream class you can’t set a sharing mode for a new file until Delphi 2010. A trick like this
var
Stream: TStream;
begin
Stream:= TFileStream.Create('TEST', fmCreate or fmShareDenyWrite);
...
is useless since fmCreate or fmShareDenyWrite = fmCreate, and you can see from VCL sources that a new file is created without sharing. There is a bug report #71632 on QC currently marked as “fixed” (in Delphi 2010, and I am using Delphi 2009).
If one need to create a new file with sharing enabled in Delphi 2009 or prior Delphi version, a class helper looks like a good workaround. Let us create a “helper” unit which extends TFileStream functionality by adding an additional constructor:
unit MyClasses;
interface
uses RTLConsts, Windows, SysUtils, Classes;
type
TMyFileStream = class helper for TFileStream
constructor CreateNew(const AFileName: string; ShareMode: LongWord = 0);
end;
implementation
{
Valid ShareMode values are:
FILE_SHARE_READ,
FILE_SHARE_WRITE,
FILE_SHARE_DELETE,
or any combination like FILE_SHARE_READ or FILE_SHARE_WRITE, etc
}
constructor TMyFileStream.CreateNew(const AFileName: string; ShareMode: LongWord);
var
FileHandle: THandle;
begin
FileHandle:= CreateFile(PChar(AFileName), GENERIC_READ or GENERIC_WRITE,
ShareMode, nil, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
if FileHandle = INVALID_HANDLE_VALUE then
raise EFOpenError.CreateResFmt(@SFOpenErrorEx,
[ExpandFileName(AFileName), SysErrorMessage(GetLastError)]);
inherited Create(FileHandle);
// FFileName := AFileName;
end;
end.
Now we can test the constructor. Create a new VCL application and add the “MyClasses.pas” unit to the “uses” clause of the main form; drop a button component to the main form and create an event handler:
procedure TForm1.Button1Click(Sender: TObject);
var
Stream, TestStream: TStream;
Buf, OutBuf: Cardinal;
begin
// Stream:= TFileStream.CreateNew('TEST');
Stream:= TFileStream.CreateNew('TEST', FILE_SHARE_READ);
try
Buf:= 12345678;
Stream.WriteBuffer(Buf, SizeOf(Buf));
TestStream:= TFileStream.Create('TEST', fmOpenRead or fmShareDenyNone);
try
TestStream.ReadBuffer(OutBuf, SizeOf(OutBuf));
ShowMessage(IntToStr(OutBuf));
finally
TestStream.Free;
end;
finally
Stream.Free;
end;
end;
We can see that file sharing for a newly created file really works.
Note that we use TFileStream.CreateNew syntax (not TMyFileStream.CreateNew). The only problem with CreateNew constructor is TFileStream.FileName property – since TFileStream.FFileName field is declared as strict private it is not accessible from a class helper, and the field cannot be set in the CreateNew constructor.