TThread
インスタンスの作成から起動までの間、メイン スレッドはコードの実行を続行します。メインスレッドのコードが問題のスレッドに依存して完全に稼働している場合、スレッドExecute
メソッドが実際に開始されるまで何らかの形で待機する必要があります。
次のコードを検討してください。
const
WM_MY_ACTION = WM_APP + 10;
type
TWndThread = class(TThread)
protected
fWndHandle: THandle;
IsRunning: boolean;
procedure WndProc(var Msg: TMessage);
procedure Execute; override;
public
Test: integer;
procedure AfterConstruction; override;
procedure DoAction;
end;
procedure TWndThread.AfterConstruction;
begin
inherited;
while not IsRunning do Sleep(100); // wait for thread start up
end;
procedure TWndThread.Execute;
var
Msg: TMsg;
begin
fWndHandle := AllocateHWnd(WndProc);
IsRunning := true;
try
while not Terminated do
begin
if MsgWaitForMultipleObjects(0, nil^, False, 1000, QS_ALLINPUT) = WAIT_OBJECT_0 then
begin
while PeekMessage(Msg, 0, 0, 0, PM_REMOVE) do
begin
TranslateMessage(Msg);
DispatchMessage(Msg);
end;
end;
end;
finally
DeallocateHWnd(fWndHandle);
end;
end;
procedure TWndThread.WndProc(var Msg: TMessage);
begin
case Msg.Msg of
WM_MY_ACTION:
begin
inc(Test);
end;
else Msg.Result := DefWindowProc(fWndHandle, Msg.Msg, Msg.WParam, Msg.LParam);
end;
end;
procedure TWndThread.DoAction;
begin
PostMessage(fWndHandle, WM_MY_ACTION, 0, 0);
end;
var
t: TWndThread;
begin
t := TWndThread.Create;
t.DoAction;
t.Terminate;
end;
IsRunning
フラグを待機するループDoAction
がないと、含まれているウィンドウ ハンドルがまだ作成されないため、メッセージを正常に投稿できません。基本的にinc(Test)
内部WndProc
は発動しません。
スレッドの起動を待ってExecute
メソッド内で必要な初期化を完了するためのより良い方法はありますか、それともこの解決策はうまくいきますか?
注: とはスレッド セーフではないことを認識しており、上記の例のような製品コードでは使用しないでくださいAllocateHWnd
。DeallocateHWnd