Question

I've got a function that returns a SYSTEMTIME.

function GetFileDate : SYSTEMTIME; //Stdcall;
var
    CheckFile: Long;
    FileTime: LPFILETIME;
    FileTimeReturn: LPFILETIME;
    SystemTimeReturn: LPSYSTEMTIME;
begin
    CheckFile := CreateFile(PChar('main.dll'), GENERIC_READ, FILE_SHARE_READ, NIL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
    GetFileTime(CheckFile, @FileTime, NIL, NIL);
    FileTimeToLocalFileTime(@FileTime, @FileTimeReturn);
    FileTimeToSystemTime(@FileTime, @SystemTimeReturn);
    GetFileDate := SystemTimeReturn^;
end;

It always returns 97 for the year, for both files from 2012 and 2006 and anything else. Why?

Was it helpful?

Solution

That code is nonsense, and I'm surprised it compiles at all. You declare three pointer variables, but you never make them point to anything. You pass pointers to those variables to the API functions, but those API functions do not expect pointers to the types you give them.

FileTimeToLocalFileTime expects to receive two FILETIME pointers. You've declared FileTime and FileTimeReturn as pointers to FILETIME values, but when you apply the @ operator to them, you get pointers to pointers to FILETIME values. Better code should look like this:

function GetFileDate : SYSTEMTIME; //Stdcall;
var
  CheckFile: Long;
  FileTime: FILETIME;
  FileTimeReturn: FILETIME;
  SystemTimeReturn: SYSTEMTIME;
begin
  CheckFile := CreateFile(PChar('main.dll'), GENERIC_READ, FILE_SHARE_READ, NIL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
  GetFileTime(CheckFile, @FileTime, NIL, NIL);
  FileTimeToLocalFileTime(@FileTime, @FileTimeReturn);
  FileTimeToSystemTime(@FileTime, @SystemTimeReturn);
  GetFileDate := SystemTimeReturn;
end;

Note that I've removed the LP prefixes from the type names, and I've removed the dereference from the final line.

Correct code would check each API function's return value to make sure it succeeded before calling the next one.


Here's why you get the unexpected results you see. A FILETIME is a 64-bit value. If you're using a 32-bit system, then your LPFILETIME variables are only 32 bits wide. The API expects a pointer to a 64-bit-wide buffer, but you're giving it a pointer to a 32-bit space. When the API writes 64 bits of information into a 32-bit space, we can't be sure where the extra 32 bits are being stored.

You passed a pointer to SystemTimeReturn, which was an LPSYSTEMTIME. The API wrote into that space as though it were a SYSTEMTIME. Then, your function dereferenced what it assumed to be an LPSYSTEMTIME, but which actually held a value of type SYSTEMTIME. You dereferenced a time instead of a pointer. The time you got happens to look like a valid address, and the value residing at that "address" happens to be 97.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top