0

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;

2012 年と 2006 年の両方のファイル、およびそれ以外のファイルについては、年に対して常に 97 を返します。なんで?

4

1 に答える 1

3

そのコードはナンセンスで、まったくコンパイルできることに驚いています。3 つのポインター変数を宣言しますが、それらが何かを指すようにすることはありません。これらの変数へのポインターを API 関数に渡しますが、これらの API 関数は、指定した型へのポインターを想定していません。

FileTimeToLocalFileTimeFILETIME2 つのポインタを受け取ることを期待しています。FileTimeandFileTimeReturnを値へのポインターとして宣言しましたが、演算子をそれらにFILETIME適用すると、値へのポインターへのポインターが得られます。より良いコードは次のようになります。@FILETIME

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;

LP型名からプレフィックスを削除し、最終行から逆参照を削除したことに注意してください。

正しいコードは、各 API 関数の戻り値をチェックして、次の関数を呼び出す前に成功したことを確認します。


予期しない結果が得られる理由は次のとおりです。AFILETIMEは 64 ビット値です。32 ビット システムを使用している場合、LPFILETIME変数は 32 ビット幅しかありません。API は 64 ビット幅のバッファーへのポインターを想定していますが、32 ビット空間へのポインターを指定しています。API が 64 ビットの情報を 32 ビット空間に書き込む場合、余分な 32 ビットがどこに格納されているかはわかりません。

へのポインタを渡しましたがSystemTimeReturn、これはLPSYSTEMTIME. API は、あたかもSYSTEMTIME. 次に、関数は であると想定しているものを逆参照しましたが、LPSYSTEMTIME実際には type の値を保持していましたSYSTEMTIME。ポインターの代わりに時間を逆参照しました。得られた時間はたまたま有効なアドレスのように見え、その「アドレス」にある値はたまたま 97 です。

于 2012-09-06T21:31:13.047 に答える