Windows EXE может работать как служба или приложение. Как я могу определить, работает ли он как сервис или нет? - PullRequest
6 голосов
/ 30 сентября 2011

Я ищу вызов Win32 API для возврата контекста времени выполнения моего процесса. Я хочу иметь возможность программно тестировать, выполняю ли я как службу или выполняю как стандартный процесс приложения.

Несколько идей приходят на ум .... Так как у меня всегда есть служба DAD.exe, которая иногда запускает SON.exe в качестве своего потомка и в контексте службы --- а иногда SON.exe запускается не DAD, а пользователь.

SON.EXE будет выполнять API whoami (), чтобы узнать, в каком контексте он работает.

Теперь DAD может создать переменную окружения - и тогда SON сможет проверить этот var - и, если найдет, он знает, что он сын DAD и, следовательно, работает как служба ..... Но это слабо ... .

Другой идеей было бы посмотреть на мой SID или токен и посмотреть, смогу ли я сделать это определение .... Опять же, в лучшем случае это выглядит более сложным по сравнению с одной проверкой API ...

Ответы [ 5 ]

1 голос
/ 30 сентября 2011

I найдено следующее:

bool WinUtil::IsServiceUser(HANDLE hToken, bool *is_service) {
  if (is_service == NULL) {
    return false;
  }

  TOKEN_STATISTICS ts;
  DWORD dwSize = 0;
  // Use token logon LUID instead of user SID, for brevity and safety
  if (!::GetTokenInformation(hToken, TokenStatistics,
                             (LPVOID)&ts, sizeof(ts), &dwSize)) {
    return false;
  }

  // Compare LUID
  const LUID SystemLuid = SYSTEM_LUID;
  const LUID LocalServiceLuid = LOCALSERVICE_LUID;
  const LUID NetworkServiceLuid = NETWORKSERVICE_LUID;
  if (EqualLuid(SystemLuid, ts.AuthenticationId) ||
      EqualLuid(LocalServiceLuid, ts.AuthenticationId) ||
      EqualLuid(NetworkServiceLuid, ts.AuthenticationId)) {
    *is_service = true;
    return true;
  }

  // Not a service account
  *is_service = false;
  return true;
}
bool WinUtil::IsServiceProcess(bool *is_service) {
  if (is_service == NULL) {
    return false;
  }

  if (Util::IsVistaOrLater()) {
    // Session 0 is dedicated to services
    DWORD dwSessionId = 0;
    if (!::ProcessIdToSessionId(::GetCurrentProcessId(), &dwSessionId) ||
        (dwSessionId == 0)) {
      *is_service = true;
      return true;
    }
  }

  // Get process token
  HANDLE hProcessToken = NULL;
  if (!::OpenProcessToken(::GetCurrentProcess(),
                          TOKEN_QUERY | TOKEN_QUERY_SOURCE,
                          &hProcessToken)) {
    return false;
  }

  ScopedHandle process_token(hProcessToken);

  // Process token is one for a service account.
  if (!IsServiceUser(process_token.get(), is_service)) {
    return false;
  }

  return true;
}
1 голос
/ 30 сентября 2011

Читая документацию, я думаю, вы можете определить, участвуете ли вы в интерактивном сеансе или в услуге:

, а затем WSF_VISIBLE должен сообщить вам.

Если вы хотите провести различие между сеансом вошедшего в систему пользователя и сеансом, который неактивен (быстрый пользовательПереключение), я думаю, вы могли бы использовать GetThreadDesktop и GetUserObjectInformation(UOI_IO).


Лучший и самый простой способ узнать изнутри сервиса - установить флаг, когда ServiceMain называется.Но вы тестируете дочерний процесс, поэтому смотрите выше.

1 голос
/ 30 сентября 2011

Другой вариант - использовать библиотеку справки Tool .Используя его, вы делаете снимок всех запущенных в данный момент процессов, а затем можете пройтись по всем процессам, используя функции Process32First и Process32Next .Они возвращают структуру ( PROCESSENTRY32 ), которая выглядит так:

typedef struct tagPROCESSENTRY32 {
  DWORD     dwSize;
  DWORD     cntUsage;
  DWORD     th32ProcessID;
  ULONG_PTR th32DefaultHeapID;
  DWORD     th32ModuleID;
  DWORD     cntThreads;
  DWORD     th32ParentProcessID;
  LONG      pcPriClassBase;
  DWORD     dwFlags;
  TCHAR     szExeFile[MAX_PATH];
} PROCESSENTRY32, *PPROCESSENTRY32;

при прохождении всех процессов, как только вы обнаружите, чей th32ProcessID совпадает с SON.exe (см. GetCurrentProcessId или GetProcessId ).Если th32ParentProcessID этой структуры совпадает с DAD.exe, то вы знаете, что вы были запущены из DAD.exe.

Редактировать: Отвечая на ваш комментарий, я думаю, вы могли бы пойти еще дальшеа затем посмотрите, кто является родителем DAD.exe, если это services.exe, то вы - сервис.

1 голос
/ 30 сентября 2011

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

0 голосов
/ 30 сентября 2011

Я думаю, что вы ищете Topshelf http://topshelf -project.com / , он делает тяжелую работу и облегчает работу в качестве консоли или установку в качестве службы. Отладка приложений хостинга Topshelf в VS2010

...