Запуск процесса службы windows на windows server 2012
Начиная с Windows 7, безопасность служб Windows была усилена. Службы теперь работают изолированно в сеансе 0, поэтому не может быть никакого взаимодействия между пользователем (обычно сеансы 1, 2, 3 и т. д.) со службами Windows. Видеть: эта статья[^]
Я прочитал старую статью, которая все же касается этого нового изменения этот[^] и я пытаюсь выяснить, почему мой, когда я создаю процесс как пользователь, из службы Windows, я не вижу пользовательского интерфейса, когда я запускаю его на Windows Server 2012, в то время как он отлично работает на Windows 10.
В статье говорится::
“In Windows Server 2012, when bringing online the same Cluster Resource, the UI application does not become visible. This happens, because the Cluster Service is also a Windows Service, and the Cluster Resources launched by the Cluster Service are run in Session 0, which does not have user interaction. The workaround is to create a Windows Service that launches the UI application, and make this Windows Service a Cluster Resource. “
Следующая функция, которую я написал, должна быть вызвана службой Windows для запуска дочернего процесса (как пользователя), чтобы дочерний процесс мог взаимодействовать с пользователем, т. е. иметь пользовательский интерфейс. Он отлично работает на рабочем столе Windows, но не работает должным образом на Windows Server 2012. Пользовательский интерфейс не отображается (даже не окно консоли), и горячая клавиша, которую мы регистрируем для удаления службы, тоже не работает.
Может ли кто-нибудь подсказать мне, как сделать этот обходной путь?
Что я уже пробовал:
Видеть мой код здесь[^].
Я следовал руководящим принципам эта статья.[^] Вызовите мой процесс как пользователя из службы Windows, так как Службы Windows изолированы в сессия 0 Таким образом, поскольку службы не могут иметь ни собственного пользовательского интерфейса, ни каких-либо взаимодействий с пользователем, этот дочерний процесс, который является программой Win32, выполняет такое взаимодействие и вызывается службой с помощью:
bRes = CreateProcessAsUserW(hToken, NULL, &commandLine[0], NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS | CREATE_UNICODE_ENVIRONMENT | CREATE_NEW_CONSOLE | CREATE_DEFAULT_ERROR_MODE, pEnv, NULL, &startupInfo, &processInfo);Следующий код:
void WINAPI Run(DWORD dwTargetSessionId, int desktop, LPTSTR lpszCmdLine) { wprintf(_T("Run client start")); if (hPrevAppProcess != NULL) { TerminateProcess(hPrevAppProcess, 0); WaitForSingleObject(hPrevAppProcess, INFINITE); } HANDLE hToken = 0; WTS_SESSION_INFO *si; DWORD cnt = 0; WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, &si, &cnt); for (int i = 0; i < (int)cnt; i++) { if (si[i].SessionId == 0)continue; wprintf(_T("Trying session id %i (%s) user admin token"), si[i].SessionId, si[i].pWinStationName); HANDLE userToken; if (WTSQueryUserToken(si[i].SessionId, &userToken)) { wprintf(_T("WTSQueryUserToken succeced")); TOKEN_LINKED_TOKEN admin; DWORD len; if (GetTokenInformation(userToken, TokenLinkedToken, &admin, sizeof(TOKEN_LINKED_TOKEN), &len)) { wprintf(_T("Success using user admin token")); hToken = admin.LinkedToken; break; } else wprintf(L"GetTokenInformation() failed"); CloseHandle(userToken); } else wprintf(L"WTSQueryUserToken() failed"); } if (hToken == 0) { HANDLE systemToken; OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &systemToken); DuplicateTokenEx(systemToken, TOKEN_ALL_ACCESS, NULL, SecurityImpersonation, TokenPrimary, &hToken); CloseHandle(systemToken); int i; for (i = 0; i < (int)cnt; i++) { if (si[i].SessionId == 0)continue; if (SetTokenInformation(hToken, TokenSessionId, &si[i].SessionId, sizeof(DWORD))) { wprintf(_T("Success using system token with set user session id %i"), si[i].SessionId); break; } } if (i == cnt) wprintf(_T("No success to get user admin token nor system token with set user session id")); } WTSFreeMemory(si); STARTUPINFO startupInfo = {}; startupInfo.cb = sizeof(STARTUPINFO); startupInfo.lpDesktop = _T("winsta0\\default"); LPVOID pEnv = NULL; CreateEnvironmentBlock(&pEnv, hToken, TRUE); PROCESS_INFORMATION processInfo = {}; PROCESS_INFORMATION processInfo32 = {}; TCHAR szCurModule[MAX_PATH] = { 0 }; GetModuleFileName(NULL, szCurModule, MAX_PATH); BOOL bRes = FALSE; std::wstring commandLine; commandLine.reserve(1024); commandLine += L"\""; commandLine += szCurModule; commandLine += L"\" \""; commandLine += SERVICE_COMMAND_LUNCHER; commandLine += L"\""; wprintf(_T("launch SG_WinService with CreateProcessAsUser ... %s"), commandLine.c_str()); bRes = CreateProcessAsUserW(hToken, NULL, &commandLine[0], NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS | CREATE_UNICODE_ENVIRONMENT | CREATE_NEW_CONSOLE | CREATE_DEFAULT_ERROR_MODE, pEnv, NULL, &startupInfo, &processInfo); if (bRes == FALSE) { DWORD dwLastError = ::GetLastError(); TCHAR lpBuffer[256] = _T("?"); if (dwLastError != 0) // Don't want to see a "operation done successfully" error ;-) ::FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, // It´s a system error NULL, // No string to be formatted needed dwLastError, // Hey Windows: Please explain this error! MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Do it in the standard language lpBuffer, // Put the message here 255, // Number of bytes to store the message NULL); (_T("CreateProcessAsUser(SG_WinService) failed - Error : %s (%i)"), lpBuffer, dwLastError); } else { wprintf(_T("CreateProcessAsUser(SG_WinService) success. New process ID: %i"), processInfo.dwProcessId); } }возвращает следующие выходные данные:
Цитата:05.06.2019 04:25 5856: попытка сеанса с идентификатором 1 (консоль) пользователя admin маркер
05.06.2019 04:25 5856: Trying session id 2 (RDP-Tcp#27) user admin token
05.06.2019 04:25 5856: Trying session id 65536 (RDP-Tcp) user admin token
05.06.2019 04:25 5856: успешное использование системного токена с установленным идентификатором сеанса пользователя 1
05.06.2019 04:25 5856: запуск SG_WinService с помощью CreateProcessAsUser ... "C:\myservice\SG_WinService.exe" ServiceIsLuncher"
05.06.2019 04:25 5856: CreateProcessAsUser(SG_WinService) успех. Новый идентификатор процесса: 5580
Поэтому вместо запуска дочернего процесса в сеансе 1 он работает как "система".
johannesnestler
Отлично, но, может быть, не надо делать работу так, как она должна быть. Может быть, еще раз прочтите комментарий Дэйва и выполните то, что он вам сказал, не должно быть так уж сложно… В .NET я использую WCF "AdministrationService", размещенный внутри моего windowsservice для IPC - так что мое настольное приложение может подключаться к службе и наоборот. Я делаю это для всех моих windowsservice по умолчанию, если ничего другого я не могу контролировать WindowsService и "смотреть внутрь".
Michael Haephrati
Это технический вопрос. Это не просьба о консультации. Мы предпочитаем избегать использования .NET в настольных и основных серверных приложениях и использует чистый Win32 API. Ответ Дейва-это не ответ, а скорее комментарий. Я обратился к этому замечанию. Чтобы быть более конкретным, когда вы запускаете любой исполняемый файл на Windows Server 2012 и этот исполняемый файл запускает другой исполняемый файл, никакой пользовательский интерфейс не будет показан. Кроме того, следуя рекомендациям Microsoft, используя CreateProcessAsUser, по какой-то причине единственный найденный токен принадлежит специальному "системному" пользователю, который вызывает эту проблему.
[no name]
Почему он не работает с удаленного рабочего стола?