Exemplo n.º 1
0
        /// <devdoc>
        ///    <para>Provides the main entry point for an executable that
        ///       contains multiple associated services. Loads the specified services into memory so they can be
        ///       started.</para>
        /// </devdoc>
        public static unsafe void Run(ServiceBase[] services)
        {
            if (services == null || services.Length == 0)
            {
                throw new ArgumentException(SR.NoServices);
            }

            IntPtr entriesPointer = Marshal.AllocHGlobal(checked ((services.Length + 1) * sizeof(SERVICE_TABLE_ENTRY)));
            Span <SERVICE_TABLE_ENTRY> entries = new Span <SERVICE_TABLE_ENTRY>((void *)entriesPointer, services.Length + 1);

            entries.Clear();
            try
            {
                bool multipleServices = services.Length > 1;

                // The members of the last entry in the table must have NULL values to designate the end of the table.
                // Leave the last element in the entries span to be zeroed out.
                for (int index = 0; index < services.Length; ++index)
                {
                    ServiceBase service = services[index];
                    service.Initialize(multipleServices);
                    // This method allocates on unmanaged heap; Make sure that the contents are freed after use.
                    entries[index] = service.GetEntry();
                }

                // While the service is running, this function will never return. It will return when the service
                // is stopped.
                // After it returns, SCM might terminate the process at any time
                // (so subsequent code is not guaranteed to run).
                bool res = StartServiceCtrlDispatcher(entriesPointer);

                foreach (ServiceBase service in services)
                {
                    if (service._startFailedException != null)
                    {
                        // Propagate exceptions throw during OnStart.
                        // Note that this same exception is also thrown from ServiceMainCallback
                        // (so SCM can see it as well).
                        service._startFailedException.Throw();
                    }
                }

                string errorMessage = string.Empty;

                if (!res)
                {
                    errorMessage = new Win32Exception().Message;
                    Console.WriteLine(SR.CantStartFromCommandLine);
                }

                foreach (ServiceBase service in services)
                {
                    service.Dispose();
                    if (!res)
                    {
                        service.WriteLogEntry(SR.Format(SR.StartFailed, errorMessage), EventLogEntryType.Error);
                    }
                }
            }
            finally
            {
                // Free the pointer to the name of the service on the unmanaged heap.
                for (int i = 0; i < entries.Length; i++)
                {
                    Marshal.FreeHGlobal(entries[i].name);
                }

                // Free the unmanaged array containing the entries.
                Marshal.FreeHGlobal(entriesPointer);
            }
        }