0

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?

Name McChange
  • 2,750
  • 5
  • 27
  • 46
  • Buy Apple stock. It'll be worth something in a few years ;) PS: a type with "LP" usually means "Long Pointer"; i.e. a 32-bit address. You probably want a "FILETIME" or a "SYSTEMTIME" record; *not* an "LPFILETIME" ;) – paulsm4 Sep 06 '12 at 21:40
  • If you see the latest answer to [your last question](http://stackoverflow.com/questions/12291076/pascal-get-field-from-lpsystemtime-record), you'll see what's wrong with this code in the first place, and also find the fix for this question. (There's a reason you're notified of new content on your questions - it's so you can check that content.) :-) – Ken White Sep 06 '12 at 22:56
  • How embarrassing. Sorry. – Name McChange Sep 07 '12 at 01:11

1 Answers1

3

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.

Rob Kennedy
  • 161,384
  • 21
  • 275
  • 467
  • +1. See this poster's last question at http://stackoverflow.com/questions/12291076/pascal-get-field-from-lpsystemtime-record - Remy Lebeau has also corrected this problem there, but apparently SuperDisk isn't checking the new content. :-) – Ken White Sep 06 '12 at 22:57
  • @KenWhite He didn't have the edit posted whenever I made this question. Sorry if all of this Pascal Winapi stuff sounds like complete idiotism, I'm just trying to get a grasp on Pascal. – Name McChange Sep 07 '12 at 01:00
  • That's OK. Remy's second answer didn't really answer the question you asked anyway. It answered the question you asked here, which is an entirely different issue from what you asked about before. One is a compiler error, and the other's a run-time error. You were right to post this question; you didn't need to post the function body in the other question since it had no bearing on the compiler error. – Rob Kennedy Sep 07 '12 at 13:10