正如我在评论中所说,这不是“隐形代码”,只是导致问题的某些单元的初始化部分中的代码。我已经成功地找到了罪魁祸首(至少是其中之一 - 可能还有其他人)。
当您使用Forms
单位,它依赖于Classes
unit.
初始化部分调用InitThreadSynchronization
,其中包括以下内容:
SyncEvent := CreateEvent(nil, True, False, '');
if SyncEvent = 0 then
RaiseLastOSError;
看来API调用CreateEvent
从登录屏幕内调用时失败。不幸的是,我不确定登录屏幕是否:(a) 禁止CreateEvent
总共 (b) 要求CreateEventEx
相反或(c)将与适当的lpEventAttributes
争论。我发布了一个更具体的问题,希望能找到答案:从 Windows-7 登录屏幕创建事件 https://stackoverflow.com/q/24726463/224704
您可以使用以下控制台应用程序验证问题:
program TestLoginScreensaver;
{$APPTYPE CONSOLE}
uses
Windows,
SysUtils;
var
SyncEvent: THandle;
begin
try
SyncEvent := CreateEvent(nil, True, False, '');
if SyncEvent = 0 then
RaiseLastOSError;
CloseHandle(SyncEvent); //So handle is closed if it was created (e.g. while logged in)
except
on E:Exception do
Writeln(E.Classname, ': ', E.Message);
end;
Readln;
end.
的目的SyncEvent
是为了启用TThread
实例同步回主线程。因此,如果您编写一个单线程应用程序,或者使用除TThread
,你实际上并不需要/使用SyncEvent
at all.
旁白:这是使用问题的一个主要例子初始化部分。仅仅包含一个单元就有可能引入不必要的副作用。他们是基本上无害,但在本例中并非如此。现在你可能会争辩说Classes.pas
很臃肿,我不会争论。但重点是,如果类初始化被调用明确地从 DPR 来看,这个问题会更容易识别并找到解决方法。
编辑:新解决方案
正如雷米·勒博(Remy Lebeau)在我发布的另一个问题中指出的那样。
该行:
SyncEvent := CreateEvent(nil, True, False, '');
必须改为:
SyncEvent := CreateEvent(nil, True, False, nil);
由于此解决方案涉及重新编译 VCL 单元,因此您可能需要经历一些之前的问题 https://stackoverflow.com/search?q=%5Bdelphi%5D+recompile+vcl+units关于这个话题
有了这个作为唯一的更改(在 D2009 中编译),我能够在登录屏幕上成功显示空白表单。但是,请记住,由于登录屏幕上的安全限制,您通常希望能够执行的某些操作将受到限制。