N>Я не работал с Wix, но в целом ситуаця видится так — выше в ветке был приведен очень полезный пример кода на VBS, который получает собственно процессы-сервисы системы. N>Нужно код оформить в виде Custom Action. N>В CA делаете так: првоеряете наличие нужного сервиса. Если есть, то objService.StopService. А далее должно пройти хорошо, по вашим словам.
Работа с сервисами через WMI, насколько я понимаю, далеко не лучшее решение просто потому что WMI должно быть сперва установлено и сконфигурировано отдельно, поправьте, если я ошибаюсь.
Для остановки/запуска сервиса вполне достаточно следующих функций:
DWORD stopService(LPCTSTR lpszServiceName)
{
DWORD dwRet = ERROR_SUCCESS;
SC_HANDLE hSCM;
SC_HANDLE schSpooler;
SERVICE_STATUS_PROCESS ssStatus;
SERVICE_STATUS ss;
DWORD dwBytesNeeded;
DWORD dwStartTime = GetTickCount();
DWORD dwTimeout = 10000; // was 30000
DWORD dwWaitTime;
__try
{
if ( !(hSCM = OpenSCManager( NULL, NULL, SC_MANAGER_CONNECT )) )
{
OUTPUT_SYSTEM_ERROR()
dwRet = GetLastError();
__leave;
}
schSpooler = OpenService(hSCM,lpszServiceName,SERVICE_ALL_ACCESS /*SERVICE_STOP | SERVICE_QUERY_STATUS*/);
if(schSpooler == NULL)
{
OUTPUT_SYSTEM_ERROR()
dwRet = SPOOLER_NO_SERVICE;
__leave;
}
if(!QueryServiceStatusEx(schSpooler
,SC_STATUS_PROCESS_INFO
,(LPBYTE) &ssStatus
,sizeof(SERVICE_STATUS_PROCESS)
,&dwBytesNeeded))
{
OUTPUT_SYSTEM_ERROR()
dwRet = SPOOLER_NO_SERVICE;
__leave;
}
if ( ssStatus.dwCurrentState == SERVICE_STOPPED )
{
dwRet = SPOOLER_SUCCESS;
__leave;
}
if( !ControlService( schSpooler, SERVICE_CONTROL_STOP, &ss ) )
{
OUTPUT_SYSTEM_ERROR()
dwRet = GetLastError();
__leave;
}
ssStatus.dwCurrentState = ss.dwCurrentState;
ssStatus.dwWaitHint = ss.dwWaitHint;
while ( ssStatus.dwCurrentState != SERVICE_STOPPED )
{
// Do not wait longer than the wait hint. A good interval is
// one tenth the wait hint, but no less than 1 second and no
// more than 10 seconds.
dwWaitTime = ssStatus.dwWaitHint / 10;
if( dwWaitTime < 1000 )
dwWaitTime = 1000;
else if ( dwWaitTime > 10000 )
dwWaitTime = 10000;
Sleep( dwWaitTime );
if ( !QueryServiceStatusEx(
schSpooler,
SC_STATUS_PROCESS_INFO,
(LPBYTE)&ssStatus,
sizeof(SERVICE_STATUS_PROCESS),
&dwBytesNeeded ) )
{
dwRet = GetLastError();
__leave;
}
if ( ssStatus.dwCurrentState == SERVICE_STOPPED )
break;
if ( GetTickCount() - dwStartTime > dwTimeout )
{
dwRet = SPOOLER_ERROR_TIMEOUT;
__leave;
}
}
}
__finally
{
if ( schSpooler )
CloseServiceHandle( schSpooler );
if ( hSCM )
CloseServiceHandle( hSCM );
}
return dwRet;
}
DWORD startService(LPCTSTR lpszServiceName)
{
DWORD dwRet = SPOOLER_SUCCESS;
SC_HANDLE hSCM;
SC_HANDLE schSpooler;
SERVICE_STATUS_PROCESS ssStatus;
DWORD dwWaitTime;
DWORD dwStartTime = GetTickCount();
DWORD dwTimeout = 10000; // was 30000
DWORD dwBytesNeeded;
__try
{
if ( !(hSCM = OpenSCManager( NULL, NULL, SC_MANAGER_CONNECT )) )
{
OUTPUT_SYSTEM_ERROR()
dwRet = GetLastError();
__leave;
}
schSpooler = OpenService(hSCM,lpszServiceName,SERVICE_ALL_ACCESS);
if(schSpooler == NULL)
{
OUTPUT_SYSTEM_ERROR()
dwRet = SPOOLER_NO_SERVICE;
__leave;
}
if (!StartService(schSpooler, 0, NULL) )
{
dwRet = SPOOLER_NO_SERVICE;
__leave;
}
if (!QueryServiceStatusEx(
schSpooler, // handle to service
SC_STATUS_PROCESS_INFO, // info level
(LPBYTE)&ssStatus, // address of structuresizeof(SERVICE_STATUS_PROCESS), // size of structure
&dwBytesNeeded ) ) // if buffer too small
{
dwRet = SPOOLER_NO_SERVICE;
__leave;
}
while (ssStatus.dwCurrentState != SERVICE_RUNNING)
{
// Do not wait longer than the wait hint. A good interval is
// one tenth the wait hint, but no less than 1 second and no
// more than 10 seconds.
dwWaitTime = ssStatus.dwWaitHint / 10;
if( dwWaitTime < 1000 )
dwWaitTime = 1000;
else if ( dwWaitTime > 10000 )
dwWaitTime = 10000;
Sleep( dwWaitTime );
// Check the status again. if (!QueryServiceStatusEx(
schSpooler, // handle to service
SC_STATUS_PROCESS_INFO, // info level
(LPBYTE)&ssStatus, // address of structuresizeof(SERVICE_STATUS_PROCESS), // size of structure
&dwBytesNeeded ) ) // if buffer too small
{
dwRet = SPOOLER_NO_SERVICE;
__leave;
}
if(ssStatus.dwCurrentState == SERVICE_STOPPED || ssStatus.dwCurrentState == SERVICE_STOP_PENDING)
if (!StartService(schSpooler, 0, NULL) )
{
dwRet = SPOOLER_NO_SERVICE;
__leave;
}
if ( GetTickCount() - dwStartTime > dwTimeout )
{
// No progress made within the wait hintbreak;
}
}
if (ssStatus.dwCurrentState == SERVICE_RUNNING)
dwRet = SPOOLER_SUCCESS;
else
dwRet = SPOOLER_NOT_STARTED;
}
__finally
{
if(schSpooler)
CloseServiceHandle(schSpooler);
if(hSCM)
CloseServiceHandle(hSCM);
}
return dwRet;
}
BOOL checkServiceRunning(LPCTSTR lpszServiceName)
{
return getServiceStatus(lpszServiceName) == SERVICE_RUNNING;
}
DWORD getServiceStatus(LPCTSTR lpszServiceName)
{
DWORD dwRet = 0;
SC_HANDLE hSCM;
SC_HANDLE schService;
SERVICE_STATUS_PROCESS ssStatus;
DWORD dwBytesNeeded;
__try
{
if ( !(hSCM = OpenSCManager( NULL, NULL, SC_MANAGER_CONNECT )) )
{
__leave;
}
schService = OpenService(hSCM,lpszServiceName,SERVICE_QUERY_STATUS);
if(schService == NULL)
{
__leave;
}
if(!QueryServiceStatusEx(schService
,SC_STATUS_PROCESS_INFO
,(LPBYTE) &ssStatus
,sizeof(SERVICE_STATUS_PROCESS)
,&dwBytesNeeded))
{
__leave;
}
dwRet = ssStatus.dwCurrentState;
}
__finally
{
if ( schService )
CloseServiceHandle( schService );
if ( hSCM )
CloseServiceHandle( hSCM );
}
return dwRet;
}
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re: А как заставить MSI перезапускать сервис уже имеющийся н
Здравствуйте, Rothmans, Вы писали:
R>Я хочу чтобы в коне инсталляции а также деинсталляции моего MSI пакета определенный стандартный сервис, уже установленный на машине, перезапускался. R>Копаю по направлению таблицы ServiceControl и действий StartServices StopServices, но эти действия выполняются не рядом, а сначала StopServices потом мои custom actions, потом StartServices. Мне надо чтобы они обе выполнялись парой в конце InstallExecuteSequence (чтобы получался restart). Допустим, я могу с помощью Orca поменять порядок их вызова, а нельзя ли этот порядок задать в WiX?
Поскольку ServiceControl не имеет параметров для задания порядка запуска (обычно это параметры Sequence либо Before/After), то придется тебе это делать руками. Но делается это довольно легко — через WMI. Пример — запуск сервиса "aspnet_state" на VBS:
Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")
Set colServiceList = objWMIService.ExecQuery("Select * from Win32_Service where Name = 'aspnet_state'")
For Each objService in colServiceList
objService.StartService
Next
Re: А как заставить MSI перезапускать сервис уже имеющийся н
> Привет, > > Я хочу чтобы в коне инсталляции а также деинсталляции моего MSI пакета > определенный стандартный сервис, уже установленный на машине, > перезапускался. > Копаю по направлению таблицы ServiceControl и действий StartServices > StopServices, но эти действия выполняются не рядом, а сначала StopServices > потом мои custom actions, потом StartServices. Мне надо чтобы они обе > выполнялись парой в конце InstallExecuteSequence (чтобы получался > restart). Допустим, я могу с помощью Orca поменять порядок их вызова, а > нельзя ли этот порядок задать в WiX? > > Спасибо.
Еще такой вариант (не пробовал но в ближайшее время буду собирать такой
пакет)
— добавить батник с
Здравствуйте, nesesser, Вы писали:
N>Тогда у меня вопрос — как стоило сделать?
Да нет, все пожалуй что правильно (туплю!).
Стоит только отметить, что самый надежный способ сделать CA — не связываться с батниками и VBS, а написать все свои CA в виде одной DLL на чистом C/C++. В данном случае — вместо net start/stop вызывать Win32-функции (не вспомню, какие).
Правда, я сам тут виновен — свои CA пишу пока только на VBS, поскольку так быстрее. Когда будет загрузка чуть поменьше — думаю перевести их все скопом на C/C++.
Здравствуйте, nzeemin, Вы писали:
N>Да нет, все пожалуй что правильно (туплю!). N>Стоит только отметить, что самый надежный способ сделать CA — не связываться с батниками и VBS, а написать все свои CA в виде одной DLL на чистом C/C++. В данном случае — вместо net start/stop вызывать Win32-функции (не вспомню, какие).
Здравствуйте, Viktor Denk, Вы писали:
VD>Привет всем VD>Простите за глупый вопрос — делаю первую инсталляцию. Мне надо сервис инсталлировать. Все окей, но если сервис уже запущен, то никак не могу его остановить и потом инсталлировать. Код- VD><Much-much code> VD>На новой системе без проблем, инсталлируеся и запускается, Если останавливаю ручками и потом инсталлирую — тоже все хорошо.
VD>Заранее благодарен за любую помощь VD>Виктор
Я не работал с Wix, но в целом ситуаця видится так — выше в ветке был приведен очень полезный пример кода на VBS, который получает собственно процессы-сервисы системы.
Нужно код оформить в виде Custom Action.
В CA делаете так: првоеряете наличие нужного сервиса. Если есть, то objService.StopService. А далее должно пройти хорошо, по вашим словам.
А как заставить MSI перезапускать сервис уже имеющийся на ма
Я хочу чтобы в коне инсталляции а также деинсталляции моего MSI пакета определенный стандартный сервис, уже установленный на машине, перезапускался.
Копаю по направлению таблицы ServiceControl и действий StartServices StopServices, но эти действия выполняются не рядом, а сначала StopServices потом мои custom actions, потом StartServices. Мне надо чтобы они обе выполнялись парой в конце InstallExecuteSequence (чтобы получался restart). Допустим, я могу с помощью Orca поменять порядок их вызова, а нельзя ли этот порядок задать в WiX?
Спасибо.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re: А как заставить MSI перезапускать сервис уже имеющийся н
Здравствуйте, Rothmans, Вы писали:
R>Привет,
R>Я хочу чтобы в коне инсталляции а также деинсталляции моего MSI пакета определенный стандартный сервис, уже установленный на машине, перезапускался. R>Копаю по направлению таблицы ServiceControl и действий StartServices StopServices, но эти действия выполняются не рядом, а сначала StopServices потом мои custom actions, потом StartServices. Мне надо чтобы они обе выполнялись парой в конце InstallExecuteSequence (чтобы получался restart). Допустим, я могу с помощью Orca поменять порядок их вызова, а нельзя ли этот порядок задать в WiX?
R>Спасибо.
Или правильнее делать свое custom action для перезапуска сервиса?
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[2]: А как заставить MSI перезапускать сервис уже имеющийс
N>Поскольку ServiceControl не имеет параметров для задания порядка запуска (обычно это параметры Sequence либо Before/After), то придется тебе это делать руками. Но делается это довольно легко — через WMI. Пример — запуск сервиса "aspnet_state" на VBS:
N>
N>Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")
N>Set colServiceList = objWMIService.ExecQuery("Select * from Win32_Service where Name = 'aspnet_state'")
N>For Each objService in colServiceList
N> objService.StartService
N>Next
N>
Руками в смысле из custom action?
(Из него перезапустить сервис для меня не проблема)
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[3]: А как заставить MSI перезапускать сервис уже имеющийс
Здравствуйте, Rothmans, Вы писали:
N>>Поскольку ServiceControl не имеет параметров для задания порядка запуска (обычно это параметры Sequence либо Before/After), то придется тебе это делать руками. Но делается это довольно легко — через WMI.
R>Руками в смысле из custom action?
Ну да.
А разве есть другие варианты? Сам по себе Windows Installer запускать/останавливать сервиса не умеет — значит в любом случае это будет CA. Просто в случае с WiX речь идет о выборе — использовать имеющиеся в WiX библиотеки CA, либо писать самому.
R>(Из него перезапустить сервис для меня не проблема)
Отлично.
Здравствуйте, OM777, Вы писали:
OM>Еще такой вариант (не пробовал но в ближайшее время буду собирать такой OM>пакет) OM>- добавить батник с OM>net stop servicename OM>net start servicename
Я пробовал. Работает. Только я делал не батник, а CA Type 98.
Здравствуйте, nesesser, Вы писали:
N>Я пробовал. Работает. Только я делал не батник, а CA Type 98.
Что-то вы тут путаете — насколько я вижу по Windows Installer Reference, CA с таким типом не бывает. Может быть, вы имели в виду Type 38 — VBScript text stored in this sequence table?
Здравствуйте, nzeemin, Вы писали:
N>Здравствуйте, nesesser, Вы писали:
N>>Я пробовал. Работает. Только я делал не батник, а CA Type 98.
N>Что-то вы тут путаете — насколько я вижу по Windows Installer Reference, CA с таким типом не бывает. Может быть, вы имели в виду Type 38 — VBScript text stored in this sequence table?
Бывает. Это 98 = 64 + 34, то есть,
64 — Synchronous, ignore exit code
34 — EXE file having a path referencing a directory. (34 = 2 + 32. В данном случае, 2 — CA находится/ссылается на таблицу, 32 — таблица Directory. Эти флажки уже не так однозначно расписываются для всех типов CA, есть исключения)
Успехов!
К этому моменту у меня внутри 0.5, 0.7, 0.33 (с) НС
Здравствуйте, WPooh, Вы писали:
WP>Бывает. Это 98 = 64 + 34, то есть, WP>64 — Synchronous, ignore exit code WP>34 — EXE file having a path referencing a directory. (34 = 2 + 32. В данном случае, 2 — CA находится/ссылается на таблицу, 32 — таблица Directory. Эти флажки уже не так однозначно расписываются для всех типов CA, есть исключения)
Да это-то понятно. Была мысль что это Type 34, но непонятно, зачем человеку запускать "EXE file having a path referencing a directory", если ему нужно сделать "net stop servicename" — это меня и смутило.
Здравствуйте, nzeemin, Вы писали:
N>Да это-то понятно. Была мысль что это Type 34, но непонятно, зачем человеку запускать "EXE file having a path referencing a directory", если ему нужно сделать "net stop servicename" — это меня и смутило.
Потому, что хочется указать, где лежит net.exe (или cmd.exe)
К этому моменту у меня внутри 0.5, 0.7, 0.33 (с) НС
Здравствуйте, nzeemin, Вы писали:
N>Да это-то понятно. Была мысль что это Type 34, но непонятно, зачем человеку запускать "EXE file having a path referencing a directory", если ему нужно сделать "net stop servicename" — это меня и смутило.
Да наверное много чего еще предстоит узнать — я новичок пока что, но у меня большое будущее, я работаю над этим =)
По мне самое очевидное было сделать EXE file having a path referencing a directory и указать этот самый directory как SystemFolder. Разве не очевидно? (я пользуюсь IS 10.5)
Здравствуйте, nzeemin, Вы писали:
N>Здравствуйте, nesesser, Вы писали:
N>>Тогда у меня вопрос — как стоило сделать?
N>Да нет, все пожалуй что правильно (туплю!). N>Стоит только отметить, что самый надежный способ сделать CA — не связываться с батниками и VBS, а написать все свои CA в виде одной DLL на чистом C/C++. В данном случае — вместо net start/stop вызывать Win32-функции (не вспомню, какие).
OpenService, QueryService, ControlService, все довольно просто, только с ожиданием завершения сервиса таймауты надо аккуратно подобрать.
N>Правда, я сам тут виновен — свои CA пишу пока только на VBS, поскольку так быстрее. Когда будет загрузка чуть поменьше — думаю перевести их все скопом на C/C++.
А можно вопрос: я не понял про батники. Куда писать текст батника в обсуждаемом примере? В поле Data таблицы Binary ?
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re: А как заставить MSI перезапускать сервис уже имеющийся н
Здравствуйте, Rothmans, Вы писали:
R>Привет,
R>Я хочу чтобы в коне инсталляции а также деинсталляции моего MSI пакета определенный стандартный сервис, уже установленный на машине, перезапускался. R>Копаю по направлению таблицы ServiceControl и действий StartServices StopServices, но эти действия выполняются не рядом, а сначала StopServices потом мои custom actions, потом StartServices. Мне надо чтобы они обе выполнялись парой в конце InstallExecuteSequence (чтобы получался restart). Допустим, я могу с помощью Orca поменять порядок их вызова, а нельзя ли этот порядок задать в WiX?
R>Спасибо.
Привет всем
Простите за глупый вопрос — делаю первую инсталляцию. Мне надо сервис инсталлировать. Все окей, но если сервис уже запущен, то никак не могу его остановить и потом инсталлировать. Код-
<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2003/01/wi">
<Product Id="73A6F27E-90B6-4A35-A4B9-AE7E2415E049" Language="1033" Manufacturer="Firma" Name="TService" Version="1.0.2.2">
<Package Id="65D5A2C9-5C75-4092-9B1A-B64C4570B3F1" Compressed="yes" Manufacturer="Firma" Keywords="Installer" InstallerVersion="101" />
<UI />
<Media Id="1" Cabinet="TService.cab" EmbedCab="yes" DiskPrompt="CD-ROM #1" />
<Property Id="DiskPrompt" Value="Firma TService" />
<Feature Id="Complete" Level="1">
<ComponentRef Id="TServiceExecutable" />
<ComponentRef Id="TServiceHelpIni" />
</Feature>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="WindowsFolder" Name="WSysPath">
<Component Id="TServiceHelpIni" Guid="9A5781E7-54BB-41AE-8529-DAEE721719B6">
<ServiceControl Id="TServiceStop" Name="TService" Stop="install" Remove="install" />
</Component>
<Directory Id="System32" Name="System32">
<Component Id="TServiceExecutable" Guid="D8375B5E-3CDC-4AA1-8B4B-65B24541F696">
<File Id="TService.exe" LongName="TService.exe" Name="TService.EXE" Source="TService.exe" DiskId="1" />
<ServiceInstall Id="TServiceI" Name="TService" Type="ownProcess" Start="auto" ErrorControl="normal" DisplayName="TService" />
<ServiceControl Id="TServiceStart" Name="TService" Start="install" Stop="uninstall" Remove="uninstall" />
</Component>
</Directory>
</Directory>
</Directory>
<Icon Id="Icon" SourceFile="Firma.ico" />
<Condition Message="You need to be an administrator to install this product!">Privileged</Condition>
<Condition Message="This application only runs on Windows 2000 and later.">VersionNT > 400</Condition>
</Product>
</Wix>
На новой системе без проблем, инсталлируеся и запускается, Если останавливаю ручками и потом инсталлирую — тоже все хорошо.
Заранее благодарен за любую помощь
Виктор
Re[2]: А как заставить MSI перезапускать сервис уже имеющийс
Здравствуйте, Viktor Denk, Вы писали:
VD>Привет всем VD>Простите за глупый вопрос — делаю первую инсталляцию. Мне надо сервис инсталлировать. Все окей, но если сервис уже запущен, то никак не могу его остановить и потом инсталлировать. Код-
VD>На новой системе без проблем, инсталлируеся и запускается, Если останавливаю ручками и потом инсталлирую — тоже все хорошо.
У Вас тут странно, что один и тот же сервис одновременно и убирается и устанавливается, тут как бы не перепутать порядок этих действий, что на этот счет показывает Orca в таблице ServiceControl?
Вообще, по-моему, деинсталировать предыдущую версию и инсталировать новую надо не за один раз. Например можно требовать, чтобы пользователь сперва удалил предыдущую версию, а потом установил новую, или же копать каким-то образом в режим установки "апгрейд существующей версии", который по идее должен отличаться от режима "первой инсталляции".
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[4]: А как заставить MSI перезапускать сервис уже имеющийс
Здравствуйте, Rothmans, Вы писали:
R>В коде следует подправить коды возврата и названия переменных (у меня когда-то давно это под спулер написано было). R>Все быстрее будет, чем использовать WMI через COM.
Тут скорее не о скорости речь идет, а о надежности. Надежнее — да. И это самое существенное. Спасибо, буду знать как сделать по-нормальному =)