11

Delphi 2009 では、アプリケーションで TThread.CurrentThread を使用するたびに、アプリケーションを閉じるときに次のようなエラー メッセージが表示されることがわかりました。

Exception EAccessViolation in module ntdll.dll at 0003DBBA.
Access violation at address 7799DBBA in module 'ntdll.dll'.  Write of
address 00000014.

私のマシンでない限り、これを数秒で複製できます。新しい Delphi フォーム アプリケーションを作成し、フォームにボタンを追加し、ボタンのイベント ハンドラに次のようなものを使用します。

procedure TForm1.Button1Click(Sender: TObject);
begin
  TThread.CurrentThread;
end;

Vista マシンと XP マシンの両方で、ボタンをクリックしなければ問題ありません、ボタンをクリックすると、アプリケーションを閉じるときに上記のエラー メッセージが表示されます。

だから...これはバグなのかと思っていますが、同時に、DelphiでTThreadsを操作する方法について非常に基本的なことを理解していない可能性が高いと思います. 私は少しDelphi初心者ですが、恐れています。

そのように TThread.CurrentThread を使用すると明らかに問題がありますか?

そうでない場合、Delphi 2009 を使用している場合、私の単純なサンプル プロジェクトを実装すると同じ問題が発生しますか?


更新: François が以下に指摘したように、これは実際には現時点で Delphi 2009 のバグです。ここで投票できます。


更新: このバグは Delphi 2010 で修正されました。

4

4 に答える 4

15

残念ながら、クラスユニットのファイナライズセクションの呼び出し順序に関連するバグのようです。

DoneThreadSynchronizationThreadLock構造をクリアして
FreeExternalThreadsから、呼び出し時に作成したばかりのThreadオブジェクトを破棄したいので、呼び出しCurrentThread
ThreadLockがすでに初期化されている必要があり
EnterCriticalSection(ThreadLock)ますTThread.RemoveQueuedEvents...

更新QCレポート回避策のパッチ
があります。

于 2008-10-09T18:07:34.633 に答える
12

CodeGear が修正を発行するまでは、以下のパッチを使用できます。スタンドアロン ユニットに保存して、プログラム内の任意の場所で使用します。QCにも追加しようと思います。

このバージョンは、D2009 (オリジナル)、アップデート 1 およびアップデート 2 で動作します。

{ Fix Delphi 2009's invalid finalization order in Classes.pas.
  Written by Primoz Gabrijelcic, http://gp.17slon.com.
  No rights reserved - released to public domain.
}
unit FixD2009Classes;

interface

implementation

uses
  Windows,
  SysUtils,
  Classes;

type
  TCode = array [0..109] of byte;

{$WARN SYMBOL_PLATFORM OFF}

procedure PatchClasses;
{$IFDEF ConditionalExpressions}
{$IF RTLVersion = 20}
var
  i         : integer;
  oldProtect: cardinal;
  pCode     : ^TCode;
  tmp       : DWORD;
const
  COffsets_Call: array [1..12] of integer = (0, 15, 24, 34, 49, 59, 69, 79, 89, 94, 99, 109);
  COffset_UnRegisterModuleClasses = 106;
  COffset_DoneThreadSynchronization = 94;
  COffset_FreeExternalThreads = 99;
  CCallDelta = COffset_FreeExternalThreads - COffset_DoneThreadSynchronization;
{$IFEND}
{$ENDIF}
begin
{$IFDEF ConditionalExpressions}
{$IF RTLVersion = 20}
  pCode := pointer(cardinal(@TStreamReader.ReadToEnd) + COffset_UnRegisterModuleClasses);
  Win32Check(VirtualProtect(pCode, COffsets_Call[High(COffsets_Call)], PAGE_READWRITE, oldProtect));
  try
    for i := Low(COffsets_Call) to High(COffsets_Call) do
      if pCode^[COffsets_Call[i]] <> $E8 then
        raise Exception.Create('Unexpected version of Classes - cannot patch');
    tmp := PDword(@pCode^[COffset_DoneThreadSynchronization+1])^;
    PDword(@pCode^[COffset_DoneThreadSynchronization+1])^ :=
      PDword(@pCode^[COffset_FreeExternalThreads+1])^ + CCallDelta;
    PDword(@pCode^[COffset_FreeExternalThreads+1])^ := tmp - CCallDelta;
  finally VirtualProtect(pCode, COffsets_Call[High(COffsets_Call)], oldProtect, oldProtect); end;
{$IFEND}
{$ENDIF}
end;

initialization
  PatchClasses;
end.
于 2008-10-10T15:58:09.673 に答える
5

Delphi 2009 Update 3 のパッチ ユニット。

{ Fix Delphi 2009's invalid finalization order in Classes.pas.
  Written by Primoz Gabrijelcic, http://gp.17slon.com.
  No rights reserved - released to public domain.

  D2009 update 3 only.
}
unit FixD2009Classes;

interface

implementation

uses
  Windows,
  SysUtils,
  Classes;

type
  TCode = array [0..144] of byte;

{$WARN SYMBOL_PLATFORM OFF}

procedure PatchClasses;
{$IFDEF ConditionalExpressions}
{$IF RTLVersion = 20}
var
  i         : integer;
  oldProtect: cardinal;
  pCode     : ^TCode;
  tmp       : DWORD;
const
  COffsets_Call: array [1..12] of integer = (0, 15, 24, 42, 47, 58, 73, 91, 101, 111, 134, 139);
  COffset_UnRegisterModuleClasses = 107;
  COffset_DoneThreadSynchronization = 134;
  COffset_FreeExternalThreads = 139;
  CCallDelta = COffset_FreeExternalThreads - COffset_DoneThreadSynchronization;
{$IFEND}
{$ENDIF}
begin
{$IFDEF ConditionalExpressions}
{$IF RTLVersion = 20}
  pCode := pointer(cardinal(@TStreamReader.ReadToEnd) + COffset_UnRegisterModuleClasses);
  Win32Check(VirtualProtect(pCode, COffsets_Call[High(COffsets_Call)], PAGE_READWRITE, oldProtect));
  try
    for i := Low(COffsets_Call) to High(COffsets_Call) do
      if pCode^[COffsets_Call[i]] <> $E8 then
        raise Exception.Create('Unexpected version of Classes - cannot patch');
    tmp := PDword(@pCode^[COffset_DoneThreadSynchronization+1])^;
    PDword(@pCode^[COffset_DoneThreadSynchronization+1])^ :=
      PDword(@pCode^[COffset_FreeExternalThreads+1])^ + CCallDelta;
    PDword(@pCode^[COffset_FreeExternalThreads+1])^ := tmp - CCallDelta;
  finally VirtualProtect(pCode, COffsets_Call[High(COffsets_Call)], oldProtect, oldProtect); end;
{$IFEND}
{$ENDIF}
end;

initialization
  PatchClasses;
end.
于 2009-06-11T16:04:28.943 に答える
0

CurrentThreadは2009年(または2007年)に追加されたと思います。私は2006年に家にいます。しかし、それがクラスプロパティであると確信していますか?

于 2008-10-09T17:59:56.290 に答える