Как я уже сказал в своем комментарии, это не «невидимый код», просто код в разделе инициализации некоторого устройства, вызывающего проблему. Мне удалось отследить преступника (ну, по крайней мере, одного из них - могут быть и другие).
Когда вы используете блок Forms
, он зависит от блока Classes
.
Раздел инициализации вызывает InitThreadSynchronization
, что среди прочего вызывает следующее:
SyncEvent := CreateEvent(nil, True, False, '');
if SyncEvent = 0 then
RaiseLastOSError;
Похоже, вызов API CreateEvent
завершается неудачно при вызове из экрана входа в систему. К сожалению, я не уверен, что экран входа в систему: (a) вообще запрещает CreateEvent
(b) вместо него CreateEventEx
или (c) будет работать с соответствующим аргументом lpEventAttributes
. Я разместил более конкретный вопрос, который, надеюсь, узнаем: CreateEvent из Windows-7 Экран входа в систему
Вы можете проверить проблему с помощью следующего консольного приложения:
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
.
SIDE-RANT : Это яркий пример проблемы с использованием раздела initialization . Простое включение устройства может привести к ненужным побочным эффектам. Они В основном безвредны , но не в этом случае. Теперь вы можете утверждать, что Classes.pas
раздут, и я не буду спорить. Но дело в том, что если бы инициализация классов была вызвана явно из DPR, эту проблему было бы легче идентифицировать и найти обходной путь для.
РЕДАКТИРОВАТЬ: новое решение
Как заметил Реми Лебо в другом моем вопросе.
Линия:
SyncEvent := CreateEvent(nil, True, False, '');
Должен быть изменен на:
SyncEvent := CreateEvent(nil, True, False, nil);
Поскольку это решение включает в себя перекомпиляцию блоков VCL, вам может понадобиться ответить на несколько предыдущих вопросов на эту тему
С этим единственным изменением (скомпилировано в D2009) я смог успешно показать пустую форму на экране входа в систему. Однако имейте в виду, что некоторые вещи, которые вы обычно можете ожидать, будут недоступны из-за ограничений безопасности на экране входа в систему.