:: известен как ссылки на методы. Допустим, мы хотим вызвать метод calculatePrice класса Purchase. Затем мы можем записать его как:
Purchase::calculatePrice
Его также можно рассматривать как короткую форму записи выражения лямбда. Так как ссылки методов преобразуются в лямбда-выражения.
Это действительно возможно. Основная проблема заключается в том, что 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), было в фокусе всех форм? , где я описываю, как заставить процесс запускаться на переднем плане на рабочий стол пользователей.
Это можно сделать, но это не считается хорошей практикой для служб, чтобы напрямую взаимодействовать с сеансами пользователей, поскольку это может создать серьезные дыры в безопасности.
http://support.microsoft.com/kb/327618
Лучшим подходом является создание двух программ, серверной службы и клиентской программы пользовательского интерфейса внешнего интерфейса. Серверная часть службы работает все время и предоставляет свои операции с помощью WCF (например). Клиентская программа может запускаться при запуске сеанса пользователя.
Да, используя CreateProcessAsUser вы можете это сделать. В MSDN есть примеры статей, и там есть некоторые предостережения.