Страница 3 из 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. |