Exemple #1
0
        static int Main(string[] args)
        {
            Thread.CurrentThread.Name = "Test Service";
            if (args.Length == 1 || args.Length == 2)
            {
                TestService testService;
                if (args[0].StartsWith("PropagateExceptionFromOnStart"))
                {
                    var expectedException = new InvalidOperationException("Fail on startup.");
                    testService = new TestService(args[0], expectedException);
                    try
                    {
                        ServiceBase.Run(testService);
                    }
                    catch (Exception actualException)
                    {
                        if (object.ReferenceEquals(expectedException, actualException))
                        {
                            testService.WriteStreamAsync(PipeMessageByteCode.ExceptionThrown).Wait();
                        }
                        else
                        {
                            throw actualException;
                        }
                    }
                }
                else if (args[0].StartsWith("LogWritten"))
                {
                    testService         = new TestService(args[0], throwException: null);
                    testService.AutoLog = false;
                    ServiceBase.Run(testService);
                }
                else
                {
                    testService = new TestService(args[0]);
                    ServiceBase.Run(testService);
                }
                return(0);
            }
            else if (args.Length == 3)
            {
                TestServiceInstaller testServiceInstaller = new TestServiceInstaller();

                testServiceInstaller.ServiceName = args[0];
                testServiceInstaller.DisplayName = args[1];

                if (args[2] == "create")
                {
                    testServiceInstaller.Install();
                    return(0);
                }
                else if (args[2] == "delete")
                {
                    testServiceInstaller.RemoveService();
                    return(0);
                }
                else
                {
                    Console.WriteLine("EROOR: Invalid Service verb. Only support create or delete.");
                    return(2);
                }
            }

            Console.WriteLine($"usage: <ServiceName> <DisplayName> [create|delete]");
            return(1);
        }
        // Install and start the test service, after starting any prerequisite services it depends on
        public unsafe void Install()
        {
            string username = Username;
            string password = Password;

            if (ServiceCommandLine == null)
            {
                string processName    = Process.GetCurrentProcess().MainModule.FileName;
                string entryPointName = System.Reflection.Assembly.GetEntryAssembly().Location;
                string arguments      = ServiceName;

                // if process and entry point aren't the same then we are running hosted so pass
                // in the entrypoint as the first argument
                if (!string.Equals(processName, entryPointName, StringComparison.OrdinalIgnoreCase))
                {
                    arguments = $"\"{entryPointName}\" {arguments}";
                }

                ServiceCommandLine = $"\"{processName}\" {arguments}";
            }

            // Build servicesDependedOn string
            // These are prerequisite services that must be started before this service
            string servicesDependedOn = null;

            if (ServicesDependedOn.Length > 0)
            {
                StringBuilder buff = new StringBuilder();
                for (int i = 0; i < ServicesDependedOn.Length; ++i)
                {
                    //The servicesDependedOn need to be separated by a null
                    buff.Append(ServicesDependedOn[i]);
                    buff.Append('\0');
                }
                // an extra null at the end indicates end of list.
                buff.Append('\0');

                servicesDependedOn = buff.ToString();
            }

            // Open the service manager
            using (var serviceManagerHandle = new SafeServiceHandle(Interop.Advapi32.OpenSCManager(null, null, Interop.Advapi32.ServiceControllerOptions.SC_MANAGER_ALL)))
            {
                if (serviceManagerHandle.IsInvalid)
                {
                    throw new InvalidOperationException("Cannot open Service Control Manager");
                }

                TestService.DebugTrace($"TestServiceInstaller: creating service '{ServiceName}' with prerequisite services {servicesDependedOn}");

                // Install the service
                using (var serviceHandle = new SafeServiceHandle(Interop.Advapi32.CreateService(serviceManagerHandle, ServiceName,
                                                                                                DisplayName, Interop.Advapi32.ServiceAccessOptions.ACCESS_TYPE_ALL, Interop.Advapi32.ServiceTypeOptions.SERVICE_WIN32_OWN_PROCESS,
                                                                                                (int)StartType, Interop.Advapi32.ServiceStartErrorModes.ERROR_CONTROL_NORMAL,
                                                                                                ServiceCommandLine, null, IntPtr.Zero, servicesDependedOn, username, password)))
                {
                    if (serviceHandle.IsInvalid)
                    {
                        int    errorCode    = Marshal.GetLastWin32Error();
                        string errorMessage = new Win32Exception(errorCode).Message;
                        throw new Win32Exception(errorCode, $"Cannot create service '{ServiceName}' with display name '{DisplayName}'. {errorMessage}");
                    }

                    // A local variable in an unsafe method is already fixed -- so we don't need a "fixed { }" blocks to protect
                    // across the p/invoke calls below.

                    if (Description.Length != 0)
                    {
                        Interop.Advapi32.SERVICE_DESCRIPTION serviceDesc = new Interop.Advapi32.SERVICE_DESCRIPTION();
                        serviceDesc.description = Marshal.StringToHGlobalUni(Description);
                        bool success = Interop.Advapi32.ChangeServiceConfig2(serviceHandle, Interop.Advapi32.ServiceConfigOptions.SERVICE_CONFIG_DESCRIPTION, ref serviceDesc);
                        Marshal.FreeHGlobal(serviceDesc.description);
                        if (!success)
                        {
                            int    errorCode    = Marshal.GetLastWin32Error();
                            string errorMessage = new Win32Exception(errorCode).Message;
                            throw new Win32Exception(errorCode, $"Cannot set description on '{ServiceName}' with display name '{DisplayName}'. {errorMessage}");
                        }
                    }

                    // Start the service after creating it
                    using (ServiceController svc = new ServiceController(ServiceName))
                    {
                        if (svc.Status != ServiceControllerStatus.Running)
                        {
                            TestService.DebugTrace($"TestServiceInstaller: instructing ServiceController to start service '{ServiceName}'");
                            svc.Start();
                            if (!ServiceName.StartsWith("PropagateExceptionFromOnStart"))
                            {
                                svc.WaitForStatus(ServiceControllerStatus.Running, TimeSpan.FromSeconds(240));
                            }
                        }
                        else
                        {
                            TestService.DebugTrace($"TestServiceInstaller: service '{ServiceName}' already running");
                        }
                    }
                }
            }
        }