3

ここで少し問題があります。Delphi 2006 から Delphi XE2 にアップグレードし、コードを変換中です。

問題は、アプリケーションとデータベース レコードで値 -693594 を使用して日付なし (ゼロ日付) を表すことです。Delphi 2006 では、FormatDateTime 関数はこれを 00/00/0000 として正しくフォーマットします (日付フォーマットが dd/mm/yyyy の場合)。

ただし、Delphi XE2 では、System.SysUtils の DateTImeToTimeStamp 関数に ValidateTimeStampDate への呼び出しが追加され、「無効な浮動小数点演算」というエラーが発生します。-693593 など、-693594 より大きい値を渡すと問題なく動作します。

他の誰かがこの問題を抱えていますか、または回避策を知っている人はいますか?

4

1 に答える 1

3

以前の動作にパッチを適用したい場合は、次のようなものを使用できます。

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure PatchCode(Address: Pointer; const NewCode; Size: Integer);
var
  OldProtect: DWORD;
begin
  if VirtualProtect(Address, Size, PAGE_EXECUTE_READWRITE, OldProtect) then
  begin
    Move(NewCode, Address^, Size);
    FlushInstructionCache(GetCurrentProcess, Address, Size);
    VirtualProtect(Address, Size, OldProtect, @OldProtect);
  end;
end;

type
  PInstruction = ^TInstruction;
  TInstruction = packed record
    Opcode: Byte;
    Offset: Integer;
  end;

procedure RedirectProcedure(OldAddress, NewAddress: Pointer);
var
  NewCode: TInstruction;
begin
  NewCode.Opcode := $E9;//jump relative
  NewCode.Offset := NativeInt(NewAddress)-NativeInt(OldAddress)-SizeOf(NewCode);
  PatchCode(OldAddress, NewCode, SizeOf(NewCode));
end;

function DateTimeToTimeStamp(DateTime: TDateTime): TTimeStamp;
const
  FMSecsPerDay: Single = MSecsPerDay;
  IMSecsPerDay: Integer = MSecsPerDay;
var
  LTemp, LTemp2: Int64;
begin
  LTemp := Round(DateTime * FMSecsPerDay);
  LTemp2 := (LTemp div IMSecsPerDay);
  Result.Date := DateDelta + LTemp2;
  Result.Time := Abs(LTemp) mod IMSecsPerDay;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  ShowMessage(FormatDateTime('dd/mm/yyyy', -693594));
end;

initialization
  RedirectProcedure(@System.SysUtils.DateTimeToTimeStamp, @DateTimeToTimeStamp);

end.

これは 32 ビット コードで機能します。古い関数と新しい関数の両方が同じ実行可能モジュールに存在する場合は、64 ビット コードでも機能します。そうしないと、ジャンプ距離が 32 ビット整数の範囲を超える可能性があります。RTL がランタイム パッケージにある場合も機能しません。これらの制限はどちらも簡単に解決できます。

SysUtils.DateTimeToTimeStampこのコードが行うことは、このユニットに実装されているバージョンへのすべての呼び出しを再ルーティングすることです。この単元のコードはPUREPASCAL、XE2 ソースからのバージョンにすぎません。

コメントで概説されているニーズを満たす唯一の他のアプローチは、SysUtils ユニット自体を変更して再コンパイルすることですが、私は個人的にそのような解決策を避けています。

ここに画像の説明を入力

于 2012-02-13T23:15:31.617 に答える