I performed some tests with Beta 12 and got interesting results. Below is a small test program - it creates two identical files (C:\dir1\TEST.txt and C:\dir2\TEST.txt) and locks whole C:\dir1\TEST.txt file (with LockFile API).
Test 1:
1) Launch "Test.exe /test1" - this will create test files (with size > 1MB), lock one of them and display a message box - don't close this message box, but go (with TC) to C:\dir1 in one panel and C:\dir2 in another panel.
2a) Use "File -> Compare By Content" to compare TEST.txt in both panels.
Expected: Message box "The two files have the same content!".
Currently: "Compare contents" window appears, but shows "0 differences found".
2b) Select "Commands -> Synchronize Dirs", check "by content" option and press "Compare" button.
Expected: files are shown as identical.
Currently: files are shown as different.
Test 2:
1) Launch "Test.exe /test2" - this will create test files (with size < 1MB), ...
2a) Use "File -> Compare By Content" to compare TEST.txt in both panels.
Expected: as in Test 1.
Currently: message box: "Access denied on file c:\dir1\TEST.txt!".
2b) Select "Commands -> Synchronize Dirs", check "by content" option and press "Compare" button.
Expected: as in Test 1.
Currently: as in Test 1.
Conclusions:
- The window, that shows results of comparing, can read locked files of size > 1MB, but can't < 1MB. Reading files larger than 1MB is possible, because a file mapping is used for such files - and, as MSDN says, "locking a region of a file does not prevent reading from a mapped file view".
- The function, that simply checks if files are identical or not, doesn't use file mappings at all, so it always fails when comparing locked files.
To solve all these problems:
Create a global wrapper for ReadFile function. In all cases, when ReadFile fails with error code 33 (ERROR_LOCK_VIOLATION), create a file mapping - not for the whole file, but only for the area being currently read - and get file contents from a view of the mapped file.
Regards
Code: Select all
program Test;
uses
Windows, SysUtils;
const
FileName1 = 'C:\dir1\TEST.txt';
FileName2 = 'C:\dir2\TEST.txt';
var
FileBytes : Integer;
F : TextFile;
S : string;
I : Integer;
FH : THandle;
begin
try
{1. Check input parameter}
S:=LowerCase(ParamStr(1));
if S = '/test1' then
FileBytes:=$100000+$10
else
if S = '/test2' then
FileBytes:=$100000-$10
else
raise Exception.Create('Use parameter /test1 or /test2.');
try
{2. Initialize test}
CreateDir(ExtractFilePath(FileName1));
CreateDir(ExtractFilePath(FileName2));
S:='0123456789abcd';
AssignFile(F,FileName1);
Rewrite(F);
for I:=1 to FileBytes div (Length(S)+Length(#13#10)) do
Writeln(F,S);
CloseFile(F);
AssignFile(F,FileName2);
Rewrite(F);
for I:=1 to FileBytes div (Length(S)+Length(#13#10)) do
Writeln(F,S);
CloseFile(F);
{3. Perform test}
FH:=CreateFile(PChar(FileName1),GENERIC_READ or GENERIC_WRITE,FILE_SHARE_READ,nil,OPEN_EXISTING,0,0);
if FH = INVALID_HANDLE_VALUE then
raise Exception.Create('CreateFile failed.');
try
if not LockFile(FH,0,0,High(Integer),0) then
raise Exception.Create('LockFile failed.');
MessageBox(0,PChar('File '+FileName1+' is locked now - perform the TC test!'),'Test',MB_ICONINFORMATION);
finally
CloseHandle(FH);
end;
finally
{4. Finalize test}
DeleteFile(FileName1);
DeleteFile(FileName2);
RemoveDir(ExtractFilePath(FileName1));
RemoveDir(ExtractFilePath(FileName2));
end;
except
on E:Exception do
MessageBox(0,PChar(E.ClassName+':'#13#10+E.Message),'Exception',MB_ICONSTOP);
end;
end.