В следующем примере, программа конфигурации службы использует функции ChangeServiceConfig и ChangeServiceConfig2, чтобы изменить параметры конфигурации установленной службы. Программа сначала делает попытку блокировать базу данных, воспрепятствовать Диспетчеру управления службами (SCM) запустить службу, в то время когда она переконфигурируется. Если она успешно блокирует базу данных, программа открывает дескриптор объекта службы, модифицирует его конфигурацию, открывает базу данных, а затем закрывает дескриптор объекта службы. Если программе не удается заблокировать базу данных, она использует функцию QueryServiceLockStatus, чтобы извлечь информацию о блокировке.
#include <windows.h>
#include <stdio.h>
BOOL ReconfigureSampleService(BOOL fDisable, LPSTR lpDesc)
{
SC_LOCK sclLock;
LPQUERY_SERVICE_LOCK_STATUS lpqslsBuf;
SERVICE_DESCRIPTION sdBuf;
DWORD dwBytesNeeded, dwStartType;
BOOL bSuccess=TRUE;
// Нужно собрать данные о блокировке базы данных перед реконфигурированием.
sclLock = LockServiceDatabase(schSCManager);
// Если база данных не может быть блокирована, то подробный отчет.
if (sclLock == NULL)
{
// Выход, если база данных не блокируется другими процессами.
if (GetLastError() != ERROR_SERVICE_DATABASE_LOCKED)
{
printf("LockServiceDatabase failed (%d)\n", GetLastError());
return FALSE;
}
// Назначаем буфер для получения деталей о блокировке.
lpqslsBuf = (LPQUERY_SERVICE_LOCK_STATUS) LocalAlloc(
LPTR, sizeof(QUERY_SERVICE_LOCK_STATUS)+256);
if (lpqslsBuf == NULL)
{
printf("LocalAlloc failed (%d)\n", GetLastError());
return FALSE;
}
// Получаем и печатаем информацию о состоянии блокировки.
if (!QueryServiceLockStatus(
schSCManager,
lpqslsBuf,
sizeof(QUERY_SERVICE_LOCK_STATUS)+256,
&dwBytesNeeded) )
{
printf("QueryServiceLockStatus failed (%d)", GetLastError());
return FALSE;
}
if (lpqslsBuf->fIsLocked)
printf("Locked by: %s, duration: %d seconds\n",
lpqslsBuf->lpLockOwner,
lpqslsBuf->dwLockDuration);
else
printf("No longer locked\n");
LocalFree(lpqslsBuf);
}
// База данных блокирована, таким образом, что она сохранит сделанные изменения.
// Откроем дескриптор службы.
schService = OpenService(
schSCManager, // база данных SCManager
"Sample_Srv", // имя службы
SERVICE_CHANGE_CONFIG); // требуемый уровень доступа - CHANGE
if (schService == NULL)
{
printf("OpenService failed (%d)\n", GetLastError());
return FALSE;
}
dwStartType = (fDisable) ? SERVICE_DISABLED :
SERVICE_DEMAND_START;
// Делаем изменения.
if (! ChangeServiceConfig(
schService, // дескриптор службы
SERVICE_NO_CHANGE, // тип службы: не изменяется
dwStartType, // тип запущенной службы, который изменяется
SERVICE_NO_CHANGE, // контроль за ошибками: не изменяется
NULL, // путь к двоичному коду: не изменяется
NULL, // загрузка очередности групп: не изменяется
NULL, // ID признака: не изменяется
NULL, // зависимость от других служб: не изменяется
NULL, // имя учетной записи: не изменяется
NULL, // пароль: не изменяется
NULL) ) // показываемое имя: не изменяется
{
printf("ChangeServiceConfig failed (%d)\n", GetLastError());
bSuccess = FALSE;
}
else
printf("ChangeServiceConfig succeeded.\n");
sdBuf.lpDescription = lpDesc;
if( !ChangeServiceConfig2(
schService, // дескриптор службы
SERVICE_CONFIG_DESCRIPTION, // изменение: описание
&sdBuf) ) // значение: новое описание
{
printf("ChangeServiceConfig2 failed\n");
bSuccess = FALSE;
}
else
printf("ChangeServiceConfig2 succeeded\n");
// Отменим блокировку базы данных.
UnlockServiceDatabase(sclLock);
// Закроем дескриптор службы.
CloseServiceHandle(schService);
return bSuccess;
} |