我的应用程序可以Master
或Worker
启动,它由启动参数控制。
program MyApp;
uses
SysUtils, Forms, WorkerForm, MasterForm;
begin
Application.Initialize;
//if ParamStr(1) = 'WorkerProcess' then
if FindCmdLineSwitch('--WorkerProcess') then
Application.CreateForm(TWorkerForm, WorkerForm)
else
Application.CreateForm(TMasterForm, MasterForm);
Application.Run;
end;
主进程可以派生工作进程。如果无法在3秒内启动工作进程,则主进程将显示错误。最近我将GDIPOBJ包含在应用程序中,因此无法按时分叉工作进程。
我通过延长等待时间来解决问题。但是由于工作进程没有UI,所以它不需要Gdi +的东西。我非常好奇地问所有亲爱的德尔菲专家,如果可以有条件地装载一个单元或有条件地初始化一个单元。
我当前的解决方案是将单元复制到我的项目目录并将代码移动到方法InitGidplusStartup
。当我创建MasterProcess
时,我必须显式调用该方法。
procedure InitGdiplusStartup;
begin
if not IsLibrary then
begin
// Initialize StartupInput structure
StartupInput.DebugEventCallback := nil;
StartupInput.SuppressBackgroundThread := False;
StartupInput.SuppressExternalCodecs := False;
StartupInput.GdiplusVersion := 1;
GdiplusStartup(gdiplusToken, @StartupInput, nil);
end;
end;
initialization
(*
if not IsLibrary then
begin
// Initialize StartupInput structure
StartupInput.DebugEventCallback := nil;
StartupInput.SuppressBackgroundThread := False;
StartupInput.SuppressExternalCodecs := False;
StartupInput.GdiplusVersion := 1;
GdiplusStartup(gdiplusToken, @StartupInput, nil);
end;
*)
program MyApp;
uses
GDIPOBJ{INCLUDE MODIFIED VERSION FIRST AND I KNOW THE RISK},
SysUtils, Forms, WorkerForm, MasterForm;
begin
Application.Initialize;
if FindCmdLineSwitch('--WorkerProcess') then
Application.CreateForm(TWorkerForm, WorkerForm)
else
begin
InitGdiplusStartup;
Application.CreateForm(TMasterForm, MasterForm);
end;
Application.Run;
end;
我知道这不是一种标准方法。我只是想了解单元初始化及其局限性。请不要怪我。
答案 0 :(得分:2)
单元未在运行时加载,它们在编译期间链接。如果要区分命令行参数,则无论是否使用,都必须存在该单元。编译器无法知道运行时参数,因此无论如何都必须链接该单元。
如果您可以分离初始化代码,则可以使用它。请注意,当您采用这种方式时,在初始化序列期间执行代码的时间可能会有所不同。
另一种可能很麻烦的方法是将违规单位放入一个只按需加载的包裹中。
答案 1 :(得分:2)
无条件执行单元初始化部分。因此,我可以看到以下可用于解决问题的选项:
后一种选择很容易做到。获取gdipobj单元的副本,并将其包含在项目的源代码树中。确保在.dpr文件中引用了此单元。修改此单元副本的initialization
部分,以根据您的条件跳过初始化。
答案 2 :(得分:1)
使用DDetours library
https://code.google.com/p/delphi-detours-library/wiki/DDetours
将呼叫修补到GDIplusStartup
。
首先在项目中添加此单元。
Unit PatchGDI;
Interface
uses
WinApi.GDIPAPI, DDetours;
Implementation
var
TrampolineGdiplusStartup : function(out token: ULONG; input: PGdiplusStartupInput;
output: PGdiplusStartupOutput): Status; stdcall = nil;
function InterceptGdiplusStartup(out token: ULONG; input: PGdiplusStartupInput;
output: PGdiplusStartupOutput): Status; stdcall;
begin
Result := GdiplusNotInitialized;
end;
Initialization
if ParamStr(1) = 'WorkerProcess' then
@TrampolineGdiplusStartup := InterceptCreate(@GdiplusStartup, @InterceptGdiplusStartup);
end.
免责声明,未经测试,但您明白了。
这是一个示例项目。在调试模式下运行它,您可以看到GDIplusStartup
被截获,GDIPOBJ中的初始化代码正在调用截获的过程:
program Project124;
{$APPTYPE CONSOLE}
uses
System.SysUtils,
PatchGDI in 'PatchGDI.pas',
GDIPOBJ;
begin
end.