c# mono get cpu usage of threads - c#

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);
}
}
}

Related

Title: C# File.Exist returning false when file can be read from/written to

Development Environment: .Net Framework 4.7.2 using VS 2022 on Win 10 Pro x64
Preface: I've reviewed the two similar questions I found at SO; the first deals with permissions and the second with restrictions on using the root directory. Neither contained info that enabled me to resolve my issue.
I'm working on a C# winforms app which uses a SQLite database. I recently discovered "PRAGMA integrity_check" will create an empty DB and return “ok” if the target DB file is missing so I need to ensure the file’s not gone missing before executing the PRAGMA. My simple solution is to wrap integrity_check in an IF (File.Exist) ELSE but the Exist method is returning ”false”.
In MSDN documentation there 7 stated reasons why a false might be returned in addition to the file actually not existing (listed to avoid the need to follow a link):
path is null
path is invalid
path exceeds maximum length (260)
path is a zero-length string
path has invalid characters
storage media is failing/missing
caller has insufficient permissions to read the specified file
My operating assumption is none of those are the root cause since I can read from and write to the DB programmatically in the app.
Code building the path:
namespace BURS_Library
{
public class MISC
{
public const string DBName = "BURS.db";
}
}
using System;
using System.IO;
using System.Reflection;
using System.Text;
using System.Windows.Forms;
namespace BURS_Library
{
public class BURS_Path
{
public static string AppData()
{
string userAppDataDir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
userAppDataDir = userAppDataDir.Replace("Roaming", "LocalLow");
if ( ! Directory.Exists(Path.Combine(userAppDataDir, "BURS_Data_tst")))
{
// display error MessageBox
Environment.Exit(1);
}
return Path.Combine(userAppDataDir, "BURS_Data_tst");
}
public static string DB()
{
return Path.Combine(AppData(), MISC.DBName);
}
{
}
Resultant path: C:\Users\Art\AppData\LocalLow\BURS_Data_tst\BURS.db
Code with File.Exist
using _Library;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Windows.Forms;
namespace BURS_UI
{
public static class Program
{
[STAThread]
public static void Main(string[] tsArgs)
{
if (File.Exists(BURS_Path.DB()))
{
// perform db Integrity Check
}
else
{
// display error MessageBox
Environment.Exit(2);
}
BURS_Connections.SetConnection(BURS_Path.DB());
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Discover());
}
}
}
If my operating assumption is valid why is File.Exist returning false?
Thank you for your time & expertise.
Following #BentTranberg's suggestion a test was run using the following code (in case its useful to somebody):
if (Directory.Exists(#"C:\Users"))
Save2Log(#"FOUND: C:\Users", true);
if (Directory.Exists(#"C:\Users\Art"))
Save2Log(#"FOUND: C:\Users\Art", true);
if (Directory.Exists(#"C:\Users\Art\AppData"))
Save2Log(#"FOUND: C:\Users\Art\AppData", true);
if (Directory.Exists(#"C:\Users\Art\AppData\LocalLow"))
Save2Log(#"FOUND: C:\Users\Art\AppData\LocalLow", true);
if (Directory.Exists(#"C:\Users\Art\AppData\LocalLow\BURS_Data_tst"))
Save2Log(#"FOUND: C:\Users\Art\AppData\LocalLow\BURS_Data_tst", true);
if (File.Exists(#"C:\Users\Art\AppData\LocalLow\BURS_Data_tst\BURS.db"))
Save2Log(#"FOUND: C:\Users\Art\AppData\LocalLow\BURS_Data_tst\BURS.db", true);
Save2Log($"METHOD: {BURS_Path.DB()}", true);
Which produced the following result:
FOUND: C:\Users
FOUND: C:\Users\Art
FOUND: C:\Users\Art\AppData
FOUND: C:\Users\Art\AppData\LocalLow
FOUND: C:\Users\Art\AppData\LocalLow\BURS_Data_tst
FOUND: C:\Users\Art\AppData\LocalLow\BURS_Data_tst\BURS.db
METHOD: C:\Users\Art\AppData\LocalLow\BURS_Data_tst\BURS.db
Next I reran my original code which surprisingly now worked as expected. To validate that result I ran more test:
int existFail = 0;
for (int i = 0; i < 10000; i++)
{
if ( ! File.Exists(BURS_Path.DB())) existFail++;
}
Save2Log($"number of exist fail in 10,000 = {existFail}", true);
I did that 5 times and in 50,000 iterations there were zero incorrect returns. At this point the error has not been reproduced.
My computer was shut down over night which may have impacted the findings. I will rerun this each morning for the next 3 days and post the results as an edit.

Autocad & System.Addin, FileNotFoundException for Autocads basic dlls

i just started to develop applications for AutoCAD 2016. I want to load my dLLs into a separate AppDomain, so that i don't have to restart ACAD all the time.
After a lot of research and trying i ended up with a pipeline solution
using System.Addin and System.Addin.Contract.
I use only interfaces and standardclasses for the Views Contract and Adapters like in this example here.
This is my addin containing one methode to write Hello into Acad's Editor and a second methode for drawing a line.
using System.AddIn;
using CADAddinView;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
namespace CADAddIn
{
[AddIn("cadAddIn", Version = "1.0.0.0")]
public class CADAddIn : ICADAddinView
{
public void drawLine()
{
Document acDoc = Autodesk.AutoCAD.ApplicationServices.Core.Application.DocumentManager.MdiActiveDocument;
Database acCurDb = acDoc.Database;
using (DocumentLock acLckDoc = acDoc.LockDocument())
{
using (Transaction acTrans = acCurDb.TransactionManager.StartTransaction())
{
DBObject blkTbl = acTrans.GetObject(acCurDb.BlockTableId, OpenMode.ForRead);
BlockTable acBlkTbl = blkTbl as BlockTable;
BlockTableRecord acBlkTblRec = (BlockTableRecord)acTrans.GetObject(acBlkTbl[BlockTableRecord.ModelSpace], OpenMode.ForWrite);
Polyline acPoly = new Polyline();
acPoly.SetDatabaseDefaults();
acPoly.AddVertexAt(0, new Point2d(0, 0), 0, 0, 0);
acPoly.AddVertexAt(0, new Point2d(100, 100), 0, 0, 0);
acBlkTblRec.AppendEntity(acPoly);
acTrans.AddNewlyCreatedDBObject(acPoly, true);
acTrans.Commit();
}
}
}
public void sayHello()
{
Editor ed = Autodesk.AutoCAD.ApplicationServices.Core.Application.DocumentManager.MdiActiveDocument.Editor;
ed.WriteMessage("Hello");
}
}
}
this is my HostApplication:
using System.AddIn.Hosting;
using System.Windows.Forms;
using CADHostView;
using System;
using System.Collections.ObjectModel;
using Autodesk.AutoCAD.Runtime;
namespace CADHost
{
public class CADHost
{
[CommandMethod("sayHello")]
public static void sayHello()
{
string addInPath = Environment.CurrentDirectory + "\\Pipeline";
string[] warnings = AddInStore.Update(addInPath);
foreach (string warning in warnings)
{
MessageBox.Show(warning);
}
Collection<AddInToken> tokens = AddInStore.FindAddIns(typeof(ICADHostView), addInPath);
if (tokens.Count == 0)
{
MessageBox.Show("No AddIn found.");
}
else
{
AddInToken cadToken = tokens[0];
ICADHostView cadApp = cadToken.Activate<ICADHostView>(AddInSecurityLevel.Host);
cadApp.sayHello();
}
}
[CommandMethod("drawLine")]
public static void drawLine()
{
string addInPath = Environment.CurrentDirectory + "\\Pipeline";
string[] warnings = AddInStore.Update(addInPath);
foreach (string warning in warnings)
{
MessageBox.Show(warning);
}
Collection<AddInToken> tokens = AddInStore.FindAddIns(typeof(ICADHostView), addInPath);
if (tokens.Count == 0)
{
MessageBox.Show("No AddIn found.");
}
else
{
AddInToken cadToken = tokens[0];
ICADHostView cadApp = cadToken.Activate<ICADHostView>(AddInSecurityLevel.Host);
cadApp.drawLine();
}
}
}
}
Both of the two applications reference to three standard-Dlls from Acad:
accoremgd.dll, acdbmgd.dll, acmgd.dll.
In both projects these dlls have the option local copy false.
If i start then i get an Exception, where the programm cannot find the file "accoremgd.dll" and Acad crashes.
So i tried to set the Option local copy true only for the Addin.
Now it works for the "sayHello"-Methode.
but i get an invalide cast exception when acBlkTbl is initialised.
Would be great if someone has the last steps for me to make this work.
Also great would be a working example must not be made with the Addinsystem
i only want to make this work for not restarting acad all the time^^
Thank you for your help
matthias
I don't believe a separate AppDomain will work, when you call AutoCAD object types it will go to the main AppDomain and get messed up...
As just want to edit your code and don't restart, you'll be better with Edit & Continue feature (available since VC2013 on AutoCAD 2015, I believe).
This is not supported. AutoCAD is a very old and complex program and most of the AutoCAD API objects cannot be used in remote fashion.
Please read:
http://through-the-interface.typepad.com/through_the_interface/2008/09/tired-of-not-be.html
http://forums.autodesk.com/t5/net/netload-is-there-a-net-unload-command/td-p/2404002
https://www.theswamp.org/index.php?topic=38675.0
In the #3, you can see that the AutoCAD development team confirmed that there are some global variables which will prevent working this way.
I gave up my tries to solve this problem. My current "best" solution is to load dlls at the start of AutoCAD. At least i don't have to netload every dll.
If someone has a better solution feel free to tell me^^ Thanks to all that answered. matthias

Determine whether assembly is a gui application

I am trying to determine whether a C# assembly is a GUI or a Console application in order to build a tool which will automatically recreate lost short cuts.
Currently, I have a routine which recursively steps all directories in Program Files (and the x86 directory).
For each EXE it finds, the tool calls IsGuiApplication, passing the name of the EXE.
From there, I create an Assembly object using LoadFrom.
I want to check whether this assembly is has a GUI output, but I'm unsure how to test this in C#.
My current idea is to use GetStdHandle, but I'm not sure how to apply this to an assembly outside of the running application.
My experience with reflection in C# is limited, so any help would be appreciated.
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace BatchShortcutBuild
{
class Program
{
//I'm uncertain that I need to use this method
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr GetStdHandle(int nStdHandle);
static void Main(string[] args) {
BuildShortcuts();
Console.ReadLine();
}
public static void BuildShortcuts() {
String dirRoot = "C:\\Program Files\\";
processRoot(dirRoot);
dirRoot = "C:\\Program Files (x86)\\";
processRoot(dirRoot);
Console.WriteLine("Finished enumerating files");
Console.ReadLine();
}
public static void processRoot(String path) {
try {
foreach (String theDir in Directory.EnumerateDirectories(path)) {
processRoot(theDir);
}
foreach (String theFile in Directory.EnumerateFiles(path, "*.exe")) {
if (IsGuiApplication(theFile)) {
//I would generate a shortcut here
}
}
} catch { }
}
public static bool IsGuiApplication(String filePath) {
Console.WriteLine(filePath);
Assembly a = Assembly.LoadFrom(filePath);
//How to get the program type from the assembly?
return false;
}
}
}
Just to be safe here, the method suggested by #Killany and #Nissim suggest is not 100% accurate, as console applications can reference the System.Windows.* dlls (either by mistake or by a need of other functionality given by the 'System.Windows' assembly).
I'm not sure a 100% method exist, as some applications can be given a parameter to run with/without ui (i.e. silently)
As several times mentioned before, you can read the Subsystem Field.
private PEFileKinds GetFileType(string inFilename)
{
using (var fs = new FileStream(inFilename, FileMode.Open, FileAccess.Read))
{
var buffer = new byte[4];
fs.Seek(0x3C, SeekOrigin.Begin);
fs.Read(buffer, 0, 4);
var peoffset = BitConverter.ToUInt32(buffer, 0);
fs.Seek(peoffset + 0x5C, SeekOrigin.Begin);
fs.Read(buffer, 0, 1);
if (buffer[0] == 3)
{
return PEFileKinds.ConsoleApplication;
}
else if (buffer[0] == 2)
{
return PEFileKinds.WindowApplication;
}
else
{
return PEFileKinds.Dll;
}
}
}
Use GetReferencedAssemblies() to get all referenced assemblies and look for the system.windows.forms assembly
AssemblyName[] referencedAssemblies = assm.GetReferencedAssemblies();
foreach (var assmName in referencedAssemblies)
{
if (assmName.Name.StartsWith("System.Windows"))
//bingo
}
A basic idea to detect GUI apps is that GUI apps always use assembly System.Windows.*.
bool isGui(Assembly exeAsm) {
foreach (var asm in exeAsm.GetReferencedAssemblies()) {
if (asm.FullName.Contains("System.Windows"))
return true;
}
return false;
}
This will detect all .NET applications that are windows forms, or even WPF
One thing you could check is the .subsystem of the file's PE header. If you open up the file in ILDASM and check the manifest, you'll see this if it uses the Windows GUI subsystem:
I don't think there's any method in the Assembly class to check this, so you'll probably need to check the file itself.
Another way to check would be to go through the types in the assembly and see if any of them derive from System.Windows.Forms.Form (Windows Forms) or System.Windows.Window (WPF):
private static bool HasGui(Assembly a)
{
return a.DefinedTypes
.Any(t => typeof(System.Windows.Forms.Form).IsAssignableFrom(t) ||
typeof(System.Windows.Window).IsAssignableFrom(t));
}
Note that you'll need to add references to System.Windows.Forms.dll and PresentationFramework.dll to gain access to these types.
You can use Assembly.LoadFrom(string) to load the assembly. I tested this method myself and it seemed a bit slow so perhaps you can make it faster by involving Parallel.ForEach.

Find out battery charge capacity in percentage using C# or .NET

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);
}

How to determine Windows.Diagnostics.Process from ServiceController

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);
}
}
}

Categories

Resources