Запуск процесса в сеансе пользователя из службы

:: известен как ссылки на методы. Допустим, мы хотим вызвать метод calculatePrice класса Purchase. Затем мы можем записать его как:

Purchase::calculatePrice

Его также можно рассматривать как короткую форму записи выражения лямбда. Так как ссылки методов преобразуются в лямбда-выражения.

13
задан Brad 4 February 2016 в 15:56
поделиться

3 ответа

Это действительно возможно. Основная проблема заключается в том, что Windows следует рассматривать как терминальный сервер, а пользовательский сеанс - как удаленный сеанс. Ваша служба должна иметь возможность запускать процесс, который выполняется в удаленном сеансе, принадлежащем пользователю.

Между прочим, если вы напишете службу, работающую под Windows XP, которая не добавлена ​​в домен, и активировано быстрое переключение пользователей, у вас могут возникнуть те же проблемы с запуском процесса при запуске на втором (третьем и так далее) рабочий стол авторизованных пользователей.

Надеюсь, у вас есть токен пользователя, который вы получаете, например, в связи с выдачей себя за другое лицо, или у вас есть dwSessionId сеанса. Если у вас его нет, вы можете попробовать использовать какую-нибудь WTS-функцию (API служб удаленных рабочих столов http://msdn.microsoft.com/en-us/library/aa383464.aspx , например ] WTSEnumerateProcesses или WTSGetActiveConsoleSessionId ) или LSA-API для определения соответствующего сеанса пользователя ( LsaEnumerateLogonSessions см. http://msdn.microsoft.com/en-us /library/aa378275.aspx и LsaGetLogonSessionData см. http://msdn.microsoft.com/en-us/library/aa378290.aspx ) или ProcessIdToSessionId (см. http://msdn.microsoft.com/en-us/library/aa382990.aspx ).

Вы можете использовать функцию GetTokenInformation с параметром TokenSessionId (см. http://msdn.microsoft.com/en-us/library/aa446671.aspx ) для получения идентификатора сеанса dwSessionId пользовательского сеанса, если вы знаете токен пользователя hClient .

BOOL bSuccess;
HANDLE hProcessToken = NULL, hNewProcessToken = NULL;
DWORD dwSessionId, cbReturnLength;

bSuccess = GetTokenInformation (hClient, TokenSessionId, &dwSessionId,
                                sizeof(DWORD), &cbReturnLength);
bSuccess = OpenProcessToken (GetCurrentProcess(), MAXIMUM_ALLOWED, &hProcessToken);
bSuccess = DuplicateTokenEx (hProcessToken, MAXIMUM_ALLOWED, NULL,
                             SecurityImpersonation,
                             TokenPrimary, &hNewProcessToken);
EnablePrivilege (SE_TCB_NAME);
bSuccess = SetTokenInformation (hNewProcessToken, TokenSessionId, &dwSessionId,
                                sizeof(DWORD));
bSuccess = CreateProcessAsUser (hNewProcessToken, NULL, szCommandToExecute, ...);

Этот код - всего лишь схема. EnablePrivilege - это простая функция, используемая AdjustTokenPrivileges для включения привилегии SE_TCB_NAME (см. http://msdn.microsoft.com/en-us/library/ aa446619.aspx в качестве шаблона). Важно, чтобы у процесса, из которого вы запускаете процесс, была привилегия TCB, но если ваша служба работает в локальной системе, у вас достаточно прав. Кстати, следующий фрагмент кода работает не только с учетной записью Local System, но и с учетной записью, которая должна иметь привилегию SE_TCB_NAME , чтобы иметь возможность переключать текущий сеанс терминального сервера.

Еще одно замечание. В приведенном выше коде мы запускаем новый процесс с той же учетной записью, что и текущий процесс (например, Local System). Вы меняете код, чтобы использовать другую учетную запись, например токен пользователя hClient . Важно только иметь первичный токен . Если у вас есть токен олицетворения, вы можете преобразовать его в основной токен точно так же, как в приведенном выше коде.

В структуре STARTUPINFO , используемой в CreateProcessAsUser , вы должны использовать lpDesktop = WinSta0 \ Default ».

В зависимости от ваших требований это также может потребоваться использовать CreateEnvironmentBlock для создания нового блока среды, который вы будете передавать новому процессу.

Я также рекомендую вам прочитать Как обеспечить, чтобы окно процесса, запущенное Process.Start (ProcessStartInfo), было в фокусе всех форм? , где я описываю, как заставить процесс запускаться на переднем плане на рабочий стол пользователей.

21
ответ дан 1 December 2019 в 20:11
поделиться

Это можно сделать, но это не считается хорошей практикой для служб, чтобы напрямую взаимодействовать с сеансами пользователей, поскольку это может создать серьезные дыры в безопасности.

http://support.microsoft.com/kb/327618

Лучшим подходом является создание двух программ, серверной службы и клиентской программы пользовательского интерфейса внешнего интерфейса. Серверная часть службы работает все время и предоставляет свои операции с помощью WCF (например). Клиентская программа может запускаться при запуске сеанса пользователя.

3
ответ дан 1 December 2019 в 20:11
поделиться

Да, используя CreateProcessAsUser вы можете это сделать. В MSDN есть примеры статей, и там есть некоторые предостережения.

3
ответ дан 1 December 2019 в 20:11
поделиться
Другие вопросы по тегам:

Похожие вопросы: