/// <include file='doc\ServiceBase.uex' path='docs/doc[@for="ServiceBase.Initialize"]/*' /> /// <devdoc> /// Starts the service object, creates the objects and /// allocates the memory needed. /// </devdoc> /// <internalonly/> internal NativeMethods.ENTRY Initialize(bool multipleServices) { //Cannot register the service with NT service manatger if the object has been disposed, since finalization has been suppressed. if (this.disposed) { throw new ObjectDisposedException(GetType().Name); } if (multipleServices) { status.serviceType = NativeMethods.SERVICE_TYPE_WIN32_OWN_PROCESS; } else { status.serviceType = NativeMethods.SERVICE_TYPE_WIN32_SHARE_PROCESS; } status.currentState = NativeMethods.STATE_START_PENDING; status.controlsAccepted = 0; status.win32ExitCode = 0; status.serviceSpecificExitCode = 0; status.checkPoint = 0; status.waitHint = 0; NativeMethods.ENTRY entry = new NativeMethods.ENTRY(); this.mainCallback = new NativeMethods.ServiceMainCallback(this.ServiceMainCallback); this.commandCallback = new NativeMethods.ServiceControlCallback(this.ServiceCommandCallback); this.commandCallbackEx = new NativeMethods.ServiceControlCallbackEx(this.ServiceCommandCallbackEx); this.handleName = Marshal.StringToHGlobalUni(this.ServiceName); nameFrozen = true; entry.callback = (Delegate)mainCallback; entry.name = this.handleName; return(entry); }
/// <include file='doc\ServiceBase.uex' path='docs/doc[@for="ServiceBase.Run"]/*' /> /// <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 void Run(ServiceBase[] services) { if (services == null || services.Length == 0) { throw new ArgumentException(Res.GetString(Res.NoServices)); } // check if we're on an NT OS if (Environment.OSVersion.Platform != PlatformID.Win32NT) { // if not NT, put up a message box and exit. string cantRunOnWin9x = Res.GetString(Res.CantRunOnWin9x); string cantRunOnWin9xTitle = Res.GetString(Res.CantRunOnWin9xTitle); LateBoundMessageBoxShow(cantRunOnWin9x, cantRunOnWin9xTitle); return; } IntPtr entriesPointer = Marshal.AllocHGlobal((IntPtr)((services.Length + 1) * Marshal.SizeOf(typeof(NativeMethods.ENTRY)))); NativeMethods.ENTRY[] entries = new NativeMethods.ENTRY[services.Length]; bool multipleServices = services.Length > 1; IntPtr structPtr = (IntPtr)0; for (int index = 0; index < services.Length; ++index) { entries[index] = services[index].Initialize(multipleServices); structPtr = (IntPtr)((long)entriesPointer + Marshal.SizeOf(typeof(NativeMethods.ENTRY)) * index); Marshal.StructureToPtr(entries[index], structPtr, true); } NativeMethods.ENTRY lastEntry = new NativeMethods.ENTRY(); lastEntry.callback = null; lastEntry.name = (IntPtr)0; structPtr = (IntPtr)((long)entriesPointer + Marshal.SizeOf(typeof(NativeMethods.ENTRY)) * services.Length); Marshal.StructureToPtr(lastEntry, structPtr, true); // While the service is running, this function will never return. It will return when the service // is stopped. bool res = NativeMethods.StartServiceCtrlDispatcher(entriesPointer); string errorMessage = ""; if (!res) { errorMessage = new Win32Exception().Message; // This message will only print out if the exe is run at the command prompt - which is not // a valid thing to do. string cantStartFromCommandLine = Res.GetString(Res.CantStartFromCommandLine); if (LateBoundGetUserInteractive()) { string cantStartFromCommandLineTitle = Res.GetString(Res.CantStartFromCommandLineTitle); LateBoundMessageBoxShow(cantStartFromCommandLine, cantStartFromCommandLineTitle); } else { Console.WriteLine(cantStartFromCommandLine); } } foreach (ServiceBase service in services) { service.Dispose(); if (!res && service.EventLog.Source.Length != 0) { service.WriteEventLogEntry(Res.GetString(Res.StartFailed, errorMessage), EventLogEntryType.Error); } } }