PDA

View Full Version : ServiceAddService returns -1



Kovalenko
07-09-2008, 10:29 AM
Hello,

ServiceAddService return -1. This is no >= ISERR_SUCCESS. And Format function gives no text message for this code. What does this code mean?

Christopher Painter
07-09-2008, 12:45 PM
Can you tell us what project type it is and a code snippet? If MSI, how are you scheduling it?

Kovalenko
07-09-2008, 02:31 PM
Yes, this is a Basic MSI type.

As far as I remember (I am now at home and will check it tomorrow and send a snippet) it is scheduled after InstallServices action.

And in fact it is installed despite -1 error code and successfully started.

Kovalenko
07-10-2008, 02:09 AM
Here is the whole function that installs Windows Service with relevant comments:



//
// Installs QEF as Windows service.
// This CA is deferred and used after InstallServices and SetInstallWindowsServiceData actions.
//
function InstallWindowsService(hMSI)
LIST lCustomActionData; // CA data list
STRING svServiceName, // QEF Windows service name
svDisplayName, // QEF Windows service display name
svDescription; // QEF Windows service description
STRING svCustomActionData, // CA data string
svBinDir, // Bin directory
svAccountType, // QEF Windows service account type
svLogin, // QEF Windws service login
svPassword, // QEF Windws service password
svStartupType, // QEF Windws service startup type
svStartAfterInstall; // QEF Windws service start after insttallation value
STRING svScriptFile, // script file in which the error occurred
svError, // error code for the error
svErrorMessage; // error message
NUMBER nvSize, // size of buffer used to get MSI properties
nResult, // result code
nAccountType, // QEF Windows service account type
nStartupType; // QEF Windws service startup type
NUMBER nvLineNumber, // line number in which the error occurred
nvError; // error code for the error
BOOL bStartAfterInstall; // QEF Windws service start after insttallation value
begin
svServiceName = "QEF";
svDisplayName = "QualiWare Execution Framework";
svDescription = "Enables deployment of QualiWare modules, management of user and groups, security and licensing, logging and monitoring.";

// Check if QEF Windows service is already installed.
if(ServiceExistsService(svServiceName) = TRUE) then
MessageBox("Cannot install Windows Servcie, because Windows Service with name \"" + svServiceName + "\" already exists!", WARNING);

return NOTHING;
endif;

nvSize = 256;
nvError = -1;

// Get CA data as a string.
nResult = MsiGetProperty(hMSI, "CustomActionData", svCustomActionData, nvSize);
if(nResult != ERROR_SUCCESS) then
MessageBox("Cannot get CA data!", SEVERE);
endif;

// Convert CA data from string to list.
lCustomActionData = ListCreate(STRINGLIST);

if (StrGetTokens(lCustomActionData, svCustomActionData, ";") > 0) then
MessageBox ("Failed to get tokens from string!", SEVERE);
endif;

// Get Bin directory from CA data list.
nResult = ListGetFirstString(lCustomActionData, svBinDir);
if(nResult = -1) then
MessageBox("Cannot get Bin directory path!", SEVERE);
endif;

// Get QEF Windows service accoount type from CA data list.
nResult = ListGetNextString(lCustomActionData, svAccountType);
if(nResult = -1) then
MessageBox("Cannot get Windows service account type!", SEVERE);
endif;

// Get QEF Windows service login from CA data list.
nResult = ListGetNextString(lCustomActionData, svLogin);
if(nResult = -1) then
MessageBox("Cannot get Windows service login!", SEVERE);
endif;

// Get QEF Windows service password from CA data list.
nResult = ListGetNextString(lCustomActionData, svPassword);
if(nResult = -1) then
MessageBox("Cannot get Windows service password!", SEVERE);
endif;

// Get QEF Windows service startup type from CA data list.
nResult = ListGetNextString(lCustomActionData, svStartupType);
if(nResult = -1) then
MessageBox("Cannot get Windows service startup type!", SEVERE);
endif;

// Get QEF Windws service start after insttallation value from CA data list.
nResult = ListGetNextString(lCustomActionData, svStartAfterInstall);
if(nResult = -1) then
MessageBox("Cannot get Windows service start after install value!", SEVERE);
endif;

// Destroy CA data list.
ListDestroy (lCustomActionData);

// Convert QEF Windows service account type from string to integer.
StrToNum(nAccountType, svAccountType);

// Set QEF Windows service login and password if account type is set to user account.
if(nAccountType = 1) then
SERVICE_IS_PARAMS.lpServiceStartName = &svLogin;
SERVICE_IS_PARAMS.lpPassword = &svPassword;
endif;

// Convert QEF Windows service startup type from string to integer.
StrToNum(nStartupType, svStartupType);

// Set QEF Windows service startup type.
switch(nStartupType)
case 0:
SERVICE_IS_PARAMS.dwStartType = SERVICE_AUTO_START;
case 1:
SERVICE_IS_PARAMS.dwStartType = SERVICE_DEMAND_START;
case 2:
SERVICE_IS_PARAMS.dwStartType = SERVICE_DISABLED;
endswitch;

// Convert QEF Windows service start after insttallation value from string to integer.
StrToNum(bStartAfterInstall, svStartAfterInstall);


nvError = ServiceAddService(svServiceName, svDisplayName, svDescription, svBinDir ^ "Qef.exe /RunAsService", bStartAfterInstall, "");
NumToStr(svError, nvError);
MessageBox("Exit code: " + svError, INFORMATION);
NumToStr(svError, ISERR_SUCCESS);
MessageBox("ISERR_SUCCESS code: " + svError, INFORMATION);
// Add QEF Windows service to the list of services to install.
if(nvError < ISERR_SUCCESS) then
svErrorMessage = "Windows sevice \"" + svServiceName + "\" cannot be installed!";
GetExtendedErrInfo(svScriptFile, nvLineNumber, nvError);
NumToStr(svError, nvError);
if(nvError = 1057) then // 1069 - wrong password
svErrorMessage = svErrorMessage + " The account name is invalid or does not exist!";
elseif(nvError = 1069) then
svErrorMessage = svErrorMessage + " The service did not start due to a logon failure!";
elseif(nvError = 2) then
svErrorMessage = "";
else
svErrorMessage = svErrorMessage + " Error code: " + svError;
endif;

MessageBox(svErrorMessage, WARNING);
endif;
end;

Christopher Painter
07-10-2008, 11:29 AM
If your using Basic MSI, what problem are you trying to solve that requires you to roll all of this code instead of just using the ServiceInstall table?

DevinEllingson
07-10-2008, 12:55 PM
This probably means that the service did not start in the time alloted by the function. Try calling GetExtendedErrInfo, this may give you more error information.

Devin Ellingson
Software Developer
Acresso Software

bryanwolf
07-10-2008, 01:11 PM
ServiceAddService returns a generic success/failure message and the error message can be gathered by calling GetLastError().

More info can be found here:
http://helpnet.acresso.com/robo/projects/installshield15langref/serviceaddservice.htm

Kovalenko
07-11-2008, 10:06 AM
The reason for using this script is to give user notifications and it is not flexible enough to run it either under System account or user account depending on user settings during installation.

GetExtendedErrInfo gives empty string.

GetLastError is a Windows API function invoked by GetExtendedErrInfo.

Christopher Painter
07-11-2008, 10:48 AM
If you mean to say that you give the user a choice as to what account to use to install the service, the ServiceInstall table's StartName and Password columns are formattable. You could create a dialog that collects the information into properties and then use that to create the service.

There are a couple ugly spots in MSI when it comes to authenticating the provided credentials and assining the LogonAsService right however.

bryanwolf
07-12-2008, 09:46 PM
Correct.

So you're saying that the GetExtErrorInfo's 3rd parameter is returning 0?

Based on how those APIs are invoked, I can't imagine a situation in which that's really possible, but if that's what you're seeing then it sounds like maybe an exception is being thrown.

Kovalenko
07-13-2008, 08:27 AM
I actually use a custom dialog to collect information from user. And then install the service with specified parameters with the help of ServiceAddService function. I have not come across any other documented way to do this (except using Services view that is I cannot use).

ServiceAddService function returns -1. And if I use GetExtendedErrInfo I get the same error number: -1. And when I try to use format function I get empty string.

DevinEllingson
07-15-2008, 12:40 AM
-1 is ISERR_GEN_FAILURE, FormatMessage only handles some errors, so you probably won't get any text for this error.

Do the svScriptFile and nvLineNumber parameters return anything?

Devin Ellingson
Software Developer
Acresso Software

Kovalenko
07-15-2008, 03:21 AM
Here is what script file and line number values are set to:

---------------------------
*** - InstallShield Wizard
---------------------------
Script file: C:\CodeBases\isdev\Script\ISRT\Src\Service.rul
Line number: 561
---------------------------
OK
---------------------------

DevinEllingson
07-16-2008, 03:27 AM
This indicates that the we did not detect that the service started in the time alloted (which is INFINITE by default).

Check the values in the public 'SERVICE_IS_STATUS' structure instance, we populate this structure with the final values that we got (check dwCurrentState especially).

One possibility is that the service is failing to report SERVICE_START_PENDING during the startup time, in this case the service code will fail in this way.

Devin Ellingson
Software Developer
Acresso Software

chenggj
07-04-2018, 01:00 AM
This indicates that the we did not detect that the service started in the time alloted (which is INFINITE by default).

Check the values in the public 'SERVICE_IS_STATUS' structure instance, we populate this structure with the final values that we got (check dwCurrentState especially).

One possibility is that the service is failing to report SERVICE_START_PENDING during the startup time, in this case the service code will fail in this way.

Devin Ellingson
Software Developer
Acresso Software

My case is this one, the service is in service_start_pending state.