Browse Source

my first shot

Kohsuke Kawaguchi 12 years ago
parent
commit
4caa17f921
4 changed files with 260 additions and 140 deletions
  1. 246 139
      Advapi32.cs
  2. 11 1
      Main.cs
  3. 2 0
      WmiSchema.cs
  4. 1 0
      winsw.csproj

+ 246 - 139
Advapi32.cs

@@ -2,16 +2,17 @@
 using System.Collections.Generic;
 using System.Text;
 using System.Runtime.InteropServices;
+using System.ComponentModel;
 
 namespace Advapi32
 {
-    class ServiceManager
+    class ServiceManager : IDisposable
     {
         private IntPtr Handle;
 
         public ServiceManager()
         {
-            Handle = Advapi32.OpenSCManager(null, null, (uint)Advapi32.SCM_ACCESS.SC_MANAGER_ALL_ACCESS);
+            Handle = Advapi32.OpenSCManager(null, null, (uint)SCM_ACCESS.SC_MANAGER_ALL_ACCESS);
             if (Handle == IntPtr.Zero)
             {
                 throw new Exception(String.Format("Error connecting to Service Control Manager. Error provided was: 0x{0:X}", Marshal.GetLastWin32Error()));
@@ -20,22 +21,24 @@ namespace Advapi32
 
         public Service Open(string serviceName)
         {
-            IntPtr svcHandle = Advapi32.OpenService(Handle, serviceName, (int)Advapi32.SERVICE_ACCESS.SERVICE_ALL_ACCESS);
+            IntPtr svcHandle = Advapi32.OpenService(Handle, serviceName, (int)SERVICE_ACCESS.SERVICE_ALL_ACCESS);
             if (svcHandle == IntPtr.Zero)
             {
                 throw new Exception(String.Format("Error opening service for modifying. Error returned was: 0x{0:X}", Marshal.GetLastWin32Error()));
             }
+            Console.WriteLine("Opened " + serviceName);
             return new Service(svcHandle);
         }
 
         public void Dispose()
         {
-            Advapi32.CloseServiceHandle(Handle);
+            if (Handle != IntPtr.Zero)
+                Advapi32.CloseServiceHandle(Handle);
             Handle = IntPtr.Zero;
         }
     }
 
-    class Service
+    class Service : IDisposable
     {
         internal IntPtr Handle;
 
@@ -44,7 +47,50 @@ namespace Advapi32
             Handle = service;
         }
 
+        public void ChangeConfig(TimeSpan failureResetPeriod)
+        {
+            SERVICE_FAILURE_ACTIONS sfa = new SERVICE_FAILURE_ACTIONS();
+            sfa.dwResetPeriod = failureResetPeriod.Seconds;
+            sfa.lpRebootMsg = ""; // delete message
+            sfa.lpCommand = "";   // delete the command to run
+            sfa.cActions = 0;
+            
+            SC_ACTION[] lpsaActions = new SC_ACTION[2];
+            lpsaActions[0] = new SC_ACTION(SC_ACTION_TYPE.SC_ACTION_RESTART, 1000);
+            lpsaActions[1] = new SC_ACTION(SC_ACTION_TYPE.SC_ACTION_RESTART, 2000);
+            lpsaActions[1] = new SC_ACTION(SC_ACTION_TYPE.SC_ACTION_RESTART, 5000);
+
+            sfa.lpsaActions = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(SC_ACTION)) * 2);
+            try
+            {
+                for (int i = 0; i < lpsaActions.Length; i++)
+                {
+                    Marshal.StructureToPtr(lpsaActions[i], sfa.lpsaActions/* new IntPtr(sfa.lpsaActions.ToInt64() + i * Marshal.SizeOf(typeof(SC_ACTION)))*/, false);
+                }
+
+                Console.WriteLine("Changing config to 2: sizeof(x)"+Marshal.SizeOf(typeof(SC_ACTION)));
+                int x = Marshal.GetLastWin32Error();
+
+                sfa.lpsaActions = IntPtr.Zero;
+
+                if (!Advapi32.ChangeServiceConfig2(Handle, SERVICE_CONFIG_INFOLEVEL.SERVICE_CONFIG_FAILURE_ACTIONS, sfa))
+                    throw new Exception("Failed to change the failure actions", new Win32Exception());
+
+                throw new Exception("OK:" + x + "/" + Marshal.GetLastWin32Error(), new Win32Exception());
+
+            }
+            finally
+            {
+                Marshal.FreeCoTaskMem(sfa.lpsaActions);
+            }
+        }
 
+        public void Dispose()
+        {
+            if (Handle!=IntPtr.Zero)
+                Advapi32.CloseServiceHandle(Handle);
+            Handle = IntPtr.Zero;
+        }
     }
 
     /// <summary>
@@ -55,7 +101,11 @@ namespace Advapi32
     {
         [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
         [return: MarshalAs(UnmanagedType.Bool)]
-        internal static extern bool ChangeServiceConfig2(IntPtr hService, int dwInfoLevel, IntPtr lpInfo);
+        internal static extern bool ChangeServiceConfig2(IntPtr hService, SERVICE_CONFIG_INFOLEVEL dwInfoLevel, IntPtr lpInfo);
+
+        [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
+        [return: MarshalAs(UnmanagedType.Bool)]
+        internal static extern bool ChangeServiceConfig2(IntPtr hService, SERVICE_CONFIG_INFOLEVEL dwInfoLevel, SERVICE_FAILURE_ACTIONS sfa);
 
         [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
         internal static extern IntPtr OpenSCManager(string machineName, string databaseName, uint dwAccess);
@@ -66,143 +116,200 @@ namespace Advapi32
         [DllImport("advapi32.dll", SetLastError = true)]
         [return: MarshalAs(UnmanagedType.Bool)]
         internal static extern bool CloseServiceHandle(IntPtr hSCObject);
+    }
 
-        internal enum SCM_ACCESS : uint
-        {
-            /// <summary>
-            /// Required to connect to the service control manager.
-            /// </summary>
-            SC_MANAGER_CONNECT = 0x00001,
-
-            /// <summary>
-            /// Required to call the CreateService function to create a service
-            /// object and add it to the database.
-            /// </summary>
-            SC_MANAGER_CREATE_SERVICE = 0x00002,
-
-            /// <summary>
-            /// Required to call the EnumServicesStatusEx function to list the 
-            /// services that are in the database.
-            /// </summary>
-            SC_MANAGER_ENUMERATE_SERVICE = 0x00004,
-
-            /// <summary>
-            /// Required to call the LockServiceDatabase function to acquire a 
-            /// lock on the database.
-            /// </summary>
-            SC_MANAGER_LOCK = 0x00008,
-
-            /// <summary>
-            /// Required to call the QueryServiceLockStatus function to retrieve 
-            /// the lock status information for the database.
-            /// </summary>
-            SC_MANAGER_QUERY_LOCK_STATUS = 0x00010,
-
-            /// <summary>
-            /// Required to call the NotifyBootConfigStatus function.
-            /// </summary>
-            SC_MANAGER_MODIFY_BOOT_CONFIG = 0x00020,
-
-            /// <summary>
-            /// Includes STANDARD_RIGHTS_REQUIRED, in addition to all access 
-            /// rights in this table.
-            /// </summary>
-            SC_MANAGER_ALL_ACCESS = ACCESS_MASK.STANDARD_RIGHTS_REQUIRED |
-                SC_MANAGER_CONNECT |
-                SC_MANAGER_CREATE_SERVICE |
-                SC_MANAGER_ENUMERATE_SERVICE |
-                SC_MANAGER_LOCK |
-                SC_MANAGER_QUERY_LOCK_STATUS |
-                SC_MANAGER_MODIFY_BOOT_CONFIG,
-
-            GENERIC_READ = ACCESS_MASK.STANDARD_RIGHTS_READ |
-                SC_MANAGER_ENUMERATE_SERVICE |
-                SC_MANAGER_QUERY_LOCK_STATUS,
-
-            GENERIC_WRITE = ACCESS_MASK.STANDARD_RIGHTS_WRITE |
-                SC_MANAGER_CREATE_SERVICE |
-                SC_MANAGER_MODIFY_BOOT_CONFIG,
-
-            GENERIC_EXECUTE = ACCESS_MASK.STANDARD_RIGHTS_EXECUTE |
-                SC_MANAGER_CONNECT | SC_MANAGER_LOCK,
-
-            GENERIC_ALL = SC_MANAGER_ALL_ACCESS,
-        }
 
-        [Flags]
-        internal enum SERVICE_ACCESS : uint
-        {
-            STANDARD_RIGHTS_REQUIRED = 0xF0000,
-            SERVICE_QUERY_CONFIG = 0x00001,
-            SERVICE_CHANGE_CONFIG = 0x00002,
-            SERVICE_QUERY_STATUS = 0x00004,
-            SERVICE_ENUMERATE_DEPENDENTS = 0x00008,
-            SERVICE_START = 0x00010,
-            SERVICE_STOP = 0x00020,
-            SERVICE_PAUSE_CONTINUE = 0x00040,
-            SERVICE_INTERROGATE = 0x00080,
-            SERVICE_USER_DEFINED_CONTROL = 0x00100,
-            SERVICE_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED |
-                              SERVICE_QUERY_CONFIG |
-                              SERVICE_CHANGE_CONFIG |
-                              SERVICE_QUERY_STATUS |
-                              SERVICE_ENUMERATE_DEPENDENTS |
-                              SERVICE_START |
-                              SERVICE_STOP |
-                              SERVICE_PAUSE_CONTINUE |
-                              SERVICE_INTERROGATE |
-                              SERVICE_USER_DEFINED_CONTROL)
-        }
+    internal enum SCM_ACCESS : uint
+    {
+        /// <summary>
+        /// Required to connect to the service control manager.
+        /// </summary>
+        SC_MANAGER_CONNECT = 0x00001,
+
+        /// <summary>
+        /// Required to call the CreateService function to create a service
+        /// object and add it to the database.
+        /// </summary>
+        SC_MANAGER_CREATE_SERVICE = 0x00002,
+
+        /// <summary>
+        /// Required to call the EnumServicesStatusEx function to list the 
+        /// services that are in the database.
+        /// </summary>
+        SC_MANAGER_ENUMERATE_SERVICE = 0x00004,
+
+        /// <summary>
+        /// Required to call the LockServiceDatabase function to acquire a 
+        /// lock on the database.
+        /// </summary>
+        SC_MANAGER_LOCK = 0x00008,
+
+        /// <summary>
+        /// Required to call the QueryServiceLockStatus function to retrieve 
+        /// the lock status information for the database.
+        /// </summary>
+        SC_MANAGER_QUERY_LOCK_STATUS = 0x00010,
+
+        /// <summary>
+        /// Required to call the NotifyBootConfigStatus function.
+        /// </summary>
+        SC_MANAGER_MODIFY_BOOT_CONFIG = 0x00020,
+
+        /// <summary>
+        /// Includes STANDARD_RIGHTS_REQUIRED, in addition to all access 
+        /// rights in this table.
+        /// </summary>
+        SC_MANAGER_ALL_ACCESS = ACCESS_MASK.STANDARD_RIGHTS_REQUIRED |
+            SC_MANAGER_CONNECT |
+            SC_MANAGER_CREATE_SERVICE |
+            SC_MANAGER_ENUMERATE_SERVICE |
+            SC_MANAGER_LOCK |
+            SC_MANAGER_QUERY_LOCK_STATUS |
+            SC_MANAGER_MODIFY_BOOT_CONFIG,
+
+        GENERIC_READ = ACCESS_MASK.STANDARD_RIGHTS_READ |
+            SC_MANAGER_ENUMERATE_SERVICE |
+            SC_MANAGER_QUERY_LOCK_STATUS,
+
+        GENERIC_WRITE = ACCESS_MASK.STANDARD_RIGHTS_WRITE |
+            SC_MANAGER_CREATE_SERVICE |
+            SC_MANAGER_MODIFY_BOOT_CONFIG,
+
+        GENERIC_EXECUTE = ACCESS_MASK.STANDARD_RIGHTS_EXECUTE |
+            SC_MANAGER_CONNECT | SC_MANAGER_LOCK,
+
+        GENERIC_ALL = SC_MANAGER_ALL_ACCESS,
+    }
 
-        [Flags]
-        internal enum ACCESS_MASK : uint
+    [Flags]
+    internal enum SERVICE_ACCESS : uint
+    {
+        STANDARD_RIGHTS_REQUIRED = 0xF0000,
+        SERVICE_QUERY_CONFIG = 0x00001,
+        SERVICE_CHANGE_CONFIG = 0x00002,
+        SERVICE_QUERY_STATUS = 0x00004,
+        SERVICE_ENUMERATE_DEPENDENTS = 0x00008,
+        SERVICE_START = 0x00010,
+        SERVICE_STOP = 0x00020,
+        SERVICE_PAUSE_CONTINUE = 0x00040,
+        SERVICE_INTERROGATE = 0x00080,
+        SERVICE_USER_DEFINED_CONTROL = 0x00100,
+        SERVICE_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED |
+                          SERVICE_QUERY_CONFIG |
+                          SERVICE_CHANGE_CONFIG |
+                          SERVICE_QUERY_STATUS |
+                          SERVICE_ENUMERATE_DEPENDENTS |
+                          SERVICE_START |
+                          SERVICE_STOP |
+                          SERVICE_PAUSE_CONTINUE |
+                          SERVICE_INTERROGATE |
+                          SERVICE_USER_DEFINED_CONTROL)
+    }
+
+    [Flags]
+    internal enum ACCESS_MASK : uint
+    {
+        DELETE = 0x00010000,
+        READ_CONTROL = 0x00020000,
+        WRITE_DAC = 0x00040000,
+        WRITE_OWNER = 0x00080000,
+        SYNCHRONIZE = 0x00100000,
+
+        STANDARD_RIGHTS_REQUIRED = 0x000f0000,
+
+        STANDARD_RIGHTS_READ = 0x00020000,
+        STANDARD_RIGHTS_WRITE = 0x00020000,
+        STANDARD_RIGHTS_EXECUTE = 0x00020000,
+
+        STANDARD_RIGHTS_ALL = 0x001f0000,
+
+        SPECIFIC_RIGHTS_ALL = 0x0000ffff,
+
+        ACCESS_SYSTEM_SECURITY = 0x01000000,
+
+        MAXIMUM_ALLOWED = 0x02000000,
+
+        GENERIC_READ = 0x80000000,
+        GENERIC_WRITE = 0x40000000,
+        GENERIC_EXECUTE = 0x20000000,
+        GENERIC_ALL = 0x10000000,
+
+        DESKTOP_READOBJECTS = 0x00000001,
+        DESKTOP_CREATEWINDOW = 0x00000002,
+        DESKTOP_CREATEMENU = 0x00000004,
+        DESKTOP_HOOKCONTROL = 0x00000008,
+        DESKTOP_JOURNALRECORD = 0x00000010,
+        DESKTOP_JOURNALPLAYBACK = 0x00000020,
+        DESKTOP_ENUMERATE = 0x00000040,
+        DESKTOP_WRITEOBJECTS = 0x00000080,
+        DESKTOP_SWITCHDESKTOP = 0x00000100,
+
+        WINSTA_ENUMDESKTOPS = 0x00000001,
+        WINSTA_READATTRIBUTES = 0x00000002,
+        WINSTA_ACCESSCLIPBOARD = 0x00000004,
+        WINSTA_CREATEDESKTOP = 0x00000008,
+        WINSTA_WRITEATTRIBUTES = 0x00000010,
+        WINSTA_ACCESSGLOBALATOMS = 0x00000020,
+        WINSTA_EXITWINDOWS = 0x00000040,
+        WINSTA_ENUMERATE = 0x00000100,
+        WINSTA_READSCREEN = 0x00000200,
+
+        WINSTA_ALL_ACCESS = 0x0000037f
+    }
+
+    // http://msdn.microsoft.com/en-us/library/windows/desktop/ms685126(v=vs.85).aspx
+    [StructLayout(LayoutKind.Sequential)]
+    public struct SC_ACTION
+    {
+        public SC_ACTION_TYPE Type;
+        /// <summary>
+        /// The time to wait before performing the specified action, in milliseconds.
+        /// </summary>
+        public uint Delay;
+
+        public SC_ACTION(SC_ACTION_TYPE type, uint delay)
         {
-             DELETE = 0x00010000,
-             READ_CONTROL = 0x00020000,
-             WRITE_DAC = 0x00040000,
-             WRITE_OWNER = 0x00080000,
-             SYNCHRONIZE = 0x00100000,
-
-             STANDARD_RIGHTS_REQUIRED = 0x000f0000,
-
-             STANDARD_RIGHTS_READ = 0x00020000,
-             STANDARD_RIGHTS_WRITE = 0x00020000,
-             STANDARD_RIGHTS_EXECUTE = 0x00020000,
-
-             STANDARD_RIGHTS_ALL = 0x001f0000,
-
-             SPECIFIC_RIGHTS_ALL = 0x0000ffff,
-
-             ACCESS_SYSTEM_SECURITY = 0x01000000,
-
-             MAXIMUM_ALLOWED = 0x02000000,
-
-             GENERIC_READ = 0x80000000,
-             GENERIC_WRITE = 0x40000000,
-             GENERIC_EXECUTE = 0x20000000,
-             GENERIC_ALL = 0x10000000,
-
-             DESKTOP_READOBJECTS = 0x00000001,
-             DESKTOP_CREATEWINDOW = 0x00000002,
-             DESKTOP_CREATEMENU = 0x00000004,
-             DESKTOP_HOOKCONTROL = 0x00000008,
-             DESKTOP_JOURNALRECORD = 0x00000010,
-             DESKTOP_JOURNALPLAYBACK = 0x00000020,
-             DESKTOP_ENUMERATE = 0x00000040,
-             DESKTOP_WRITEOBJECTS = 0x00000080,
-             DESKTOP_SWITCHDESKTOP = 0x00000100,
-
-             WINSTA_ENUMDESKTOPS = 0x00000001,
-             WINSTA_READATTRIBUTES = 0x00000002,
-             WINSTA_ACCESSCLIPBOARD = 0x00000004,
-             WINSTA_CREATEDESKTOP = 0x00000008,
-             WINSTA_WRITEATTRIBUTES = 0x00000010,
-             WINSTA_ACCESSGLOBALATOMS = 0x00000020,
-             WINSTA_EXITWINDOWS = 0x00000040,
-             WINSTA_ENUMERATE = 0x00000100,
-             WINSTA_READSCREEN = 0x00000200,
-
-             WINSTA_ALL_ACCESS = 0x0000037f
+            this.Type = type;
+            this.Delay = delay;
         }
     }
+
+    internal enum SERVICE_CONFIG_INFOLEVEL
+    {
+        SERVICE_CONFIG_DESCRIPTION = 1,
+        SERVICE_CONFIG_FAILURE_ACTIONS = 2,
+        SERVICE_CONFIG_DELAYED_AUTO_START_INFO = 3,
+        SERVICE_CONFIG_FAILURE_ACTIONS_FLAG = 4,
+        SERVICE_CONFIG_SERVICE_SID_INFO = 5,
+        SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO = 6,
+        SERVICE_CONFIG_PRESHUTDOWN_INFO = 7,
+        SERVICE_CONFIG_TRIGGER_INFO = 8,
+        SERVICE_CONFIG_PREFERRED_NODE = 9
+    }
+
+    public enum SC_ACTION_TYPE
+    {
+        SC_ACTION_NONE = 0,
+        SC_ACTION_RESTART = 1,
+        SC_ACTION_REBOOT = 2,
+        SC_ACTION_RUN_COMMAND = 3
+    }
+
+    // http://msdn.microsoft.com/en-us/library/windows/desktop/ms685939(v=vs.85).aspx
+    [StructLayout(LayoutKind.Sequential)]
+    public struct SERVICE_FAILURE_ACTIONS
+    {
+        /// <summary>
+        /// The time after which to reset the failure count to zero if there are no failures, in seconds.
+        /// Specify INFINITE to indicate that this value should never be reset.
+        /// </summary>
+        public int dwResetPeriod;
+
+        [MarshalAs(UnmanagedType.LPTStr)]
+        public string lpRebootMsg;
+        [MarshalAs(UnmanagedType.LPTStr)]
+        public string lpCommand;
+        public int cActions;
+        public IntPtr/*SC_ACTION[]*/ lpsaActions;
+    }
 }

+ 11 - 1
Main.cs

@@ -421,7 +421,7 @@ namespace winsw
             });
         }
 
-        public static int Main(string[] args)
+        public static int _Main(string[] args)
         {
             try
             {
@@ -550,6 +550,16 @@ namespace winsw
                     else
                         Console.WriteLine("Stopped");
                 }
+                if (args[0] == "autorestart")
+                {// debug only. to be removed.
+                    using (Advapi32.ServiceManager scm = new Advapi32.ServiceManager())
+                    {
+                        using (Advapi32.Service sc = scm.Open(d.Id))
+                        {
+                            sc.ChangeConfig(TimeSpan.FromHours(48));
+                        }
+                    }
+                }
                 if (args[0] == "test")
                 {
                     WrapperService wsvc = new WrapperService();

+ 2 - 0
WmiSchema.cs

@@ -53,9 +53,11 @@ namespace WMI
         Win32Service Select(string name);
     }
 
+    // http://msdn.microsoft.com/en-us/library/windows/desktop/aa394418(v=vs.85).aspx
     public interface Win32Service : IWmiObject
     {
         string Description { get; set; }
+        string Name { get; }
         bool Started { get; }
         void Delete();
         void StartService();

+ 1 - 0
winsw.csproj

@@ -53,6 +53,7 @@
     <Compile Include="Main.cs">
       <SubType>Component</SubType>
     </Compile>
+    <Compile Include="NotGettingAnywhere.cs" />
     <Compile Include="PeriodicRollingCalendar.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="ServiceDescriptor.cs" />