2011-06-15 21 views
14

मैंने हाल ही में एक छोटी सी कक्षा लिखी है ताकि मुझे विंडोज़ सेवा पर वसूली विकल्पों को बदलने में मदद मिल सके (अधिकांश कोड मुझे कहीं ऑनलाइन मिले)। कोड पहले, दूसरे, और बाद की विफलताओं के लिए एक विफलता क्रिया बनाता है। प्रत्येक विफलता ऑब्जेक्ट में एक प्रकार (कोई नहीं, पुनरारंभ, रीबूट, रनकॉमैंड), और मिलीसेकंड में विलंब (int) होता है। इन वस्तुओं को एक संरचना के अंदर पैक किया जाता है और ChangeServiceConfig2 (WinAPI पी/Invoke) में पारित किया जाता है। हालांकि, जब मैं वास्तव में कंसोल पर किसी सेवा पर राइट-क्लिक करता हूं और रिकवरी टैब पर जाता हूं, तो आप सभी असफलताओं (पहले, दूसरे और बाद वाले) के लिए देरी ("फ़ील्ड के बाद सर्वर को पुनरारंभ करें) सेट कर सकते हैं। जब मैं इसे प्रोग्रामेटिक रूप से सेट करता हूं, तो यह पहली विफलता से देरी लेता है और अन्य सभी को अनदेखा करता है। क्या किसी को पता है कि यह मामला क्यों है? हमें केवल विफलता ऑब्जेक्ट ऑब्जेक्ट्स के लिए देरी मूल्य में क्यों गुजरना पड़ता है जब केवल पहला उपयोग किया जाता है? क्या मैं कुछ गलत समझ रहा हूँ?विंडोज सेवाओं पर रिकवरी विकल्प सेट करना

इसके अलावा, dwResetPeriod/"रीसेट विफल गिनती" को कोई प्रभाव नहीं लग रहा है।

कोड:

public class ServiceConfigurator 
{ 
    private const int SERVICE_ALL_ACCESS = 0xF01FF; 
    private const int SC_MANAGER_ALL_ACCESS = 0xF003F; 
    private const int SERVICE_CONFIG_DESCRIPTION = 0x1; 
    private const int SERVICE_CONFIG_FAILURE_ACTIONS = 0x2; 
    private const int SERVICE_NO_CHANGE = -1; 
    private const int ERROR_ACCESS_DENIED = 5; 

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] 
    private struct SERVICE_FAILURE_ACTIONS 
    { 
     public int dwResetPeriod; 
     [MarshalAs(UnmanagedType.LPWStr)] 
     public string lpRebootMsg; 
     [MarshalAs(UnmanagedType.LPWStr)] 
     public string lpCommand; 
     public int cActions; 
     public IntPtr lpsaActions; 
    } 

    [DllImport("advapi32.dll", EntryPoint = "ChangeServiceConfig2")] 
    private static extern bool ChangeServiceFailureActions(IntPtr hService, int dwInfoLevel, [MarshalAs(UnmanagedType.Struct)] ref SERVICE_FAILURE_ACTIONS lpInfo); 
    [DllImport("advapi32.dll", EntryPoint = "ChangeServiceConfig2")] 
    private static extern bool ChangeServiceDescription(IntPtr hService, int dwInfoLevel, [MarshalAs(UnmanagedType.Struct)] ref SERVICE_DESCRIPTION lpInfo); 

    [DllImport("kernel32.dll")] 
    private static extern int GetLastError(); 

    private IntPtr _ServiceHandle; 
    public IntPtr ServiceHandle { get { return _ServiceHandle; } } 

    public ServiceConfigurator(ServiceController svcController) 
    { 
     this._ServiceHandle = svcController.ServiceHandle.DangerousGetHandle(); 
    } 

    public void SetRecoveryOptions(FailureAction pFirstFailure, FailureAction pSecondFailure, FailureAction pSubsequentFailures, int pDaysToResetFailureCount = 0) 
    { 
     int NUM_ACTIONS = 3; 
     int[] arrActions = new int[NUM_ACTIONS * 2]; 
     int index = 0; 
     arrActions[index++] = (int)pFirstFailure.Type; 
     arrActions[index++] = pFirstFailure.Delay; 
     arrActions[index++] = (int)pSecondFailure.Type; 
     arrActions[index++] = pSecondFailure.Delay; 
     arrActions[index++] = (int)pSubsequentFailures.Type; 
     arrActions[index++] = pSubsequentFailures.Delay; 

     IntPtr tmpBuff = Marshal.AllocHGlobal(NUM_ACTIONS * 8); 

     try 
     { 
      Marshal.Copy(arrActions, 0, tmpBuff, NUM_ACTIONS * 2); 
      SERVICE_FAILURE_ACTIONS sfa = new SERVICE_FAILURE_ACTIONS(); 
      sfa.cActions = 3; 
      sfa.dwResetPeriod = pDaysToResetFailureCount; 
      sfa.lpCommand = null; 
      sfa.lpRebootMsg = null; 
      sfa.lpsaActions = new IntPtr(tmpBuff.ToInt32()); 

      bool success = ChangeServiceFailureActions(_ServiceHandle, SERVICE_CONFIG_FAILURE_ACTIONS, ref sfa); 
      if(!success) 
      { 
       if(GetLastError() == ERROR_ACCESS_DENIED) 
        throw new Exception("Access denied while setting failure actions."); 
       else 
        throw new Exception("Unknown error while setting failure actions."); 
      } 
     } 
     finally 
     { 
      Marshal.FreeHGlobal(tmpBuff); 
      tmpBuff = IntPtr.Zero; 
     } 
    } 
} 

ट्रेवर

+0

कारण है कि यह केवल मैं यह सोचते कर रहा हूँ कि माइक्रोसॉफ्ट प्रत्येक विफलता कार्रवाई के लिए एक अंतर देरी लागू नहीं किया लेता है केवल पहले पर अपने प्रश्न के लिए।केवल पहले इस्तेमाल किए जाने के बावजूद प्रत्येक विफलता के लिए एक संरचना प्रकार का उपयोग करना संभव था। साथ ही, सेवा प्रबंधक विंडो में रिकवरी टैब में केवल "बाद में सेवा पुनरारंभ करें" के लिए एक प्रविष्टि है, इसलिए ऐसा लगता है कि विंडोज़ वर्तमान में केवल पहले पर ध्यान देना चाहता है। एचटीएच – Jose

+0

@ थ्रेड, इस कोड में FailureAction – user626528

+0

@ user626528 की परिभाषा गुम है: मुझे डर है कि अब मुझे कोड तक पहुंच नहीं है (अब मैं एक अलग कंपनी के साथ हूं)। लेकिन जहां तक ​​मुझे याद है, 'विफलता' वर्ग अनिवार्य रूप से आप उदाहरण कोड में देखते हैं, एक वर्ग जिसमें दो गुण होते हैं: 'टाइप' और' देरी '। – Trevor

उत्तर

1

मैं ने पाया है कि जीत 7 के सभी जायके कुछ सेवाओं तक कि जब विफलता पर उनके पुनः आरंभ हाँ करने के लिए सेट कर दिया जाता पुनः आरंभ करने की कोई क्षमता है।

मैंने स्टार्ट और स्टॉप स्टेटस के साथ-साथ (हेरिस्टिक्स व्युत्पन्न) प्रतिक्रिया की निगरानी करने के लिए एक सेवा लिखना समाप्त कर दिया (उदाहरण के लिए लटका नहीं लटका)। क्या आप यहां पोस्ट किए गए सेवा कोड को पसंद करेंगे?

संपादित करें: जोड़ा गया कोड

ठीक है, निम्नलिखित सेवा कोड मैं करने के लिए भेजा है। ध्यान रखें:

  • यह कोड लॉगिंग के लिए "सी: \ appMon" को इंगित करने के लिए डिज़ाइन किया गया है, और cpu उपयोग। मान्यताओं की सीमा रेखा।
  • यह कोड बदसूरत है कि जब मैं अन्य प्राथमिकताओं के साथ झुका हुआ था, तो यह क्रैंक हो गया था - नतीजतन, इसे किसी भी प्रकार की सेवाओं, उपयोगकर्ता परिभाषित लॉग और सीएफजी पथ इत्यादि को संभालने के लिए फिर से लिखा जा सकता है।
  • सेवा यह कुख्यात विंडोज स्पूलर (spoolsv.exe) के लिए लिखा गया था।

सेवा स्थापित करने के लिए, एमएस से installutil.exe का उपयोग करें। सुनिश्चित करें कि सेवा "स्थानीय सिस्टम खाता" के रूप में चलती है या यह सेवाओं को शुरू/बंद करने में सक्षम नहीं होगी।

appMon.cs:

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Diagnostics; 
using System.ServiceProcess; 
using System.Text; 
using System.Timers; 
using System.Windows.Forms; 
using System.IO; 
using System.Net.Mail; 
using System.Threading; 
using System.Management; 

namespace appMon 
{ 
    public class appMon : ServiceBase 
    { 
     public const string serviceName = "appMon";  
     public appMon() 
     { 
      InitializeComponent();   
     }  
     private void InitializeComponent() 
     { 
      this.ServiceName = serviceName;   
     }  
     /// <summary> 
     /// Clean up any resources being used. 
     /// </summary> 
     protected override void Dispose(bool disposing) 
     { 
      // free instantiated object resources not handled by garbage collector 
      base.Dispose(disposing); 
     } 
     public static string getCurrUser() 
     {// gets the owner of explorer.exe/UI to determine current logged in user 
      String User = String.Empty; 
      String Domain = String.Empty; 
      String OwnerSID = String.Empty; 
      string processname = String.Empty; 
      int PID = Process.GetProcessesByName("explorer")[0].Id; 
      ObjectQuery sq = new ObjectQuery 
       ("Select * from Win32_Process Where ProcessID = '" + PID + "'"); 
      ManagementObjectSearcher searcher = new ManagementObjectSearcher(sq);    
      foreach (ManagementObject oReturn in searcher.Get()) 
      { 
       string[] o = new String[2]; 
       oReturn.InvokeMethod("GetOwner", (object[])o); 
       User = o[0]; 
       System.IO.StreamWriter sr = new System.IO.StreamWriter(@"C:\user.txt"); 
       sr.WriteLine("\\" + o[2] + "\\" + o[1] + "\\" + o[0]); 
       return User; 
      } 
      return User; 
     } 
     public static int readConfigFile() 
     { 
      int cputime = 5; // 5 min dflt 
      try 
      { 
       string readcfg; 
       readcfg = File.ReadAllText(@"c:\appMon\cpuUtilization.txt"); 
       cputime = Convert.ToInt16(readcfg); 
       return cputime; 
      } 
      catch (Exception e) 
      { 
       MessageBox.Show(e.ToString()); 
       return cputime; // 5 min dflt 
      } 
     } 
     public static void logEvents(bool spoolerHang, bool appHang, string msg) 
     { 
      try 
      { 
       StreamWriter sw; 
       sw = File.AppendText(@"c:\appMon\appMonLog.txt"); 
       sw.WriteLine(@"appMon spoolsv.exe event: " + "," + System.Environment.MachineName + "," + System.DateTime.Now + "," + msg); 
       sw.Close(); 
      } 
      catch (Exception e) 
      { 
       MessageBox.Show(e.ToString()); 
      } 
     } 
     /// <summary> 
     /// Start this service. 
     /// </summary> 
     protected override void OnStart(string[] args) 
     {// upon appMon load, a polling interval is set (in milliseconds 1000 ms = 1 s) 
      System.Timers.Timer pollTimer = new System.Timers.Timer(); 
      pollTimer.Elapsed += new ElapsedEventHandler(pollTimer_Elapsed); 
      pollTimer.Interval = 20000; // 20 sec 
      pollTimer.Enabled = true; 
     } 
     public static void StartService(string serviceName, int timeoutMilliseconds) 
     { 
      ServiceController service = new ServiceController(serviceName); 
      try 
      { 
       TimeSpan timeout = TimeSpan.FromMilliseconds(timeoutMilliseconds); 
       if (service.Status == ServiceControllerStatus.Stopped) // if service is not running... 
       { 
        service.Start(); // ...start the service 
       } 
      } 
      catch(Exception e) 
      { 
       MessageBox.Show(e.ToString()); 
      } 
     } 
     public static void StopService(string serviceName, int timeoutMilliseconds) 
     { 
      ServiceController service = new ServiceController(serviceName); 
      try 
      { 
       TimeSpan timeout = TimeSpan.FromMilliseconds(timeoutMilliseconds); 
       if (service.Status == ServiceControllerStatus.Running) // if service is running... 
       { 
        service.Stop(); //...stop the service 
       } 
       service.WaitForStatus(ServiceControllerStatus.Stopped, timeout); 
      } 
      catch (Exception e) 
      { 
       MessageBox.Show(e.ToString()); 
      } 
     } 
     public static void delFiles(string path) 
     { 
      string[] filePaths = Directory.GetFiles(path); 
      foreach (string filePath in filePaths) 
      { 
       try 
       { 
        File.Delete(filePath); 
       } 
       catch (Exception e) 
       { 
        // TODO: !log to file instead! 
        MessageBox.Show("error deleting files: " + e.ToString()); 
       } 
      } 
     } 
     public static void getServiceInfo(string serviceName) 
     { 
      ServiceController service = new ServiceController(serviceName); 
      ServiceController[] depServices = service.ServicesDependedOn; 
      List<string> depServicesList = new List<string>(); 
      foreach (ServiceController sc in depServices) 
      { 
       depServicesList.Add(sc.ServicesDependedOn.ToString()); 
       logEvents(false, false, sc.ServicesDependedOn.ToString()); 
      } 

     } 
     void pollTimer_Elapsed(object sender, ElapsedEventArgs e) 
     {// polling interval has elapsed    
      getServiceInfo("spooler"); 
      ServiceController serviceSpooler = new ServiceController("spooler"); 
      if (serviceSpooler.Status == ServiceControllerStatus.Stopped) 
      { 
       logEvents(true, false, "Print Spooler is: " + serviceSpooler.Status.ToString()); 
       serviceSpooler.Refresh(); 
       serviceSpooler.Start(); 
       logEvents(true, false, "Print Spooler is: " + serviceSpooler.Status.ToString()); 
      }    
      int cputime = readConfigFile(); 
      // get active processes (exe's, including services) 
      Process[] processlist = Process.GetProcesses(); 
      // iterate through process list 
      foreach (Process theprocess in processlist) 
      { 
       // assign local variable to iterator - cures the foreach "gotcha" 
       Process p = theprocess; 
       if (p.ProcessName == "spoolsv") // "spoolsv" = windows name for spoolsv.exe aka "spooler" 
       { 
        if (p.TotalProcessorTime.Minutes > cputime) // has current spooler thread occupied >= cputime # mins of CPU time? 
        { 
         logEvents(true, false, "spoolsv.exe CPU time (mins): " + p.TotalProcessorTime.Minutes.ToString()); 
         p.Refresh(); 
         StopService("spooler", 0); 
         StartService("spooler", 0); 
        } 
       } 
      } 
     } 
     /// <summary> 
     /// Stop this service. 
     /// </summary> 
     /// 
     protected override void OnStop() 
     { 
     } 
    } 
} 
+0

यकीन है, यह बहुत अच्छा होगा! – Trevor

+3

@negEntropy: स्टैक ओवरफ़्लो में आपका स्वागत है! कृपया, अगर आप मौजूदा उत्तर में कुछ जोड़ना चाहते हैं, या किसी बिंदु को स्पष्ट करना चाहते हैं, तो अतिरिक्त उत्तरों न खोलें। अपने मौजूदा उत्तर को संपादित करने के लिए संपादन सुविधा का उपयोग करें। कृपया इस पोस्ट का संदर्भ लें: http://meta.stackexchange.com/questions/25209/what-is-the-official-etiquette-on-answering-a-question-twice –

17

अनुसूचित जाति आदेश सेवा प्रबंधन को स्वचालित के लिए एक शानदार तरीका प्रदान करता है। कोड से कॉल करने के लिए बस Process.Start("sc", "args") करें और यदि आप परिणाम प्राप्त करना चाहते हैं तो आउटपुट को रीडायरेक्ट करें।

यह एक पंक्ति सेवा को 1 मिनट प्रतीक्षा करने के बाद दो बार पुनरारंभ करने के लिए कहती है। विफलता पर एक दिन के बाद यह विफलता गिनती को रीसेट करता है। आप बाद की असफलताओं पर प्रोग्राम चलाने के लिए इसे भी सेट अप कर सकते हैं।

sc failure myservice reset= 86400 actions= restart/60000/restart/60000// 

http://technet.microsoft.com/en-us/library/cc742019(v=ws.10).aspx

+3

यदि आप इसे कॉल करने जा रहे हैं इंस्टॉलर [] सेवा सी # में हैंडलर स्थापित करें, आप इस कॉल को कॉमरेड इवेंट हैंडलर में डाल सकते हैं जो सर्विस मैनेजर में सेवा के बाद इसे निष्पादित करेगा। इसे "AfterInstall" ईवेंट मैनेजर में न डालें, क्योंकि यह बॉक्स पर सेवा पहली बार स्थापित होने पर काम नहीं करेगा। – Contango

संबंधित मुद्दे