/// <summary> /// Sets the failure actions for the specified service /// </summary> /// <param name="serviceName"></param> /// <param name="sfa"></param> internal static void SetFailureActions(string serviceName, ref NativeMethods.SERVICE_FAILURE_ACTIONS sfa) { AppAssert.Assert(null != serviceName, "Null service name passed!"); IntPtr lockHandle = NativeMethods.NullIntPtr; IntPtr scmHandle = NativeMethods.NullIntPtr; IntPtr svcHandle = NativeMethods.NullIntPtr; try { scmHandle = ServiceConfigurationHandler.GetSCMHandle(); //lock the database lockHandle = RepeatLockServiceDatabase(scmHandle); if (NativeMethods.NullIntPtr.Equals(lockHandle)) { SetupLogger.LogError("BackEnd.Configure: Got back NULL service handle!"); int lastWin32Error = System.Runtime.InteropServices.Marshal.GetLastWin32Error(); throw new Exception(String.Format("Setup was unable to configure service {0}", serviceName)); } svcHandle = NativeMethods.OpenService( scmHandle, serviceName, NativeMethods.SERVICE_CHANGE_CONFIG | NativeMethods.SERVICE_START);//since we set restart as a failure option, the handle should have SERVICE_START rights if (NativeMethods.NullIntPtr.Equals(svcHandle)) { //throw exception here SetupLogger.LogInfo("BackEnd.Configure: Got back NULL service handle!"); int lastWin32Error = System.Runtime.InteropServices.Marshal.GetLastWin32Error(); throw new Exception(String.Format("Setup was unable to configure service {0}", serviceName)); } SetupLogger.LogInfo("BackEnd.Configure: Successfully opened {0} service", serviceName); bool success = NativeMethods.ChangeServiceConfig2(svcHandle, NativeMethods.SERVICE_CONFIG_FAILURE_ACTIONS, ref sfa); if (!success) { SetupLogger.LogInfo("BackEnd.Configure: Couldn't modify service description!"); int lastWin32Error = System.Runtime.InteropServices.Marshal.GetLastWin32Error(); throw new Exception(String.Format("Setup was unable to configure service {0}", serviceName)); } } finally { if (!NativeMethods.NullIntPtr.Equals(lockHandle)) { NativeMethods.UnlockServiceDatabase(lockHandle); } if (!NativeMethods.NullIntPtr.Equals(svcHandle)) { NativeMethods.CloseServiceHandle(svcHandle); } if (!NativeMethods.NullIntPtr.Equals(scmHandle)) { NativeMethods.CloseServiceHandle(scmHandle); } } }
/// <summary> /// Create the engine service and start it /// </summary> public static void ConfigureCMPWorkerService(ServiceConfigurationHandler serviceConfigurationHandler) { AppAssert.AssertNotNull(serviceConfigurationHandler, "serviceConfigurationHandler"); string installPath = SetupConstants.GetServerInstallPath(); //attempt to remove services first. //this will ignore errors of service does not exist and service marked for deletion //If service is marked for deletion, then exception will be thrown at create time as //we will be unable to create the service. //reason: //1. Keeps the code path of Install and Repair same //2. Handles corner case of service already existing in Install mode //3. Repairs the configuration of the service if broken IntPtr hSCManager = NativeMethods.NullIntPtr; IntPtr password = NativeMethods.NullIntPtr; try { hSCManager = ServiceConfigurationHandler.GetSCMHandle(); //TODO: Handle rollback if exception is thrown ServiceConfigurationHandler.StopAndRemoveService(hSCManager, SetupConstants.EngineServiceName); //construct paths to service binaries string servicePathEngine = PathHelper.QuoteString(installPath + @"MSIT\CmpWorkerService\" + SetupConstants.EngineServiceBinary); SetupLogger.LogInfo("BackEnd.Configure: Engine Service path is : {0}", servicePathEngine); //Get account string userAccountName = null; bool runasLocalAccount = SetupInputs.Instance.FindItem(SetupInputTags.CmpServiceLocalAccountTag); if (!runasLocalAccount) { userAccountName = UserAccountHelper.GetVmmServiceDomainAccount(); password = Marshal.SecureStringToGlobalAllocUnicode(SetupInputs.Instance.FindItem(SetupInputTags.CmpServiceUserPasswordTag)); } //create engine service ServiceConfigurationHandler.CreateService( hSCManager, SetupConstants.EngineServiceName, Resources.EngineServiceDisplayName, Resources.EngineServiceDescription, servicePathEngine, null, // dependent services userAccountName, password: password, autoStart: true, interactive: false); //set failure actions for VMMService NativeMethods.SERVICE_FAILURE_ACTIONS sfa = new NativeMethods.SERVICE_FAILURE_ACTIONS(); NativeMethods.SC_ACTION[] sca = new NativeMethods.SC_ACTION[SetupConstants.ServiceActionsCount + 1]; for (int i = 0; i < SetupConstants.ServiceActionsCount; i++) { sca[i].Delay = SetupConstants.ServiceRestartDelay; sca[i].Type = NativeMethods.SC_ACTION_TYPE.SC_ACTION_RESTART; } sca[SetupConstants.ServiceActionsCount].Delay = 0; sca[SetupConstants.ServiceActionsCount].Type = NativeMethods.SC_ACTION_TYPE.SC_ACTION_NONE; IntPtr unmanagedStructArray = NativeMethods.NullIntPtr; try { unmanagedStructArray = GetUnmanagedStructArray(sca); sfa.sc_Action = unmanagedStructArray; sfa.cActions = SetupConstants.ServiceActionsCount + 1; sfa.dwResetPeriod = SetupConstants.ServiceResetPeriod; sfa.lpCommand = null; sfa.lpRebootMsg = null; //set service failure actions for engine service ServiceConfigurationHandler.SetFailureActions(SetupConstants.EngineServiceName, ref sfa); //ConfigurationProgressEvent(this, new EventArgs()); } finally { if (NativeMethods.NullIntPtr != unmanagedStructArray) { Marshal.FreeHGlobal(unmanagedStructArray); } } } finally { if (!NativeMethods.NullIntPtr.Equals(hSCManager)) { NativeMethods.CloseServiceHandle(hSCManager); } if (!NativeMethods.NullIntPtr.Equals(password)) { Marshal.ZeroFreeGlobalAllocUnicode(password); } } }