Как определить, что мое приложение работает как служба или в интерактивном сеансе?
Я пишу приложение, которое может работать как служба или автономно, но я хочу определить, было ли приложение выполнено как служба или обычный сеанс пользователя.
Ответы
Ответ 1
Я думаю, вы можете запросить токен процесса для членства в интерактивной группе.
Из http://support.microsoft.com/kb/243330:
SID: S-1-5-4
Имя: Интерактивный
Описание: группа, включающая всех пользователей, которые вошли в систему в интерактивном режиме. Членство контролируется операционной системой.
Позвоните в GetTokenInformation с помощью TokenGroups, чтобы получить группы, связанные с учетной записью, в которой выполняется этот процесс, а затем итерации по сидерам, которые ищут интерактивный sid.
Я нашел хороший кусок кода в http://marc.info/?l=openssl-dev&m=104401851331452&w=2
Ответ 2
Если это приложение на С++, где-то в вашем стартовом коде вам нужно вызвать StartServiceCtrlDispatcher. Если это не удается, приложение не запускается как служба.
Ответ 3
Другой вариант - использовать System.Environment.UserInteractive
http://msdn.microsoft.com/en-us/library/system.environment.userinteractive.aspx
Обновить. Чтобы компенсировать отправку ответа .NET на тему С++, я предоставляю реализацию C на основе реализации .NET.
BOOL IsUserInteractive()
{
BOOL bIsUserInteractive = TRUE;
HWINSTA hWinStation = GetProcessWindowStation();
if (hWinStation != NULL)
{
USEROBJECTFLAGS uof = {0};
if (GetUserObjectInformation(hWinStation, UOI_FLAGS, &uof, sizeof(USEROBJECTFLAGS), NULL) && ((uof.dwFlags & WSF_VISIBLE) == 0))
{
bIsUserInteractive = FALSE;
}
}
return bIsUserInteractive;
}
Ответ 4
Я думаю, вы можете основывать свое обнаружение на том, что службы работают с SessionID 0, а учетные записи пользователей имеют другие значения (например, 1).
bServiceMode = false;
SessionID=-1;
Size=0;
hToken = NULL;
(!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
GetLastError();
if (!GetTokenInformation(hToken, TokenSessionId, &SessionID, sizeof(SessionID), &Size) || !Size)
return FALSE;
if(SessionID==0)
bServiceMode = true;
Ответ 5
Все вышеперечисленные методы ненадежны. Идентификатор сеанса не обязательно 0 (по крайней мере, не в предыдущих версиях Windows), Window Station только WinSta0, если "Если служба запущена в учетной записи LocalSystem и взаимодействует с рабочим столом".
Подробнее см. KB171890.
Один метод определения того, выполняется ли процесс как служба, следующий:
Обратите внимание: Этот метод обнаружит только службы, установленные в базе данных служб, но не дочерние процессы, запущенные процессом службы, которые не зарегистрированы в базе данных. В этом случае это также не будет системным сервисом. * 1.
bool IsRunningAsService(unsigned int Pid) {
bool Result = false;
SC_HANDLE hScm = OpenSCManager(
0,
SERVICES_ACTIVE_DATABASE,
SC_MANAGER_ENUMERATE_SERVICE
);
if (hScm == 0) {
return Result;
}
DWORD ServicesBufferRequired = 0;
DWORD ResumeHandle = 0;
DWORD ServicesBufferSize = 0;
DWORD ServicesCount = 0;
ENUM_SERVICE_STATUS_PROCESS* ServicesBuffer = 0;
EnumServicesStatusEx(hScm, SC_ENUM_PROCESS_INFO, SERVICE_WIN32,
SERVICE_ACTIVE, 0, 0, &ServicesBufferRequired, &ServicesCount, &ResumeHandle, 0);
// Todo: Error handling (GetLastError() results are currently bogus?)
ServicesBuffer = (ENUM_SERVICE_STATUS_PROCESS*) new
char[ServicesBufferRequired];
ServicesBufferSize = ServicesBufferRequired;
EnumServicesStatusEx(hScm, SC_ENUM_PROCESS_INFO, SERVICE_WIN32,
SERVICE_ACTIVE, (LPBYTE) ServicesBuffer, ServicesBufferSize,
&ServicesBufferRequired, &ServicesCount, &ResumeHandle, 0);
ENUM_SERVICE_STATUS_PROCESS* ServicesBufferPtr = ServicesBuffer;
while (ServicesCount--) {
if (ServicesBufferPtr->ServiceStatusProcess.dwProcessId == Pid) {
Result = true;
break;
}
ServicesBufferPtr++;
}
delete [] ServicesBuffer;
CloseServiceHandle(hScm);
return Result;
}
Обратите внимание, что приведенный выше код должен содержать дополнительную обработку ошибок, особенно он должен вызываться в цикле до тех пор, пока EnumServicesStatusEx не возвращает ненулевое значение. Но, к сожалению, как только я узнал, GetLastError()
всегда возвращает 1 (ERROR_INVALID_FUNCTION), даже если буфер правильно заполнен данными.
* 1: Тестирование, если процесс был запущен службой: в этом случае вы могли бы использовать комбинацию других решений. Можно проверить, если процесс имеет родительский (grandparent...) процесс, который является зарегистрированным в качестве службы. Для этой цели вы можете использовать API CreateToolhelp32Snapshot
. Однако, если родительский процесс уже убит, все становится трудно. Я уверен, что есть недокументированные настройки, которые могут определять, работает ли процесс как служба, кроме обычных подозреваемых, таких как SessionId = 0, WindowStation = 0, WSF_VISIBLE, No Interactive Group Members...
Ответ 6
Существует простой способ определить, запускается ли приложение как служба. Когда вы создаете службу с CreateService, передайте в параметр lpBinaryPathName дополнительный аргумент, скажем -s, который указывает, что ваше приложение запускается как служба. Затем в приложении вы можете проверить этот аргумент. Это также может помочь при отладке, поскольку вы можете протестировать свои функциональные возможности без фактического запуска службы. Если StartServiceCtrlDispatcher выходит из строя с помощью ERROR_FAILED_SERVICE_CONTROLLER_CONNECT, вы можете установить флаг, указывающий, что программа запущена как консольное приложение, имитирующее режим обслуживания, поэтому вы можете пропустить связанные с API вызовы API, используя этот флаг.
Ответ 7
Процесс в обычном пользовательском сеансе всегда имеет оконную станцию с именем WinSta0.
wchar_t buffer[256] = {0};
DWORD length = 0;
GetUserObjectInformation(GetProcessWindowStation(), UOI_NAME, buffer, 256, &length);
if (!lstricmp(buffer, "WinSta0")) {
// normal user session
} else {
// service session
}