При разработке сервисов на Delphi и Pascal, часто возникает необходимость запуска GUI приложений из контекста службы. Однако, в силу того, что службы не имеют графического интерфейса, запущенное из них приложение с графическим интерфейсом не будет отображаться. В данной статье мы рассмотрим, как решить эту проблему, используя примеры кода на Object Pascal.
Описание проблемы
При попытке запустить GUI приложение из сервиса, приложение запускается, но выполняется в контексте службы, что не позволяет увидеть его графический интерфейс. В приведенном ниже коде используется функция CreateProcessAsUser, однако приложение все равно запускается в сессии службы.
procedure RunAppFromService(Path, FileName: string);
var
zPath, zAppName: array[0..512] of char;
StartupInfo: TStartupInfo;
ProcessInfo: TProcessInformation;
begin
// Инициализация переменных
// Вызов CreateProcessAsUser
end;
Подтвержденное решение
Для решения данной проблемы необходимо использовать функции Windows API для запуска процесса от имени пользователя. В частности, следует использовать WTSQueryUserToken с WtsGetActiveConsoleSessionID, чтобы получить токен текущего активного пользователя, а затем использовать CreateEnvironmentBlock и CreateProcessAsUserW для запуска процесса.
function RunAppFromService(const Path, FileName: string): Boolean;
var
zPath, zAppName: array[0..512] of char;
StartupInfo: TStartupInfo;
ProcessInfo: TProcessInformation;
hUserToken: THandle;
p: Pointer;
begin
// Инициализация переменных
// Получение токена пользователя
// Создание среды для процесса
// Запуск процесса с использованием токена пользователя
end;
В обновленной версии кода, после комментария Remy Lebeau, добавлено использование WTSEnumerateSessions для перебора активных сессий и выбора подходящего токена пользователя.
function RunAppFromService(const Path, FileName: string): Boolean;
var
// ... переменные
Sessions, Session: PWTS_SESSION_INFO;
NumSessions: DWORD;
I: Integer;
begin
// Инициализация переменных
// Перебор сессий для выбора активной
// Получение токена пользователя выбранной сессии
// Создание среды для процесса
// Запуск процесса с использованием токена пользователя
end;
Важные замечания
WTSQueryUserToken работает только если сервис запущен в аккаунте SYSTEM.
Лучше использовать WTSEnumerateSessions и WTSQuerySessionInformation для выбора активной сессии, особенно если приложение должно запускаться от имени конкретного пользователя или клиентского ПК.
Заключение
При запуске GUI приложений из сервисов важно использовать функции Windows API для работы с токенами пользователей и сессиями. Приведенный выше код демонстрирует, как это можно сделать на языке Object Pascal в среде Delphi. Следуя этим рекомендациям, разработчики смогут успешно запускать графические приложения из контекста сервиса.
При разработке сервисов на Delphi и Pascal, рассматривается проблема отображения GUI приложений при запуске из контекста службы и предлагаются решения с использованием функций Windows API для работы с токенами пользователей и сессиями.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS