📜 ⬆️ ⬇️

Windows service. Search for system errors and display them in WinForm C #

In this article we will analyze how to create an application from scratch that will work with windows services and display system errors in WinForm (C #).

Plan for this article:


Service creation


Open Visual Studio. Next File → New → Project → (Windows Desktop) → Windows Service (.Net Framework) → Ok.
')
Next you need to create an installer. In the window that opens, right-click and select "Add Installer". You will create a "ProjectInstaller.cs [Design]" after which you will need to go to the code "F7" or PCM "View Code". You need to find the line "InitializeComponent ();", put the cursor on it and press "F12", then you need to add the following lines:

this.serviceProcessInstaller1.Account = System.ServiceProcess.ServiceAccount.LocalSystem; //       this.serviceInstaller1.Description = "Show me system error."; //       this.serviceInstaller1.DisplayName = "GetSystemError"; //        

But you need to add these lines only in the following sequence and place. Otherwise there will be an error when installing the service.



Event viewer


This is necessary to verify the correct operation of our program.

Event Viewer - a program for viewing the event log that is on each computer with windows. Each program that runs on a computer publishes a notification in the event log before it stops. Any system access, security changes, operating system tweaks, hardware failures and driver crashes all fall into the event log. The Event Viewer scans text log files, merges them and puts them into the interface.

How to open it? - Start → Event Viewer (in search) → “View event logs”.

Further “Custom Views” → “Administrative Events”. Here we can see all the errors, warnings and information about them.

There are 3 types of log: application (Application), system (System) and security (Security). We need only the system (System).

Service code


Find the .cs file with the name of the service, I have this "Service1.cs", open it. The file must have prepared 2 overridden methods:


There are also a few more methods, but we will not need them now. You can find them yourself.

The data that we receive will be stored in an updated text file, so we add

 using System.IO; 

Add the code to the OnStart (string [] args) method:

 EventLog myLog; //       string filepath = AppDomain.CurrentDomain.BaseDirectory + @"\ServiceLog.txt";; //    List<string> list; //    protected override void OnStart(string[] args) { myLog = new EventLog(); myLog.Log = "System"; //     - (Application),    (System). myLog.Source = "System Error"; for (int index = myLog.Entries.Count - 1; index > 0; index--) //         { var errEntry = myLog.Entries[index]; \\     if (errEntry.EntryType == EventLogEntryType.Error) \\    { //     var appName = errEntry.Source; list = new List<string>(); list.Add("Entry Type: " + Convert.ToString(errEntry.EntryType)); list.Add("Event log: " + (string)myLog.Log); list.Add("Machine Name: " + (string)errEntry.MachineName); list.Add("App Name: " + (string)errEntry.Source); list.Add("Message: " + (string)errEntry.Message); list.Add("Time Written: " + errEntry.TimeWritten.ToString()); list.Add("-*-"); WriteToFile(list); //    } } } public void WriteToFile(List<string> list) //   { using (StreamWriter sw = File.AppendText(filepath)) { for (int i = 0; i < list.Count; i++) sw.WriteLine(list[i]); } } 

Next you need to build the solution “Solution” -> “Rebuild Solution”. After successful assembly, you can check the work.

Check service operation (start service manually)


The windows service cannot be started as a normal application. You can run only through the command line as an administrator.

Run the command prompt as administrator. Enter the following commands:

 cd C:\Windows\Microsoft.NET\Framework\v4.0.30319 InstallUtil.exe \  .exe (InstallUtil.exe C:\Users\\source\repos\WindowsService1\WindowsService1 \bin\Debug\WindowsService1.exe)    : InstallUtil.exe -u \  .exe 

Next, press the Win + R key. Enter "Services.msc". We find our service in the list, click on it, and click "Start (Start)". After a successful launch, a file is generated according to the path specified in the code, which will contain the list of system errors.
Do not forget to remove the service after verification.

WinForm mapping


For display in the console, if you try, you can find articles, but for display in WinForm I did not find it, so here. By default, a service project is created of type "Application". To display through the console, this parameter in the settings must be changed, for WinForm to leave as is. Next you need to add a form to the project. “WindowsService1” → PCM → Add → Windows Form → Add. And we do about the following design. Next, change the file "Program.cs".

Add using:

 using System.Windows.Forms; using System.Security.Principal; using System.ComponentModel; using System.Diagnostics; 

And change the Main method:

 static void Main(string[] args) { WindowsPrincipal windowsPricipal = new WindowsPrincipal(WindowsIdentity.GetCurrent()); bool hasAdministrativeRight = windowsPricipal.IsInRole(WindowsBuiltInRole.Administrator); if (hasAdministrativeRight == false) //    { ProcessStartInfo processInfo = new ProcessStartInfo(); //   processInfo.Verb = "runas"; //       processInfo.FileName = Application.ExecutablePath; try { Process.Start(processInfo); //   } catch (Win32Exception){} Application.Exit(); } else { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new Form1(args)); //  } } 

Add a new class "SystemError". ("WindowsService1" -> PCM -> Add -> Class -> Add). Here we will store error data. Change it:

 public string EntryType{ get; set; } public string EventLog{ get; set; } public string MachineName { get; set; } public string AppName { get; set; } public string Message { get; set; } public string TimeWritten { get; set; } 

Next in “Service1.cs” add the method “RunFromForm (string [] args)” which starts the service.

 public void RunFromForm(string[] args) { OnStart(args); OnStop(); } 

Add a new class “GetListErrors”. ("WindowsService1" -> PCM -> Add -> Class -> Add). Here we will get the data from the file. Add using:

 using System.IO; 

Change it:

 string filepath = AppDomain.CurrentDomain.BaseDirectory + @"\ServiceLog.txt"; SystemError systemError; public List<SystemError> listSysErrs; public void ReadFile() //          { systemError = new SystemError(); listSysErrs = new List<SystemError>(); using (StreamReader sr = new StreamReader(filepath)) { string line; while ((line = sr.ReadLine()) != null) { if (line.Contains("-*-")) { listSysErrs.Add(systemError); systemError = new SystemError(); //       } if (line.Contains("Entry Type")) { systemError.EntryType = line.Substring(12); } else if (line.Contains("Event log")) { systemError.EventLog = line.Substring(11); } else if (line.Contains("Machine Name")) { systemError.MachineName = line.Substring(14); } else if (line.Contains("App Name")) { systemError.AppName = line.Substring(10); } else if (line.Contains("Message")) { systemError.Message = line.Substring(9); } else if (line.Contains("Time Written")) { systemError.TimeWritten = line.Substring(14); } } } } 

Further we change the code of the form “Form1.cs”. Add using:

 using System.ServiceProcess; using System.Diagnostics; 

Change it:

 Service1 service = new Service1(); List<SystemError> listSysErrs; string[] args; public Form1(string[] args) { InitializeComponent(); this.args = args; if (Environment.UserInteractive)//          { service.RunFromForm(args); //  GetListErrors getListErrors = new GetListErrors(); getListErrors.ReadFile(); //      listSysErrs = getListErrors.listSysErrs; FillDataGridView(); //    } else { ServiceBase[] ServicesToRun; ServicesToRun = new ServiceBase[] { service }; ServiceBase.Run(ServicesToRun); } } public void FillDataGridView() //     { foreach (SystemError item in listSysErrs) { dataGridView1.Rows.Add(item.AppName, item.Message); } } private void dataGridView1_CellClick(object sender, DataGridViewCellEventArgs e) //                { SystemError sys = listSysErrs[dataGridView1.CurrentRow.Index]; label1.Text = "Entry Type: " + sys.EntryType + "\nEvent log: " + sys.EventLog + "\nMachine Name: " + sys.MachineName + "\nApp Name: " + sys.AppName + "\n\nMessage: " + FormatMessage(sys.Message) + "\n\nTime Written: " + sys.TimeWritten; } private string FormatMessage(string msg) //       ,                 { string retMsg = ""; int count = 75; if (msg.Length > count - 9) { retMsg += msg.Substring(0, count - 9) + "\n"; msg = msg.Substring(count - 9); } while (msg.Length > count) { retMsg += msg.Substring(0, count) + "\n"; msg = msg.Substring(count); } retMsg += msg + "\n"; return retMsg; } private void button1_Click(object sender, EventArgs e) //          { if (Environment.UserInteractive) { while (dataGridView1.Rows.Count != 0) { dataGridView1.Rows.Remove(dataGridView1.Rows[dataGridView1.Rows.Count - 1]); } service.RunFromForm(args); GetListErrors getListErrors = new GetListErrors(); getListErrors.ReedFile(); listSysErrs = getListErrors.listSysErrs; FillDataGridView(); } else { ServiceBase[] ServicesToRun; ServicesToRun = new ServiceBase[] { service }; ServiceBase.Run(ServicesToRun); } } private void button2_Click(object sender, EventArgs e) { Process.Start(AppDomain.CurrentDomain.BaseDirectory); //  } 

Now you can start the service as a normal application. The result looks like this:

Source: https://habr.com/ru/post/452688/


All Articles