唯一の希望は、スレッドを作成し、そのスレッドから DLL をロードすることです。したがって、できるだけ明確にするために、スレッドを作成し、そのスレッド内で実行されているコードから呼び出しLoadLibrary
て DLL をロードします。
VCL は、DLL をロードするスレッドから実行する必要があります。VCL の初期化は DLL の初期化中に行われ、どのスレッドが VCL メイン スレッドであるかが決定されます。VCL メイン スレッドは、VCL を初期化するスレッドであり、DLL をロードするスレッドです。
1 つのプロセスで 2 つの GUI スレッド、2 つのメッセージ ポンプを使用するため、このアプローチ全体について明確な頭を保つ必要があります。モーダル ウィンドウを表示するには、両方の GUI スレッドでウィンドウを無効にする必要があります。
この一般的なアプローチ (同じプロセスに 2 つの GUI スレッドがあり、そのうちの 1 つは VCL スレッド) が機能するかどうかは、実際に行ったことがないので確信が持てません。でも、飛べる可能性は十分あると思います。
また、非常に具体的な質問をします。
TThread.Synchronize (Proc: TThreadProc) はどのスレッドにメッセージを送信しますか?
答えは常に、モジュールを初期化したスレッドです。したがって、実行可能ファイルの場合、これはプロセスのメイン スレッドです。DLL の場合、モジュールを初期化したスレッドは、 を呼び出したスレッドLoadLibrary
、 への最初の呼び出しを実行するDllMain
スレッド、DLL ユニットの初期化コードを実行するスレッドです。これは、RTL/VCL ではモジュールのメイン スレッドとして知られています。によって ID が指定されたスレッドですSystem.MainThreadID
。
この点を証明するために、これについて私の言葉を信じない場合のために、ここに少しデモンストレーションを示します。
実行可能
program DllThreading;
{$APPTYPE CONSOLE}
uses
Classes, Windows;
type
TMyThread = class(TThread)
protected
procedure Execute; override;
end;
procedure TMyThread.Execute;
var
lib: HMODULE;
proc: procedure; stdcall;
begin
lib := LoadLibrary('dll.dll');
proc := GetProcAddress(lib, 'foo');
proc();
Sleep(INFINITE);
end;
begin
Writeln('This is the process main thread: ', GetCurrentThreadId);
TMyThread.Create;
Readln;
end.
DLL
library Dll;
uses
Classes, Windows;
type
TMyThread = class(TThread)
private
procedure DoStuff;
protected
procedure Execute; override;
end;
procedure TMyThread.DoStuff;
begin
Writeln('This is the thread which executes synchronized methods in the DLL: ', GetCurrentThreadId);
end;
procedure TMyThread.Execute;
begin
Writeln('This is the thread created in the DLL: ', GetCurrentThreadId);
Synchronize(DoStuff);
end;
procedure foo; stdcall;
begin
TMyThread.Create;
CheckSynchronize(1000);
end;
exports
foo;
begin
Writeln('This is the initialization thread of the DLL: ', GetCurrentThreadId);
end.
出力
これはプロセスのメイン スレッドです: 2788
これは DLL の初期化スレッドです: 5752
これは DLL で作成されたスレッドです: 6232
これは、DLL で同期メソッドを実行するスレッドです: 5752