Ответ 1
Как я уже сказал в своем комментарии, это не "невидимый код", просто код в разделе инициализации какой-то единицы, вызывающей проблему. Мне удалось выследить преступника (ну хотя бы один из них - могут быть и другие).
Когда вы используете блок 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. Это яркий пример проблемы с использованием раздела инициализации. Простое включение устройства может ввести ненужные побочные эффекты. Они в основном безвредны, но не в этом случае. Теперь вы можете утверждать, что
Classes.pas
раздувается, и я не буду спорить. Но дело в том, что если инициализация классов была вызвана явно из DPR, эта проблема была бы легче идентифицировать и найти обходной путь для.
EDIT: новое решение
Как заметил Реми Лебо в другом вопросе, который я опубликовал.
Строка:
SyncEvent := CreateEvent(nil, True, False, '');
Необходимо изменить на:
SyncEvent := CreateEvent(nil, True, False, nil);
Поскольку это решение включает в себя перекомпиляцию единиц VCL, вы можете пройти несколько предыдущих предыдущих вопросов по этому вопросу
С этим в качестве единственного изменения (скомпилированного в D2009) я смог успешно показать пустую форму на экране входа в систему. Однако имейте в виду, что некоторые вещи, которые вы обычно можете ожидать, будут недоступны из-за ограничений безопасности на экране входа в систему.