Программирование для Windows NT© Александр Фролов, Григорий ФроловТом 27, часть 2, М.: Диалог-МИФИ, 1996, 272 стр. Приложение SRVCTRLВ этом разделе мы приведем исходные тексты простейшего сервиса Simple и приложения SRVCTRL, с помощью которого можно установить данный сервис, запустить, остановить или удалить его, а также определить текущую конфигурацию. Главное меню приложения SRVCTRL и временное меню Service показано на рис. 5.4.
Рис. 5.4. Главное меню приложения SRVCTRL С помощью строки Install вы можете установить сервис. Не забудьте перед этим записать загрузочный файл сервиса в каталог c:\ntbk2\src\service\small\debug, так как приложение SRVCTRL может установить сервис только из этого каталога. После установки имя сервиса появится в списке сервисов, который можно просмотреть при помощи приложения Services из папки Control Panel (рис. 5.5).
Рис. 5.5. В списке сервисов появился новый сервис Sample of simple service Если теперь из меню Service нашего приложения выбрать строку Get configuration, на экране появится диалоговая панель, в которой будут отображены некоторые поля структуры конфигрурации сервиса (рис. 5.6).
Рис. 5.6. Просмотр конфигурации сервиса Исходный текст сервисаИсходный текст сервиса представлен в листинге 5.1. Так как ранее мы уже подробно описывали структуру этого сервиса, то мы оставим вам этот листинг и листинг приложения SRVCTRL на самостоятельное изучение. Листинг 5.1. Файл service/small/small.c
// ==================================================
// Сервис "Sample of simple service"
// Шаблон простейшего сервиса Windows NT
//
// (С) Фролов А.В., 1996
// Email: frolov@glas.apc.org
// ==================================================
#define STRICT
#include <windows.h>
#include <windowsx.h>
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include "small.h"
// -----------------------------------------------------
// Глобальные переменные
// -----------------------------------------------------
// Код ошибки
DWORD dwErrCode;
// Текущее состояние сервиса
SERVICE_STATUS ss;
// Идентификатор сервиса
SERVICE_STATUS_HANDLE ssHandle;
// -----------------------------------------------------
// Функция main
// Точка входа процесса
// -----------------------------------------------------
void main(int agrc, char *argv[])
{
// Таблица точек входа
SERVICE_TABLE_ENTRY DispatcherTable[] =
{
{
// Имя сервиса
MYServiceName,
// Функция main сервиса
(LPSERVICE_MAIN_FUNCTION)ServiceMain
},
{
NULL,
NULL
}
};
printf("Sample of simple service\n"
"(C) A. Frolov, 1996, Email: frolov@glas.apc.org\n");
// Запуск диспетчера
if(!StartServiceCtrlDispatcher(DispatcherTable))
{
fprintf(stdout,
"StartServiceCtrlDispatcher: Error %ld\n",
GetLastError());
getch();
return;
}
}
// -----------------------------------------------------
// Функция ServiceMain
// Точка входа сервиса
// -----------------------------------------------------
void WINAPI ServiceMain(DWORD argc, LPSTR *argv)
{
// Регистрируем управляющую функцию сервиса
ssHandle =
RegisterServiceCtrlHandler(MYServiceName, ServiceControl);
if(!ssHandle)
return;
// Устанавливаем состояние сервиса
// Сервис работает как отдельный процесс
ss.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
// Код ошибки при инициализации и завершения сервиса
// не используется
ss.dwServiceSpecificExitCode = 0;
// Начинаем запуск сервиса.
// Прежде всего устанавливаем состояние ожидания
// запуска сервиса
ReportStatus(SERVICE_START_PENDING, NO_ERROR, 4000);
// Вызываем функцию, которая выполняет все
// необходимые инициализирующие действия
// ServiceStart(argc, argv);
// После завершения инициализации устанавливаем
// состояние работающего сервиса
ReportStatus(SERVICE_RUNNING, NOERROR, 0);
return;
}
// -----------------------------------------------------
// Функция ServiceControl
// Точка входа функции обработки команд
// -----------------------------------------------------
void WINAPI ServiceControl(DWORD dwControlCode)
{
// Анализируем код команды и выполняем эту команду
switch(dwControlCode)
{
// Команда остановки сервиса
case SERVICE_CONTROL_STOP:
{
// Устанавливаем состояние ожидания остановки
ss.dwCurrentState = SERVICE_STOP_PENDING;
ReportStatus(ss.dwCurrentState, NOERROR, 0);
// Выполняем остановку сервиса, вызывая функцию,
// которая выполняет все необходимые для этого действия
// ServiceStop();
// Отмечаем состояние как остановленный сервис
ReportStatus(SERVICE_STOPPED, NOERROR, 0);
break;
}
// Определение текущего состояния сервиса
case SERVICE_CONTROL_INTERROGATE:
{
// Возвращаем текущее состояние сервиса
ReportStatus(ss.dwCurrentState, NOERROR, 0);
break;
}
// В ответ на другие команды просто возвращаем
// текущее состояние сервиса
default:
{
ReportStatus(ss.dwCurrentState, NOERROR, 0);
break;
}
}
}
// -----------------------------------------------------
// Функция ReportStatus
// Посылка состояния сервиса системе управления сервисами
// -----------------------------------------------------
void ReportStatus(DWORD dwCurrentState,
DWORD dwWin32ExitCode, DWORD dwWaitHint)
{
// Счетчик шагов длительных операций
static DWORD dwCheckPoint = 1;
// Если сервис не находится в процессе запуска,
// его можно остановить
if(dwCurrentState == SERVICE_START_PENDING)
ss.dwControlsAccepted = 0;
else
ss.dwControlsAccepted = SERVICE_ACCEPT_STOP;
// Сохраняем состояние, переданное через
// параметры функции
ss.dwCurrentState = dwCurrentState;
ss.dwWin32ExitCode = dwWin32ExitCode;
ss.dwWaitHint = dwWaitHint;
// Если сервис не работает и не остановлен,
// увеличиваем значение счетчика шагов
// длительных операций
if((dwCurrentState == SERVICE_RUNNING) ||
(dwCurrentState == SERVICE_STOPPED))
ss.dwCheckPoint = 0;
else
ss.dwCheckPoint = dwCheckPoint++;
// Вызываем функцию установки состояния
SetServiceStatus(ssHandle, &ss);
}
В файле small.h (листинг 5.2) определено имя сервиса MYServiceName и прототипы функций. Листинг 5.2. Файл service/small/small.h
#define MYServiceName "Sample of simple service"
void WINAPI ServiceMain(DWORD dwArgc, LPSTR *lpszArv);
void WINAPI ServiceControl(DWORD dwControlCode);
void ReportStatus(DWORD dwCurrentState,
DWORD dwWin32ExitCode, DWORD dwWaitHint);
Исходные тексты приложения SRVCTRLГлавный файл исходных текстов приложения SRVCTRL, предназначенного для управления сервисом Sample of simple service приведен в листинге 5.3. Листинг 5.3. Файл service/srvctrl.c
// ==================================================
// Приложение SRVCTRL
// Работа с сервисом "Sample of simple service"
//
// (С) Фролов А.В., 1996
// Email: frolov@glas.apc.org
// ==================================================
#define STRICT
#include <windows.h>
#include <windowsx.h>
#include "resource.h"
#include "afxres.h"
#include "srvctrl.h"
HINSTANCE hInst;
char szAppName[] = "ServiceCtlApp";
char szAppTitle[] = "Simple Service Control";
// Состояние сервиса
SERVICE_STATUS ss;
// -----------------------------------------------------
// Функция WinMain
// -----------------------------------------------------
int APIENTRY
WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wc;
HWND hWnd;
MSG msg;
// Сохраняем идентификатор приложения
hInst = hInstance;
// Преверяем, не было ли это приложение запущено ранее
hWnd = FindWindow(szAppName, NULL);
if(hWnd)
{
// Если было, выдвигаем окно приложения на
// передний план
if(IsIconic(hWnd))
ShowWindow(hWnd, SW_RESTORE);
SetForegroundWindow(hWnd);
return FALSE;
}
// Регистрируем класс окна
memset(&wc, 0, sizeof(wc));
wc.cbSize = sizeof(WNDCLASSEX);
wc.hIconSm = LoadImage(hInst,
MAKEINTRESOURCE(IDI_APPICONSM),
IMAGE_ICON, 16, 16, 0);
wc.style = 0;
wc.lpfnWndProc = (WNDPROC)WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInst;
wc.hIcon = LoadImage(hInst,
MAKEINTRESOURCE(IDI_APPICON),
IMAGE_ICON, 32, 32, 0);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
wc.lpszMenuName = MAKEINTRESOURCE(IDR_APPMENU);
wc.lpszClassName = szAppName;
if(!RegisterClassEx(&wc))
if(!RegisterClass((LPWNDCLASS)&wc.style))
return FALSE;
// Создаем главное окно приложения
hWnd = CreateWindow(szAppName, szAppTitle,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
NULL, NULL, hInst, NULL);
if(!hWnd) return(FALSE);
// Отображаем окно и запускаем цикл
// обработки сообщений
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
// -----------------------------------------------------
// Функция WndProc
// -----------------------------------------------------
LRESULT WINAPI
WndProc(HWND hWnd, UINT msg, WPARAM wParam,
LPARAM lParam)
{
switch(msg)
{
HANDLE_MSG(hWnd, WM_COMMAND, WndProc_OnCommand);
HANDLE_MSG(hWnd, WM_DESTROY, WndProc_OnDestroy);
default:
return(DefWindowProc(hWnd, msg, wParam, lParam));
}
}
// -----------------------------------------------------
// Функция WndProc_OnDestroy
// -----------------------------------------------------
#pragma warning(disable: 4098)
void WndProc_OnDestroy(HWND hWnd)
{
PostQuitMessage(0);
return 0L;
}
// -----------------------------------------------------
// Функция WndProc_OnCommand
// -----------------------------------------------------
#pragma warning(disable: 4098)
void WndProc_OnCommand(HWND hWnd, int id,
HWND hwndCtl, UINT codeNotify)
{
// Идентификатор сервиса
SC_HANDLE schService;
// Идентификатор системы управления сервисами
SC_HANDLE schSCManager;
LPQUERY_SERVICE_CONFIG lpBuf;
DWORD dwBytesNeeded;
char szBuf[1024];
switch (id)
{
case ID_FILE_EXIT:
{
// Завершаем работу приложения
PostQuitMessage(0);
return 0L;
break;
}
// Установка сервиса в систему
case ID_SERVICE_INSTALL:
{
// Открываем систему управления сервисами
schSCManager = OpenSCManager(NULL, NULL,
SC_MANAGER_ALL_ACCESS);
if(!schSCManager)
break;
// Создаем сервис с именем MYServiceName
schService = CreateService(
schSCManager,
MYServiceName,
MYServiceName,
SERVICE_ALL_ACCESS,
SERVICE_WIN32_OWN_PROCESS,
SERVICE_DEMAND_START,
SERVICE_ERROR_NORMAL,
"c:\\ntbk2\\src\\service\\small\\debug\\small.exe",
NULL,
NULL,
"",
NULL,
NULL);
// Закрываем идентификатор системы управления
// сервисами
CloseServiceHandle(schSCManager);
break;
}
// Удаление сервиса из системы
case ID_SERVICE_REMOVE:
{
// Открываем систему управления сервисами
schSCManager = OpenSCManager(NULL, NULL,
SC_MANAGER_ALL_ACCESS);
if(!schSCManager)
break;
// Открываем сервис с именем MYServiceName
schService = OpenService(
schSCManager, MYServiceName,
SERVICE_ALL_ACCESS);
if(!schService)
break;
// Останавливаем сервис
ControlService(schService,
SERVICE_CONTROL_STOP, &ss);
// Вызываем функцию удаления сервиса из системы
DeleteService(schService);
// Закрываем идентификатор системы управления
// сервисами
CloseServiceHandle(schSCManager);
break;
}
case ID_SERVICE_START:
{
// Открываем систему управления сервисами
schSCManager = OpenSCManager(NULL, NULL,
SC_MANAGER_ALL_ACCESS);
if(!schSCManager)
break;
// Открываем сервис с именем MYServiceName
schService = OpenService(
schSCManager, MYServiceName,
SERVICE_ALL_ACCESS);
if(!schService)
break;
// Запускаем сервис
StartService(schService, 0, NULL);
// Закрываем идентификатор системы управления
// сервисами
CloseServiceHandle(schSCManager);
break;
}
case ID_SERVICE_STOP:
{
// Открываем систему управления сервисами
schSCManager = OpenSCManager(NULL, NULL,
SC_MANAGER_ALL_ACCESS);
if(!schSCManager)
break;
// Открываем сервис с именем MYServiceName
schService = OpenService(
schSCManager, MYServiceName,
SERVICE_ALL_ACCESS);
// Останавливаем сервис
ControlService(schService,
SERVICE_CONTROL_STOP, &ss);
// Закрываем идентификатор системы управления
// сервисами
CloseServiceHandle(schSCManager);
break;
}
case ID_SERVICE_GETCONFIGURATION:
{
// Открываем систему управления сервисами
schSCManager = OpenSCManager(NULL, NULL,
SC_MANAGER_ALL_ACCESS);
if(!schSCManager)
break;
// Открываем сервис с именем MYServiceName
schService = OpenService(
schSCManager, MYServiceName,
SERVICE_ALL_ACCESS);
if(!schService)
break;
// Получаем буфер для сохранения конфигурации
lpBuf = (LPQUERY_SERVICE_CONFIG)malloc(4096);
if(lpBuf != NULL)
{
// Сохраняем конфигурацию в буфере
QueryServiceConfig(schService,
lpBuf, 4096, &dwBytesNeeded);
// Отображаем некоторые поля конфигурации
wsprintf(szBuf, "Binary path: %s\n"
"Start Name: %s\n"
"Display Name: %s\n",
lpBuf->lpBinaryPathName,
lpBuf->lpServiceStartName,
lpBuf->lpDisplayName);
MessageBox(hWnd, szBuf, szAppTitle,
MB_OK | MB_ICONINFORMATION);
// Освобождаем буфер
free(lpBuf);
}
// Закрываем идентификатор системы управления
// сервисами
CloseServiceHandle(schSCManager);
break;
}
case ID_HELP_ABOUT:
{
MessageBox(hWnd,
"Simple Service Control\n"
"(C) Alexandr Frolov, 1996\n"
"Email: frolov@glas.apc.org",
szAppTitle, MB_OK | MB_ICONINFORMATION);
return 0L;
break;
}
default:
break;
}
return FORWARD_WM_COMMAND(hWnd, id, hwndCtl, codeNotify,
DefWindowProc);
}
В файле srvctrl.h (листинг 5.4) определено имя сервиса и прототипы функций. Листинг 5.4. Файл service/srvctrl.h
// Имя сервиса
#define MYServiceName "Sample of simple service"
// -----------------------------------------------------
// Описание функций
// -----------------------------------------------------
LRESULT WINAPI
WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
void WndProc_OnCommand(HWND hWnd, int id,
HWND hwndCtl, UINT codeNotify);
void WndProc_OnDestroy(HWND hWnd);
LRESULT WINAPI
DlgProc(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam);
BOOL DlgProc_OnInitDialog(HWND hdlg, HWND hwndFocus,
LPARAM lParam);
void DlgProc_OnCommand(HWND hdlg, int id,
HWND hwndCtl, UINT codeNotify);
Файл resource.h (листинг 5.5) содержит описания констант, которые используются в файле определения ресурсов приложения. Листинг 5.5. Файл service/resource.h
//{{NO_DEPENDENCIES}}
// Microsoft Developer Studio generated include file.
// Used by srvctrl.rc
//
#define IDR_MENU1 101
#define IDR_APPMENU 101
#define IDI_APPICON 102
#define IDI_APPICONSM 103
#define ID_FILE_EXIT 40001
#define ID_HELP_ABOUT 40002
#define ID_SERVICE_INSTALL 40010
#define ID_SERVICE_REMOVE 40011
#define ID_SERVICE_START 40012
#define ID_SERVICE_STOP 40013
#define ID_SERVICE_GETCONFIGURATION 40014
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 105
#define _APS_NEXT_COMMAND_VALUE 40015
#define _APS_NEXT_CONTROL_VALUE 1006
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif
Файл определения ресурсов приложения приведен в листинге 5.6. Листинг 5.6. Файл service/srvctrl.rc
//Microsoft Developer Studio generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
//////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "afxres.h"
//////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
//////////////////////////////////////////////////////////////
// Russian resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_RUS)
#ifdef _WIN32
LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT
#pragma code_page(1251)
#endif //_WIN32
//////////////////////////////////////////////////////////////
//
// Menu
//
IDR_APPMENU MENU DISCARDABLE
BEGIN
POPUP "&File"
BEGIN
MENUITEM "E&xit", ID_FILE_EXIT
END
POPUP "&Service"
BEGIN
MENUITEM "&Install", ID_SERVICE_INSTALL
MENUITEM "&Remove", ID_SERVICE_REMOVE
MENUITEM SEPARATOR
MENUITEM "&Start", ID_SERVICE_START
MENUITEM "Sto&p", ID_SERVICE_STOP
MENUITEM SEPARATOR
MENUITEM "&Get configuration",
ID_SERVICE_GETCONFIGURATION
END
POPUP "&Help"
BEGIN
MENUITEM "&About...", ID_HELP_ABOUT
END
END
#ifdef APSTUDIO_INVOKED
//////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE DISCARDABLE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE DISCARDABLE
BEGIN
"#include ""afxres.h""\r\n"
"\0"
END
3 TEXTINCLUDE DISCARDABLE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
//////////////////////////////////////////////////////////////
//
// Icon
//
// Icon with lowest ID value placed first to ensure
// application icon
// remains consistent on all systems.
IDI_APPICON ICON DISCARDABLE "srvctrl.ico"
IDI_APPICONSM ICON DISCARDABLE "srvctrsm.ico"
#endif // Russian resources
//////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
//////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
//////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED
|




