This is my first post, so let me start by saying HELLO!
I am writing a windows service to monitor the running state of a number of other windows services on the same server. I'd like to extend the application to also print some of the memory statistics of the services, but I'm having trouble working out how to map from a particular ServiceController object to its associated Diagnostics.Process object, which I think I need to determine the memory state.
I found out how to map from a ServiceController to the original image name, but a number of the services I am monitoring are started from the same image, so this won't be enough to determine the Process.
Does anyone know how to get a Process object from a given ServiceController? Perhaps by determining the PID of a service? Or else does anyone have another workaround for this problem?
Many thanks, Alex
System.Management should work for you in this case. Here's a sample to get you started:
using System;
using System.Diagnostics;
using System.ServiceProcess;
using System.Management;
class Program
{
static void Main(string[] args)
{
foreach (ServiceController scTemp in ServiceController.GetServices())
{
if (scTemp.Status == ServiceControllerStatus.Stopped)
continue; // stopped, so no process ID!
ManagementObject service = new ManagementObject(#"Win32_service.Name='" + scTemp.ServiceName + "'");
object o = service.GetPropertyValue("ProcessId");
int processId = (int) ((UInt32) o);
Process process = Process.GetProcessById(processId);
Console.WriteLine("Service: {0}, Process ID: {1}", scTemp.ServiceName, processId);
}
}
}
Related
I have trouble with checking if a process is still running.
I created a small program that should keep 2 programs up and running.
For this example I use Notepad and windows calculator.
The Code below will launch both applications, but its failing on checking their running state by their process.checkalive propert also hasexited fails.
Notice that the sample program uses a class Apprunner to handle multiple applications. After launching both applications it crashes with:
System.InvalidOperationException:
'Process has exited, so the requested information is not available.'
Despite that both programs Notepad.exe and Calc.exe are running.
Code :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Diagnostics;
namespace watchdog
{
class AppRunner
{
public Process Program;
public AppRunner(ProcessStartInfo processrunner)
{
this.Program = new Process();
this.Program.StartInfo = processrunner;
StartExecute();
}
public void StartExecute()
{
this.Program.Start();
}
public bool checkAlive()
{
this.Program.Refresh();
return (bool)this.Program.Responding;
//fails
// also failing as true => return this.Program.HasExited;
//(its not true app still runs)
}
public void KeepEmRunning()
{
if (!checkAlive())
{
StartExecute();
}
}
}
//-----------main prog - - - - -
class Program
{
static void Main(string[] args)
{
List<AppRunner> programs = new List<AppRunner>();
ProcessStartInfo prog = new ProcessStartInfo();
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.FileName = #"C:\Windows\system32\Notepad.exe";
programs.Add(new AppRunner(startInfo));
startInfo.FileName = #"C:\Windows\system32\Calc.exe";
programs.Add(new AppRunner(startInfo));
string s;
do
{
System.Threading.Thread.Sleep(1000);// wait for start.
Console.WriteLine("Notepad" + programs[0].checkAlive());
Console.WriteLine("Calc" + programs[1].checkAlive());
Console.WriteLine("press X for exit other key for update");
s = Console.ReadLine().ToUpper();
} while (s != "X");
}
}
}
Code running on Windows 10, and vs2017 its a .net 4.6 console app.
Process.Responding throws an exception if the process has already exited. I guess Responding's purpose is to check if the process is dead-locked or still working, but doesn't work if the process is gone already.
Calc.exe indeed immediatly returns, after starting Calculator.exe (see TaskManager). So the result you observe is correct: the process you started for calc.exe has already exited, although you still see a calculator window.
Consider next situation. I have injected my managed dll into the process using EasyHook. EasyHook injects dll using separate AppDomain. Now I need a way to get notifications about creation of new AppDomain in the current process.
So the question is there a way do get notifications when a new AppDomain was created in the process?
There is no event or easy way to do it, there is a COM interrupt that allows you to get a list of app domains loaded but any events etc are all hidden from us on private interfaces.
There is two ways you could do this but both require you to actively seek the information i.e. there is no event to register too.
Using Performance Counters.
Using mscoree COM interrupt.
Both there options can complement each other but it depends what level of information you need.
Using Performance Counters
CLR has numerous performance counters available but the one we care about resides in the category ".Net CLR Loading" and it is the counter called "Total Appdomains".
Using the System.Diagnostics namespace you can get the number of app domains per instance/process running in you machine.
Like the code below:
PerformanceCounter toPopulate = new PerformanceCounter(".Net CLR Loading", "Total Appdomains", "ConsoleApplication2.vshost", true);
Console.WriteLine("App domains listed = {0}", toPopulate.NextValue().ToString());
(please note the example needs the application instance name if you create your own app make sure to change this)
You can wrap this on a loop and raise an even for your app when the number changes.
(Not elegant but there is no way around it at the moment)
Using mscoree COM interrupt
Further more if you want to List all the app domains in a process you need to make use the MSCOREE.TBL library which is a COM library used by the CLRHost.
You can find the library at C:\WINDOWS\Microsoft.NET\Framework\vXXXXXX\mscoree.tlb
using mscoree;
If you are using it on window 7 or above you must make sure that the embed assembly type in the reference properties is turned off as this assembly can not be embedded like that.
See further information on this stack post: Interop type cannot be embedded
See the code below to see how you can return and list all app domains in a process (this will return the actual AppDomain instances for each app domain).
The original stack post for this can be found here: List AppDomains in Process
public static List<AppDomain> GetAppDomains()
{
List<AppDomain> _IList = new List<AppDomain>();
IntPtr enumHandle = IntPtr.Zero;
CorRuntimeHostClass host = new mscoree.CorRuntimeHostClass();
try
{
host.EnumDomains(out enumHandle);
object domain = null;
while (true)
{
host.NextDomain(enumHandle, out domain);
if (domain == null) break;
AppDomain appDomain = (AppDomain)domain;
_IList.Add(appDomain);
}
return _IList;
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
return null;
}
finally
{
host.CloseEnum(enumHandle);
Marshal.ReleaseComObject(host);
}
}
Now that you can see how many app domains exist in a process and list them let put that to the test.
Below is a fully working example using both techniques.
using System;
using System.Collections.Generic;
using System.Drawing.Printing;
using System.Linq;
using System.Printing;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Controls;
using System.Windows.Xps.Packaging;
using System.Runtime.InteropServices;
using mscoree;
using System.Diagnostics;
using System.Threading;
namespace ConsoleApplication2
{
class AppDomainWorker
{
public void DoSomeWork()
{
while (true)
{
for (int i = 0; i < 1000; i++)
{
var hello = "hello world".GetHashCode();
}
Thread.Sleep(500);
}
}
}
class Program
{
[STAThread]
static void Main(string[] args)
{
PerformanceCounter toPopulate = new PerformanceCounter(".Net CLR Loading", "Total Appdomains", "ConsoleApplication2.vshost", true);
Console.WriteLine("App domains listed = {0}", toPopulate.NextValue().ToString());
for (int i = 0; i < 10; i++)
{
AppDomain domain = AppDomain.CreateDomain("App Domain " + i);
domain.DoCallBack(() => new Thread(new AppDomainWorker().DoSomeWork).Start());
Console.WriteLine("App domains listed = {0}", toPopulate.NextValue().ToString());
}
Console.WriteLine("List all app domains");
GetAppDomains().ForEach(a => {
Console.WriteLine(a.FriendlyName);
});
Console.WriteLine("running, press any key to stop");
Console.ReadKey();
}
public static List<AppDomain> GetAppDomains()
{
List<AppDomain> _IList = new List<AppDomain>();
IntPtr enumHandle = IntPtr.Zero;
CorRuntimeHostClass host = new mscoree.CorRuntimeHostClass();
try
{
host.EnumDomains(out enumHandle);
object domain = null;
while (true)
{
host.NextDomain(enumHandle, out domain);
if (domain == null) break;
AppDomain appDomain = (AppDomain)domain;
_IList.Add(appDomain);
}
return _IList;
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
return null;
}
finally
{
host.CloseEnum(enumHandle);
Marshal.ReleaseComObject(host);
}
}
}
}
I hope this is helpful and if you need any further help let us know.
How can i get the cpuload of running-threads of my application.
My application runs on linux, mac NOT windows.
I update mono to version 3.0.2.
Now i can get the correct thread-count of "Process.GetCurrentProcess().Threads" but no ProcessThread object is available to read the "TotalProcessorTime"
What can i do to calculate the cpu-usage/threads of my running application?
Can i get the linux-process-id of my running thread? If i can, i can read the proc directory structure but i can't find any way.
I hope someone can help me.
Apparently the Process.Threads property is only partially implemented at the moment:
// This'll return a correctly-sized array of empty ProcessThreads for now.
int error;
return new ProcessThreadCollection(new ProcessThread[GetProcessData (pid, 0, out error)]);
Not sure what trouble you have run into getting the process id, this code seems to work for me:
using System;
using System.Diagnostics;
using System.IO;
class MainClass
{
static void Main(string[] args)
{
int pid = Process.GetCurrentProcess().Id;
DirectoryInfo taskDir = new DirectoryInfo(String.Format("/proc/{0}/task", pid));
foreach(DirectoryInfo threadDir in taskDir.GetDirectories())
{
int tid = Int32.Parse(threadDir.Name);
Console.WriteLine(tid);
}
}
}
I have an application that gets detailed system information, and I have been able to get the percent of charge remaining but not the percent of the battery itself.
Explanation: As time goes on, the battery slowly gets worse and worse, and some applications, like Dell Support Center on Laptops, display the status of the battery, not the status of the charge, which used to be 100% but now is 90%.
How can I get this value in C# or .NET?
Don't have a laptop to test with, but I'm guessing you could use the WMI class Win32_Battery.
It has two fields that look interesting - DesignCapacity, which tells you
Design capacity of the battery in milliwatt-hours.
and FullChargeCapacity, which has the fascinating note that
Full charge capacity of the battery in milliwatt-hours. Comparison of the value to the DesignCapacity property determines when the battery requires replacement.
So my guess is that you can use WMI to read these two values, and then calculate FullChargeCapacity/DesignCapacity to find the battery health percentage number.
EDIT
Here's a brief example of accessing WMI information using C#. I first added a reference to the System.Management assembly. Then:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Management;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
System.Management.ObjectQuery query = new ObjectQuery("Select * FROM Win32_Battery");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(query);
ManagementObjectCollection collection = searcher.Get();
foreach (ManagementObject mo in collection)
{
foreach (PropertyData property in mo.Properties)
{
Console.WriteLine("Property {0}: Value is {1}", property.Name, property.Value);
}
}
}
}
}
Also, note that you are basically running a SQL-like query against WMI, so you can vary that if you want. Windows Management Instrumentation Query Language, or WQL, is what you want to search for to learn more about it.
Also take a look at ahawker's answer, it may end up being more helpful if WMI isn't properly capturing the battery data, as he notes.
It seems that you are looking for the values of FullChargeCapacity, DesignCapacity and CurrentCapacity. As someone who has solved this problem before, let me make a few comments.
The first route normally taken would be through a WMI query (Win32_Battery). However, on the test laptops I ran the WMI query (Win32_Battery) against, which included multiple manufacturers, I consistently ran into the problem of FullChargeCapacity always returning zero. Since that didn't work, I re-wrote my solution using Win32 API and was successfully able to get accurate values that way.
Hopefully, WMI will work for you. However, if you experience the same issues I did, here is a summary of the steps required for Win32API.
Use SetupDiGetClassDevs to get a device handle to the battery (GUID_DEVCLASS_BATTERY).
Use SetupDiEnumDeviceInterfaces to get the device data (SP_DEVICE_INTERFACE_DATA).
Use SetupDiGetDeviceInterfaceDetail to get the device path (SP_DEVICE_INTERFACE_DETAIL_DATA).
Use CreateFile with the device path to get handle to battery.
Use DeviceIoControl with battery handle, IOCTL_BATTERY_QUERY_TAG to retrieve battery query info (BATTERY_QUERY_INFORMATION).
Use DeviceIoControl with battery handle, IOCTL_BATTERY_QUERY_INFORMATION and marshalled structs to to retrieve battery info (BATTERY_INFORMATION).
Also see the Enumerating Battery Devices post on MSDN as I found that quite helpful.
I can post my solution if necessary but with all the native struct definitions, it ends up around 500 lines of code.
Example source code: https://gist.github.com/ahawker/9715872
No need to unnecessary complicate things. Try something like:
using System.Management;
PowerStatus pwr = SystemInformation.PowerStatus;
String strBatteryChargingStatus;
strBatteryChargingStatus = pwr.BatteryChargeStatus.ToString();
MessageBox.Show("battery charge status : " + batterystatus);
String strBatterylife;
strBatterylife = pwr.BatteryLifePercent.ToString();
MessageBox.Show("Battery life: "+batterylife);
In this way you can get all of the battery information.
You can use the System.Windows.Forms.PowerStatus class - http://msdn.microsoft.com/en-us/library/system.windows.forms.powerstatus.aspx
PowerStatus p = SystemInformation.PowerStatus;
int a = (int)(p.BatteryLifePercent * 100);
MessageBox.Show(""+a);
WMI worked for me (tested on 3 notebooks of different brands), but I had to use something like this:
new ManagementObjectSearcher(#"\\localhost\root\wmi",
"Select FullChargedCapacity From BatteryFullChargedCapacity");
// use value of resultingInstance.Properties["FullChargedCapacity"]
new ManagementObjectSearcher(#"\\localhost\root\wmi",
"Select DesignedCapacity From BatteryStaticData");
//use value of resultingInstance2.Properties["DesignedCapacity"]
BatteryChargeStatus.Text = SystemInformation.PowerStatus.BatteryChargeStatus.ToString();
BatteryFullLifetime.Text = SystemInformation.PowerStatus.BatteryFullLifetime.ToString();
BatteryLifePercent.Text = SystemInformation.PowerStatus.BatteryLifePercent.ToString();
BatteryLifeRemaining.Text = SystemInformation.PowerStatus.BatteryLifeRemaining.ToString();
PowerLineStatus.Text = SystemInformation.PowerStatus.PowerLineStatus.ToString();
If you want to perform some operation just convert these string values into the integer.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace batterie
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
showbattrie();
}
private void Form1_Load(object sender, EventArgs e)
{
}
public void showbattrie()
{
PowerStatus status = SystemInformation.PowerStatus;
textBox1.Text = status.BatteryLifePercent.ToString("P0");
}
}
}
Simple code to get Battery Level in C#
protected void batteryLevel ()
{
var filter = new IntentFilter(Intent.ActionBatteryChanged);
var battery = RegisterReceiver(null, filter);
int level = battery.GetIntExtra(BatteryManager.ExtraLevel, -1);
int scale = battery.GetIntExtra(BatteryManager.ExtraScale, -1);
double level_0_to_100 = Math.Floor (level * 100D / scale);
}
I wrote a program in c#
now I would like to know what is the proper way to prevent the program from starting if it is already running?
so if it is already running, and double-click on the program it will not start because it is already running.
I can do that, but I was thinking of a standard and proper way.
The recommended way to do this is with a system mutex.
bool createdNew;
using(var mutex = new System.Threading.Mutex(true, "MyAppName", out createdNew))
{
if (createdNew)
// first instance
Application.Run();
else
MessageBox.Show("There is already an instace running");
}
The first parameter to the Mutex ctor tells it to give create a system wide mutex for this thread. If the Mutex already exists it will return out false through the 3rd parameter.
Update
Where to put this?
I'd put this in program.cs. If you put it in form_load you'll need to keep the mutex for the life time of the application (have the mutex as a member on the form), and manually release it in the form unload.
The earlier you call this the better, before the other app opens DB connections etc. and before resources are put created for forms / controlls etc.
Quick way I did in one of the applications .. You can look at the list of running processes to see whether the current application is already running and not start the application again.
Process[] lprcTestApp = Process.GetProcessesByName("TestApplication");
if (lprcTestApp.Length > 0)
{
// The TestApplication is already running, don't run it again
}
I think enumerating the process list could potentially be slow. You could also create a Mutex using the System.Threading.Mutex class and check to see if it's already created when the process starts. However, this would require calling into Win32 system code so wouldn't be completely platform agnostic.
Take a look at Scotts blog post and don't be foolished by the assembly name. It's just a file name of a standard file in the .Net framework.
Here are more informations direct out of MSDN for the WindowsFormsApplicationBase.
You can use a system-wide Semaphore, using the Semaphore Constructor (Int32, Int32, String, Boolean%) constructor and a fairly unique name.
Cheers, Matthias
If your application produces/consumes files, then you're better registering a system wide communication mechanism (e.g. a remoting or WCF endpoint, or even a socket). Then, if the second instance of the application is being launched from double clicking one of your files, you can send the file information across to the running instance.
Otherwise, if it's a standalone program, then as others have said, a Mutex or Semaphore would server equally well.
solution in Windows form application Prohibit again run application(reopen application).
1- first add Class RunAlready.cs
2-Call method processIsRunning() with Name Process from RunAlready.cs in Program.cs
Program.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Tirage.MainStand
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
PublicClass.Class.RunAlready RunAPP = new PublicClass.Class.RunAlready();
string outApp = RunAPP.processIsRunning("Tirage.MainStand");
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
MainStand_FrmLogin fLogin = new MainStand_FrmLogin();
if (outApp.Length == 0)
{
if (fLogin.ShowDialog() == DialogResult.OK)
{
Application.Run(new MainStand_masterFrm());
}
}
else MessageBox.Show( "Instance already running");
}
}
}
class RunAlready:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace PublicClass.Class
{
public class RunAlready
{
public string processIsRunning(string process)
{
string xdescription = "";
System.Diagnostics.Process[] processes =
System.Diagnostics.Process.GetProcessesByName(process);
foreach (System.Diagnostics.Process proc in processes)
{
var iddd = System.Diagnostics.Process.GetCurrentProcess().Id;
if (proc.Id != System.Diagnostics.Process.GetCurrentProcess().Id)
{
xdescription = "Application Run At time:" + proc.StartTime.ToString() + System.Environment.NewLine;
xdescription += "Current physical memory : " + proc.WorkingSet64.ToString() + System.Environment.NewLine;
xdescription += "Total processor time : " + proc.TotalProcessorTime.ToString() + System.Environment.NewLine;
xdescription += "Virtual memory size : " + proc.VirtualMemorySize64.ToString() + System.Environment.NewLine;
}
}
return xdescription;
}
}
}