Создание сервисов для Windows NT
Страница 3.


 

Для открытия сервиса мы используем функцию OpenService(). Третьим параметром этой функции является тип доступа к сервису. Указывая тип доступа SERVICE_START, мы получаем возможность запускать сервис.

Запуск сервиса осуществляется с помощью функции StartService(), которая возвращает нулевое значение, если запустить сервис не удалось.

      //получить информацию о сервисе
      case IDB_CONFIG: {
         hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
         if(!hSCManager) {
            MessageBox(NULL, "Can't open Service Control Manager",
                      "Error", MB_OK | MB_ICONERROR);
                       break;
                 }
         hService = OpenService(hSCManager, SomeServiceName,
                                                   SERVICE_QUERY_CONFIG);
         if(!hService) {
                       GetSomeSvcError();
                       break;
                 }
         lpBufConfig = (LPQUERY_SERVICE_CONFIG)malloc(4096);
         if(lpBufConfig != NULL) {
            //сохраняем конфигурацию в буфере
            QueryServiceConfig(hService, lpBufConfig, 4096,
                               &dwBytesNeeded);
            //отображаем поля конфигурации
                       wsprintf(szBufConfig,
                    "Binary path: %s\nStart Name: %s\nDisplay Name: %s",
                     lpBufConfig->lpBinaryPathName,
                     lpBufConfig->lpServiceStartName,
                     lpBufConfig->lpDisplayName);
            MessageBox(NULL, szBufConfig, szWindowTitle,
                       MB_OK | MB_ICONINFORMATION);
                       free(lpBufConfig);
                 }
         else {
            MessageBox(NULL, "Can't create buffer.\nNot enough memory.",
                       "Error", MB_OK | MB_ICONERROR);
                 }
                 CloseServiceHandle(hService);
                 CloseServiceHandle(hSCManager);
                 break;
           }

На этот раз, открывая сервис, мы указываем тип доступа SERVICE_QUERY_CONFIG, чтобы получить информацию о конфигурации сервиса. Эту информацию мы помещаем в структуру типа QUERY_SERVICE_CONFIG (через указатель на эту структуру lpBufConfig, используя динамически выделяемую память) с помощью функции QueryServiceConfig(). Функция QueryServiceConfig() помещает в структуру типа QUERY_SERVICE_CONFIG информацию о сервисе, которая находится в реестре. Эта информация была помещена в реестр функцией CreateService().

Далее мы помещаем содержимое некоторых полей структуры в буфер szBufConfig и выводим его содержимое с помощью функции MessageBox().

      //остановка сервиса
      case IDB_STOP: {
         hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
         if(!hSCManager) {
            MessageBox(NULL, "Can't open Service Control Manager",
                       "Error", MB_OK | MB_ICONERROR);
                       break;
                 }
         hService = OpenService(hSCManager, SomeServiceName,
                                                               SERVICE_STOP);
         if(!hService) {
                       GetSomeSvcError();
                       break;
                 }
         //останавливаем сервис
         if(!ControlService(hService, SERVICE_CONTROL_STOP, &ss))
            MessageBox(NULL, "Can't stop service", "Error",
                       MB_OK | MB_ICONERROR);
                 CloseServiceHandle(hService);
                 CloseServiceHandle(hSCManager);
                 break;
           }

Здесь мы открываем сервис, используя уровень доступа SERVICE_STOP.

Для остановки сервиса используется функция ControlService(). Эта функция посылает сервису управляющий код, который она получает в качестве второго параметра. В нашем случае управляющий код равен константе SERVICE_CONTROL_STOP. Третьим параметром функции является адрес структуры типа SERVICE_STATUS, в которой содержится информация о текущем статусе сервиса. Содержимое этой структуры использует SCM. Если сервис остановить не удалось функция ControlService() возвращает нулевое значение.

      //удаление сервиса из системы
      case IDB_REMOVE: {
         hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
         if(!hSCManager) {
            MessageBox(NULL, "Can't open Service Control Manager",
                       "Error", MB_OK | MB_ICONERROR);
                       break;
                 }
         hService = OpenService(hSCManager, SomeServiceName,
                                SERVICE_STOP | DELETE);
         if(!hService) {
                       GetSomeSvcError();
                       break;
                 }
         if(ss.dwCurrentState != SERVICE_STOPPED)
            ControlService(hService, SERVICE_CONTROL_STOP, &ss);
         //удаляем сервис из системы
                 DeleteService(hService);
                 CloseServiceHandle(hService);
                 CloseServiceHandle(hSCManager);
                 break;
           }

В этом случае, открывая сервис, мы используем комбинацию флагов SERVICE_STOP и DELETE, поскольку если сервис в данный момент работает, то прежде чем его удалять из системы, его необходимо остановить. Для удаления сервиса из системы используется функция DeleteService().

      //завершаем работу приложения
      case IDB_EXIT: {
                 PostQuitMessage(0);
                 return;
           }
      default: break;
     }
   return FORWARD_WM_COMMAND(hWnd, id, hwndCtl, codeNotify, DefWindowProc);
}

Функции WndProcOnDestroy() и GetSomeSvcError()

Приведем код функции WndProcOnDestroy() и функции GetSomeSvcError(), которая используется для вывода сообщений об ошибках:

void
WndProcOnDestroy(HWND hWnd) {
     PostQuitMessage(0);
}


void GetSomeSvcError() {
   DWORD dwError = GetLastError();
   char errMess[100];
   switch(dwError) {
      case ERROR_ACCESS_DENIED: {
         sprintf(errMess, "The specified service control manager"\
                          "database handle does not have access to"\
                          "the service.");
                 break;
           }
      case ERROR_INVALID_HANDLE: {
         sprintf(errMess, "The specified handle is invalid.");
                 break;
           }
      case ERROR_INVALID_NAME: {
         sprintf(errMess, "The specified service name is invalid.");
                 break;
           }
      case ERROR_SERVICE_DOES_NOT_EXIST: {
         sprintf(errMess, "The specified service does not exist.");
                 break;
           }
      default: {
         sprintf(errMess, "Can't open service.\nError number not found.");
           }
     }
   MessageBox(NULL, errMess, "Error", MB_OK | MB_ICONERROR);
     return;
}

В функции GetSomeSvcError() анализируется код ошибки, полученный с помощью функции Win API GetLastError(). Полный список кодов ошибок и их значений можно посмотреть в файле WinError.h или в документации по Win API.

 
« Предыдущая статья   Следующая статья »