Del*_*mer 3 delphi multithreading vcl c++builder
我现在有一个相当罕见的情况.我有一个直接与Windows的消息队列交互的应用程序.此应用程序还使用LuaJIT运行外部Lua脚本.我想为这些脚本设置调试工具,因此我创建了一个普通的VCL应用程序,然后将其转换为DLL库.当第一个应用程序启动与库的调试会话时,此DLL创建一个分离的线程,其中整个VCL工具被初始化并运行.
procedure TDebuggerThread.Execute;
begin
Application.Initialize;
Application.MainFormOnTaskbar := True;
Application.CreateForm (TMainForm, MainForm);
Application.Run;
end;
Run Code Online (Sandbox Code Playgroud)
VCL是否完全支持以这种方式执行?哪个线程会TThread.Synchronize (Proc: TThreadProc)发送消息?
Inb4"向VCL和主应用程序的消息将会混乱" - 它们不会因为每个线程都有自己的消息队列.
此外,您可以在此处查看来源.(也许)有问题的库被命名LuaDebugger.在地方适当的客户端(Core,Engine,Client)我目前使用的LuaDefaultHost,这是一个相当简单的控制台应用程序,要求调试器和行为大多喜欢lua.exe.与控制台客户端,调试器的工作原理出奇的顺利-我遇到的唯一问题是,如果我关闭控制台窗口,而库仍在使用,VCL抛出"窗口句柄不再有效"(俄文:/).如果我让客户端按照预期的方式完成与调试器的交互,一切都很顺利.可能Windows.TerminateThread在单元定稿期间调用应该解决这个问题.
您唯一的希望是创建线程,然后从该线程加载DLL.因此,为了尽可能清楚,您创建线程,然后从该线程中执行的代码,您调用LoadLibrary加载DLL.
VCL必须用于加载DLL的线程.VCL初始化在DLL初始化期间发生,并确定哪个线程是VCL主线程.VCL主线程是初始化VCL的线程,VCL是加载DLL的线程.
您可能必须对整个方法保持清醒,因为您将在一个进程中拥有两个GUI线程,两个消息泵.显示模态窗口涉及禁用两个GUI线程上的窗口.
我无法确定这种通用方法(同一进程中的两个GUI线程,其中一个是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.
Run Code Online (Sandbox Code Playgroud)
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.
Run Code Online (Sandbox Code Playgroud)
产量
This is the process main thread: 2788 This is the initialization thread of the DLL: 5752 This is the thread created in the DLL: 6232 This is the thread which executes synchronized methods in the DLL: 5752