Here is the implementation of FileGetDate()
in Delphi 5:
function FileGetDate(Handle: Integer): Integer;
var
FileTime, LocalFileTime: TFileTime;
begin
if GetFileTime(THandle(Handle), nil, nil, @FileTime) and
FileTimeToLocalFileTime(FileTime, LocalFileTime) and
FileTimeToDosDateTime(LocalFileTime, LongRec(Result).Hi,
LongRec(Result).Lo) then Exit;
Result := -1;
end;
That is 3 different points of failure that could happen on any given input file handle:
does GetFileTime()
fail?
does FileTimeToLocalFileTime()
fail?
does FileTimeToDosDateTime()
fail?
Unless FileOpen()
fails (which you are not checking for - it returns -1
if it is not able to open the file), then it is unlikely (but not impossible) that #1 or #2 are failing. But #3 does have a documented caveat:
The MS-DOS date format can represent only dates between 1/1/1980 and 12/31/2107; this conversion fails if the input file time is outside this range.
It is not likely that you encounter files with timestamps in the year 2108 and later, but you can certainly encounter files with timestamps in the year 1979 and earlier.
All 4 functions (counting the CreateFile()
function called inside of FileOpen()
) report an error code via GetLastError()
, so you can do this:
var
Src : integer;
FileDate : LongInt;
begin
Src := FileOpen(SrcPath, fmOpenRead);
Win32Check(Src <> -1);
FileDate := FileGetDate(Src);
Win32Check(FileDate <> -1);
...
Win32Check(FileSetDate(Dest, FileDate) = 0);
Win32Check()
calls RaiseLastWin32Error()
if the input parameter is false. RaiseLastWin32Error()
raises an EOSError
exception containing the actual error code in its ErrorCode
property.
If FileGetDate()
fails, obviously you won't know which Win32 function actually failed. That is where the debugger comes into play. Enable Debug DCUs in your Project Options to allow you to step into the VCL/RTL source code. Find a file that fails, call FileGetDate() on it, and step through its source code to see which if the three API functions is actually failing.
Similarly for FileSetDate()
, which also calls 3 API functions internally:
function FileSetDate(Handle: Integer; Age: Integer): Integer;
var
LocalFileTime, FileTime: TFileTime;
begin
Result := 0;
if DosDateTimeToFileTime(LongRec(Age).Hi, LongRec(Age).Lo, LocalFileTime) and
LocalFileTimeToFileTime(LocalFileTime, FileTime) and
SetFileTime(Handle, nil, nil, @FileTime) then Exit;
Result := GetLastError;
end;
If FileSetDate()
fails, is it because:
DosDateTimeToFileTime()
failed?
LocalFileTimeToFileTime()
failed?
does SetFileTime()
failed?