The Complete Service Sample
The topics in this section form a complete service sample:
- Sample.mc (contains error messages)
- Svc.cpp (contains the service code)
- SvcConfig.cpp (contains service configuration code)
- SvcControl.cpp (contains service control code)
Building the Service
The following procedure describes how to build the service and register the event message DLL.
To build the service and register the event message DLL
Build the message DLL from Sample.mc using the following steps:
- mc -U sample.mc
- rc -r sample.rc
- link -dll -noentry -out:sample.dll sample.res
Build Svc.exe, SvcConfig.exe, and SvcControl.exe from Svc.cpp, SvcConfig.cpp, and SvcControl.cpp, respectively.
Create the registry key HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\EventLog\Application\SvcName and add the following registry values to this key.
Value | Type | Description |
---|---|---|
EventMessageFile = dll_path | REG_SZ | The path to the resource-only DLL that contains strings that the service can write to the event log. |
TypesSupported = 0x00000007 | REG_DWORD | A bit mask that specifies the supported event types. The value 0x000000007 indicates that all types are supported. |
Testing the Service
The following procedure describes how to test the service.
To test the service
In Control Panel, start the Services application. (In the following steps, use the F5 key to refresh the display after executing a command that modifies the information in the Services application.)
Run the following command to install the service:
svc install
The service writes «Service installed successfully» to the console if the operation succeeds or an error message otherwise.
If the service installation succeeds, the service is displayed in the Services application. Note that Name is set to «SvcName», Description and Status are blank, and Startup Type is set to «Manual».
Run the following command to start the service:
svccontrol start SvcName
If the operation succeeds, the service control program writes «Service start pending. » and then «Service started successfully» to the console. Otherwise, the program writes an error message to the console.
If the service starts successfully, Status is set to «Started». The code in the ServiceMain function is executed by the SCM. If an error occurs, the service will write an error message to the event log. This message includes the name of the function that failed and the error code that was returned on failure.
Run the following command to update the service description:
svcconfig describe SvcName
The service configuration program writes «Service description updated successfully» to the console if the operation succeeds or an error message otherwise.
If the update succeeds, Description is set to «This is a test description».
Run the following command to query the service configuration:
svcconfig query SvcName
The service configuration program writes the service configuration information to the console if the operation succeeds or an error message otherwise.
Run the following command to change the service DACL:
svccontrol dacl SvcName
The service configuration program writes «Service DACL updated successfully» to the console if the operation succeeds or an error message otherwise.
Run the following command to disable the service:
svcconfig disable SvcName
The service configuration program writes «Service disabled successfully» to the console if the operation succeeds or an error message otherwise.
If the service is disabled successfully, Startup Type is set to «Disabled».
Run the following command to enable the service:
svcconfig enable SvcName
The service configuration program writes «Service enabled successfully» to the console if the operation succeeds or an error message otherwise.
If the service is enabled successfully, Startup Type is set to «Manual».
Run the following command to stop the service:
svccontrol stop SvcName
If the operation succeeds, the service control program writes «Service stop pending. » and then «Service stopped successfully» to the console. Otherwise, the program writes an error message to the console.
If the service stops successfully, Status is blank.
If the service fails to stop, the service control program writes an error message to the event log that includes the name of the function that failed and the error code that was returned on failure.
Run the following command to delete the service:
svcconfig delete SvcName
The service configuration program writes «Service deleted successfully» to the console if the operation succeeds or an error message otherwise.
If the service is deleted successfully, it is no longer displayed in the Services application. (Note that if you attempt to delete a service that is not stopped, the operation succeeds but Startup Type is set to «Disabled» and the service entry will be deleted at system restart or when the service is terminated using Task Manager.)
Служба Windows на C#: ещё один пример
Всем доброго времени суток. На связи Алексей Гулынин. В данной статье я бы хотел привести ещё один пример службы Windows на C#. Ранее мы уже писали службу Windows, но это была WCF-служба, т.е. мы ей отправляли запросы и получали ответы. Сейчас же я бы хотел реализовать следующий пример:
Наша служба будет отслеживать количество запусков калькулятора (процесс calc.exe ). Результат будет записываться в текстовый файл. Сразу приведу код:
Метод CheckIDsCalcProcess() , который выполняется раз в 15 секунд, делает следующее:
Он сравнивает содержимое списка oldProcsID со всеми текущими процессами. Если в списке есть id процесса, которого нет во всех процессах, то данный id удаляется из списка.
Далее нам необходимо корректно установить службу. Приведу содержимое двух бат-файлов для установки и удаления службы. После выполнения данных команд необходимо зайти в службы Windows и запустить нашу службу.
Мы видим, что служба успешно запустилась:
Давайте теперь протестируем работу службы. Запустите несколько процессов калькулятора. После этого у нас на диске C создастся файл calc.txt :
Мы видим, что всё работает.
У нашей службы есть один недостаток, который сразу бросается в глаза. Каждый раз при загрузке компьютера, служба будет заново стартовать, при этом переменная count будет равна 0. Чтобы этого избежать значение переменной count можно записывать в текстовый файл или базу данных, и при старте службы переменной count присваивать это значение.
В данной статье мы реализовали ещё один пример службы Windows на C#.
На связи был Алексей Гулынин, оставляйте свои комментарии, увидимся в следующих статьях.
Служба Windows (Windows Service) создание С++
Перейду сразу к делу и постараюсь описать задачу. Необходимо создать Службу Windows (Windows Service).
Ранее передо мной стояла такая задача. Для ее реализации целиком и полностью использовал средства языка C#.
Т.е. создал службу, создал библиотеку, которую и запускала и останавливала эта служба, все там работало хорошо.
Что же теперь, задача на C++ (знаком с ним хуже, чем с C#). Необходимо создать службу, которая точно также будет крутиться на Windows, но библиотека, которую и запускает и останавливает эта должна быть написана на С++.
Ход мыслей таков, что необходим создать проект «Служба Windows» на C#. Далее создать проект Visual C++ -> CLR -> Библиотека классов, в ней собственно реализовать все что нужно, добавить dll, как ссылку в проекте C#.
Что можете подсказать по данной задаче?
Использую Visual Studio 2012. Нашел что в ней можно создать еще некий проект ATL, при создании проекта можно выбрать тип приложения «Служба.exe» — может это то, что мне нужно на самом деле, если так подскажите пример или уроки создания подобного приложения.
Socket и windows service (служба)
Пишу IPC(межпроцессорное воздействие) между служебным приложением и Windows forms (дальше WF).
Что такое служба ? Windows Service
Рассматриваю вариант решение поставленной задачи написанием своей службы. Собственно, доки.
Создание Windows Service
Добрый день! Пытаюсь разобраться как писать вин сервисы, что это за зверь такой и зачем он вообще.
Создание Windows Service
Добрый день, пытаюсь разработать обычный виндусовский сервис, вот мой код: #include .
Добрый день. Открыл пример создания сервиса. Но на 7й винде выдёт ошибку. У меня студия 2012. Если запускаю через неё — то выдаёт Первый этап обработки исключения по адресу 0x759EC41F (KernelBase.dll) в ConsoleApplication1.exe: 0x00000005: Отказано в доступе.
Если запускаю экзешник из папки от имени администратора, то GetLastError выдаёт 183 ошибку.
Вот код всего main.cpp
использовал данный пример на Win7 32bit + VS2012. Все работает добротно
Службы выполняются в отдельной, неинтерактивной оконной станции, которая изолирована от
оконной станции пользователя. Поэтому окна, которые пытается отображать служба или
созданные ей процессы, на рабочем столе пользователя не видны. Это во-первых.
Во-вторых, для служб выделена отдельная нулевая сессия. На Windows XP и Windows Server 2003 в
этой же сессии выполняются процессы первого залогиненного пользователя. Начиная с Windows
Vista, нулевая сессия принадлежит исключительно службам, а пользовательские сессии начинаются с
первой (Session 0 Isolation).
В-третьих, запуская notepad.exe из службы, Вы запускаете его с правами службы, а не пользователя.
Со всеми вытекающими последствиями.
Могу ли я запустить процесс из службы с правами пользователя?
P.S. В какой литературе можно поподробнее почитать об этом(на русском)?
Если нужен запуск процесса при входе пользователя в систему, то лучше и проще
автозагрузки для этой задачи решения не существует.
Если процесс нужно запускать в произвольные моменты времени, когда пользователь уже
залогинен, то здесь все усложняется. Нужно из службы вызвать WTSQueryUserToken и с
полученным токеном запустить процесс через CreateProcessAsUser. При этом следует, как
минимум, создать для нового процесса блок переменных окружения — CreateEnvironmentBlock, в
противном случае он унаследует блок переменных системного процесса.
Здесь самая тонкость в том, что для WTSQueryUserToken нужен ID пользовательской сессии, в
которой будет создаваться новый процесс. Существует только один корректный способ
получить этот ID — это подписаться в службе на событие SERVICE_CONTROL_SESSIONCHANGE и
вести учет всех созданных сессий, а также их состояний. Но на этом пути Вас будут поджидать
различные ловушки, так что «малой кровью» обойтись не удастся.
Подробности ищите на RSDN, я по этой теме там отписывался предельно подробно.
Создание своего Windows Service
Я решил провести один эксперимент, суть его пока не могу разглашать, но по результатам обязательно опишу его))) Для этого эксперимента, мне нужно написать приложение которое работает как сервис в Windows.
Думаю описывать как создавать обычный Win32 Console Application проект в Visual Studio нет надобности )))
С чего начинается сервис?
int _tmain( int argc, _TCHAR* argv[]) <
SERVICE_TABLE_ENTRY ServiceTable[1];
ServiceTable[0].lpServiceName = serviceName;
ServiceTable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain;
SERVICE_TABLE_ENTRY это структура, которая описывает точку входа для сервис менеджера, в данном случаи вход будет происходить через ф-цию ServiceMain. Функция StartServiceCtrlDispatcher собственно связывает наш сервис с SCM (Service Control Manager)
Точка входа сервиса
SERVICE_STATUS ServiceStatus;
SERVICE_STATUS_HANDLE hStatus;
void ServiceMain( int argc, char ** argv) <
int error;
int i = 0;
serviceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
serviceStatus.dwCurrentState = SERVICE_START_PENDING;
serviceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
serviceStatus.dwWin32ExitCode = 0;
serviceStatus.dwServiceSpecificExitCode = 0;
serviceStatus.dwCheckPoint = 0;
serviceStatus.dwWaitHint = 0;
serviceStatusHandle = RegisterServiceCtrlHandler(serviceName, (LPHANDLER_FUNCTION)ControlHandler);
if (serviceStatusHandle == (SERVICE_STATUS_HANDLE)0) <
return ;
>
error = InitService();
if (error) <
serviceStatus.dwCurrentState = SERVICE_STOPPED;
serviceStatus.dwWin32ExitCode = -1;
SetServiceStatus(serviceStatusHandle, &serviceStatus);
return ;
>
serviceStatus.dwCurrentState = SERVICE_RUNNING;
SetServiceStatus (serviceStatusHandle, &serviceStatus);
while (serviceStatus.dwCurrentState == SERVICE_RUNNING)
<
char buffer[255];
sprintf_s(buffer, «%u» , i);
int result = addLogMessage(buffer);
if (result) <
serviceStatus.dwCurrentState = SERVICE_STOPPED;
serviceStatus.dwWin32ExitCode = -1;
SetServiceStatus(serviceStatusHandle, &serviceStatus);
return ;
>
i++;
>
void ControlHandler(DWORD request) <
switch (request)
<
case SERVICE_CONTROL_STOP:
addLogMessage( «Stopped.» );
serviceStatus.dwWin32ExitCode = 0;
serviceStatus.dwCurrentState = SERVICE_STOPPED;
SetServiceStatus (serviceStatusHandle, &serviceStatus);
return ;
case SERVICE_CONTROL_SHUTDOWN:
addLogMessage( «Shutdown.» );
serviceStatus.dwWin32ExitCode = 0;
serviceStatus.dwCurrentState = SERVICE_STOPPED;
SetServiceStatus (serviceStatusHandle, &serviceStatus);
return ;
ControlHandler вызывается каждый раз, как SCM шлет запросы на изменения состояния сервиса. В основном ее используют для описания корректной завершении работа сервиса.
Установка сервиса
sc create SampleService binpath= c:\SampleService.exe
if (argc — 1 == 0) <
SERVICE_TABLE_ENTRY ServiceTable[1];
ServiceTable[0].lpServiceName = serviceName;
ServiceTable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain;
if (!StartServiceCtrlDispatcher(ServiceTable)) <
addLogMessage( «Error: StartServiceCtrlDispatcher» );
>
> else if ( wcscmp(argv[argc-1], _T( «install» )) == 0) <
InstallService();
> else if ( wcscmp(argv[argc-1], _T( «remove» )) == 0) <
RemoveService();
> else if ( wcscmp(argv[argc-1], _T( «start» )) == 0 ) <
StartService();
>
>
int InstallService() <
SC_HANDLE hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE);
if (!hSCManager) <
addLogMessage( «Error: Can’t open Service Control Manager» );
return -1;
>
SC_HANDLE hService = CreateService(
hSCManager,
serviceName,
serviceName,
SERVICE_ALL_ACCESS,
SERVICE_WIN32_OWN_PROCESS,
SERVICE_DEMAND_START,
SERVICE_ERROR_NORMAL,
servicePath,
NULL, NULL, NULL, NULL, NULL
);
if (!hService) <
int err = GetLastError();
switch (err) <
case ERROR_ACCESS_DENIED:
addLogMessage( «Error: ERROR_ACCESS_DENIED» );
break ;
case ERROR_CIRCULAR_DEPENDENCY:
addLogMessage( «Error: ERROR_CIRCULAR_DEPENDENCY» );
break ;
case ERROR_DUPLICATE_SERVICE_NAME:
addLogMessage( «Error: ERROR_DUPLICATE_SERVICE_NAME» );
break ;
case ERROR_INVALID_HANDLE:
addLogMessage( «Error: ERROR_INVALID_HANDLE» );
break ;
case ERROR_INVALID_NAME:
addLogMessage( «Error: ERROR_INVALID_NAME» );
break ;
case ERROR_INVALID_PARAMETER:
addLogMessage( «Error: ERROR_INVALID_PARAMETER» );
break ;
case ERROR_INVALID_SERVICE_ACCOUNT:
addLogMessage( «Error: ERROR_INVALID_SERVICE_ACCOUNT» );
break ;
case ERROR_SERVICE_EXISTS:
addLogMessage( «Error: ERROR_SERVICE_EXISTS» );
break ;
default :
addLogMessage( «Error: Undefined» );
>
CloseServiceHandle(hSCManager);
return -1;
>
CloseServiceHandle(hService);
CloseServiceHandle(hSCManager);
addLogMessage( «Success install service!» );
return 0;
>
int RemoveService() <
SC_HANDLE hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (!hSCManager) <
addLogMessage( «Error: Can’t open Service Control Manager» );
return -1;
>
SC_HANDLE hService = OpenService(hSCManager, serviceName, SERVICE_STOP | DELETE);
if (!hService) <
addLogMessage( «Error: Can’t remove service» );
CloseServiceHandle(hSCManager);
return -1;
>
DeleteService(hService);
CloseServiceHandle(hService);
CloseServiceHandle(hSCManager);
addLogMessage( «Success remove service!» );
return 0;
>
int StartService() <
SC_HANDLE hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE);
SC_HANDLE hService = OpenService(hSCManager, serviceName, SERVICE_START);
if (!StartService(hService, 0, NULL)) <
CloseServiceHandle(hSCManager);
addLogMessage( «Error: Can’t start service» );
return -1;
>
CloseServiceHandle(hService);
CloseServiceHandle(hSCManager);
return 0;
>
SampleService.exe install
SampleService.exe remove
SampleService.exe start
Продолжение следует, если все не забракуют 🙂