Delphi XE2 FormatDateTime с передачей -693594 - PullRequest
3 голосов
/ 13 февраля 2012

У нас есть небольшая проблема здесь. Мы обновили Delphi 2006 до Delphi XE2 и в настоящее время преобразуем наш код.

Проблема в том, что мы используем значение -693594 в записях нашего приложения и базы данных, чтобы не указывать дату (нулевую дату). В Delphi 2006 функция FormatDateTime правильно отформатировала бы это как 00/00/0000 (с учетом формата даты дд / мм / гггг).

Однако в Delphi XE2 они добавили вызов ValidateTimeStampDate в функцию DateTImeToTimeStamp в System.SysUtils, которая вызывает ошибку «недопустимая операция с плавающей запятой». передача чего-либо больше, чем -693594, например -693593, работает нормально.

Кто-нибудь еще имел эту проблему и / или кто-нибудь знает обойти?

1 Ответ

3 голосов
/ 14 февраля 2012

Если вам действительно не терпится вернуться к предыдущему поведению, вы можете использовать что-то вроде этого:

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, но я личноизбегайте такого решения.

enter image description here

...