mirror of
https://github.com/mirror/processhacker
synced 2026-06-08 16:03:24 +00:00
Tray icon now displays the current CPU usage, and the tooltip is almost exactly the same as Process Explorer's (current CPU usage + process using most of the CPU)
git-svn-id: svn://svn.code.sf.net/p/processhacker/code@433 21ef857c-d57f-4fe0-8362-d861dc6d29cd
This commit is contained in:
@@ -10,6 +10,9 @@ Process Hacker
|
||||
techniques
|
||||
* NEW: Highlighting for UAC elevated processes
|
||||
* NEW: Struct reader (with support for user-defined structs)
|
||||
* NEW: Tray icon now displays the current CPU usage, and the tooltip is almost
|
||||
exactly the same as Process Explorer's (current CPU usage + process using most
|
||||
of the CPU)
|
||||
* FIXED: Shows SIDs without names in SDDL format
|
||||
* FIXED: Less "Access denied" errors - uses PROCESS_QUERY_LIMITED_INFORMATION
|
||||
on Vista
|
||||
|
||||
@@ -71,6 +71,17 @@ namespace ProcessHacker
|
||||
get { return _pitem.Name; }
|
||||
}
|
||||
|
||||
public string DisplayPID
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_pitem.PID >= 0)
|
||||
return _pitem.PID.ToString();
|
||||
else
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
public int PID
|
||||
{
|
||||
get { return _pitem.PID; }
|
||||
@@ -88,7 +99,13 @@ namespace ProcessHacker
|
||||
|
||||
public string CPU
|
||||
{
|
||||
get { return _pitem.CPUUsage.ToString("F2"); }
|
||||
get
|
||||
{
|
||||
if (_pitem.CPUUsage == 0)
|
||||
return "";
|
||||
else
|
||||
return _pitem.CPUUsage.ToString("F2");
|
||||
}
|
||||
}
|
||||
|
||||
private string GetBestUsername(string username, bool includeDomain)
|
||||
|
||||
@@ -135,7 +135,7 @@
|
||||
//
|
||||
// nodePID
|
||||
//
|
||||
this.nodePID.DataPropertyName = "PID";
|
||||
this.nodePID.DataPropertyName = "DisplayPID";
|
||||
this.nodePID.EditEnabled = false;
|
||||
this.nodePID.IncrementalSearchEnabled = true;
|
||||
this.nodePID.LeftMargin = 3;
|
||||
|
||||
@@ -48,6 +48,8 @@ namespace ProcessHacker
|
||||
ProcessSystemProvider processP = new ProcessSystemProvider();
|
||||
ServiceProvider serviceP = new ServiceProvider();
|
||||
|
||||
UsageIcon cpuUsageIcon = new UsageIcon(16, 16);
|
||||
|
||||
Dictionary<int, List<string>> processServices = new Dictionary<int, List<string>>();
|
||||
|
||||
int processSelectedItems;
|
||||
@@ -756,6 +758,22 @@ namespace ProcessHacker
|
||||
|
||||
#region Providers
|
||||
|
||||
private void processP_Updated()
|
||||
{
|
||||
processP.DictionaryAdded += new ProcessSystemProvider.ProviderDictionaryAdded(processP_DictionaryAdded);
|
||||
processP.DictionaryRemoved += new ProcessSystemProvider.ProviderDictionaryRemoved(processP_DictionaryRemoved);
|
||||
processP.Updated -= new ProcessSystemProvider.ProviderUpdateOnce(processP_Updated);
|
||||
|
||||
if (processP.RunCount >= 1)
|
||||
this.Invoke(new MethodInvoker(UpdateCommon));
|
||||
}
|
||||
|
||||
private void processP_IconUpdater()
|
||||
{
|
||||
cpuUsageIcon.Update(processP.CurrentCPUUsage);
|
||||
notifyIcon.Icon = cpuUsageIcon.GetIcon();
|
||||
}
|
||||
|
||||
public void processP_DictionaryAdded(ProcessItem item)
|
||||
{
|
||||
ProcessItem parent = new ProcessItem();
|
||||
@@ -794,6 +812,20 @@ namespace ProcessHacker
|
||||
"The process " + item.Name + " (" + item.PID.ToString() + ") was terminated.", ToolTipIcon.Info);
|
||||
}
|
||||
|
||||
private void serviceP_Updated()
|
||||
{
|
||||
listServices.List.EndUpdate();
|
||||
HighlightedListViewItem.StateHighlighting = true;
|
||||
|
||||
serviceP.DictionaryAdded += new ServiceProvider.ProviderDictionaryAdded(serviceP_DictionaryAdded);
|
||||
serviceP.DictionaryModified += new ServiceProvider.ProviderDictionaryModified(serviceP_DictionaryModified);
|
||||
serviceP.DictionaryRemoved += new ServiceProvider.ProviderDictionaryRemoved(serviceP_DictionaryRemoved);
|
||||
serviceP.Updated -= new ServiceProvider.ProviderUpdateOnce(serviceP_Updated);
|
||||
|
||||
if (processP.RunCount >= 1)
|
||||
this.Invoke(new MethodInvoker(UpdateCommon));
|
||||
}
|
||||
|
||||
public void serviceP_DictionaryAdded(ServiceItem item)
|
||||
{
|
||||
this.QueueMessage("New Service: " + item.Status.ServiceName +
|
||||
@@ -1151,6 +1183,17 @@ namespace ProcessHacker
|
||||
private void timerFire_Tick(object sender, EventArgs e)
|
||||
{
|
||||
UpdateStatusInfo();
|
||||
|
||||
notifyIcon.Text = "Process Hacker\n" +
|
||||
"CPU Usage: " + (processP.CurrentCPUUsage * 100).ToString("F2") + "%";
|
||||
|
||||
try
|
||||
{
|
||||
notifyIcon.Text += "\n" + processP.Dictionary[processP.PIDWithMostCPUUsage].Name +
|
||||
": " + processP.Dictionary[processP.PIDWithMostCPUUsage].CPUUsage.ToString("F2") + "%";
|
||||
}
|
||||
catch
|
||||
{ }
|
||||
}
|
||||
|
||||
private void timerMessages_Tick(object sender, EventArgs e)
|
||||
@@ -1383,30 +1426,6 @@ namespace ProcessHacker
|
||||
((MenuItem)sender).Checked = !((MenuItem)sender).Checked;
|
||||
}
|
||||
|
||||
private void serviceP_Updated()
|
||||
{
|
||||
listServices.List.EndUpdate();
|
||||
HighlightedListViewItem.StateHighlighting = true;
|
||||
|
||||
serviceP.DictionaryAdded += new ServiceProvider.ProviderDictionaryAdded(serviceP_DictionaryAdded);
|
||||
serviceP.DictionaryModified += new ServiceProvider.ProviderDictionaryModified(serviceP_DictionaryModified);
|
||||
serviceP.DictionaryRemoved += new ServiceProvider.ProviderDictionaryRemoved(serviceP_DictionaryRemoved);
|
||||
serviceP.Updated -= new ServiceProvider.ProviderUpdateOnce(serviceP_Updated);
|
||||
|
||||
if (processP.RunCount >= 1)
|
||||
this.Invoke(new MethodInvoker(UpdateCommon));
|
||||
}
|
||||
|
||||
private void processP_Updated()
|
||||
{
|
||||
processP.DictionaryAdded += new ProcessSystemProvider.ProviderDictionaryAdded(processP_DictionaryAdded);
|
||||
processP.DictionaryRemoved += new ProcessSystemProvider.ProviderDictionaryRemoved(processP_DictionaryRemoved);
|
||||
processP.Updated -= new ProcessSystemProvider.ProviderUpdateOnce(processP_Updated);
|
||||
|
||||
if (processP.RunCount >= 1)
|
||||
this.Invoke(new MethodInvoker(UpdateCommon));
|
||||
}
|
||||
|
||||
private void UpdateCommon()
|
||||
{
|
||||
timerMessages.Enabled = true;
|
||||
@@ -1441,8 +1460,12 @@ namespace ProcessHacker
|
||||
processP.Interval = RefreshInterval;
|
||||
treeProcesses.Provider = processP;
|
||||
processP.Updated += new ProcessSystemProvider.ProviderUpdateOnce(processP_Updated);
|
||||
processP.Updated += new Provider<int, ProcessItem>.ProviderUpdateOnce(processP_IconUpdater);
|
||||
processP.Enabled = true;
|
||||
|
||||
cpuUsageIcon.BackColor = Color.Black;
|
||||
cpuUsageIcon.Color = Color.Red;
|
||||
|
||||
HighlightedListViewItem.HighlightingDuration = Properties.Settings.Default.HighlightingDuration;
|
||||
HighlightedListViewItem.StateHighlighting = false;
|
||||
listServices.List.BeginUpdate();
|
||||
|
||||
@@ -194,6 +194,7 @@
|
||||
this.checkShowTrayIcon.TabIndex = 7;
|
||||
this.checkShowTrayIcon.Text = "Show tray icon";
|
||||
this.checkShowTrayIcon.UseVisualStyleBackColor = true;
|
||||
this.checkShowTrayIcon.CheckedChanged += new System.EventHandler(this.checkShowTrayIcon_CheckedChanged);
|
||||
//
|
||||
// tabHighlighting
|
||||
//
|
||||
|
||||
@@ -98,5 +98,18 @@ namespace ProcessHacker
|
||||
Program.HackerWindow.ProcessList.RefreshItems();
|
||||
this.Close();
|
||||
}
|
||||
|
||||
private void checkShowTrayIcon_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (checkShowTrayIcon.Checked)
|
||||
{
|
||||
checkHideWhenMinimized.Enabled = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
checkHideWhenMinimized.Enabled = false;
|
||||
checkHideWhenMinimized.Checked = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,8 @@
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
@@ -32,17 +33,51 @@ namespace ProcessHacker
|
||||
public class UsageIcon
|
||||
{
|
||||
private List<float> _values;
|
||||
private int _width;
|
||||
private int _height;
|
||||
|
||||
public UsageIcon(int size)
|
||||
public UsageIcon(int width, int height)
|
||||
{
|
||||
_values = new List<float>(size);
|
||||
_values = new List<float>();
|
||||
_width = width;
|
||||
_height = height;
|
||||
|
||||
for (int i = 0; i < width; i++)
|
||||
_values.Add(0);
|
||||
}
|
||||
|
||||
public void Update(float value)
|
||||
{
|
||||
|
||||
if (value > 1)
|
||||
throw new ArgumentOutOfRangeException();
|
||||
|
||||
// shift values left, push value onto the end
|
||||
_values.RemoveAt(0);
|
||||
_values.Add(value);
|
||||
}
|
||||
|
||||
public Color BackColor { get; set; }
|
||||
|
||||
public Color Color { get; set; }
|
||||
|
||||
public Icon GetIcon()
|
||||
{
|
||||
using (Bitmap bm = new Bitmap(_width, _height))
|
||||
{
|
||||
using (Graphics g = Graphics.FromImage(bm))
|
||||
{
|
||||
g.FillRectangle(new SolidBrush(this.BackColor), new Rectangle(0, 0, _width, _height));
|
||||
|
||||
for (int x = 0; x < _width; x++)
|
||||
{
|
||||
int height = (int)(_values[x] * _height);
|
||||
|
||||
g.DrawLine(new Pen(this.Color), new Point(x, _height), new Point(x, _height - height));
|
||||
}
|
||||
|
||||
return Icon.FromHandle(bm.GetHicon());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,6 +56,7 @@ namespace ProcessHacker
|
||||
|
||||
public class ProcessSystemProvider : Provider<int, ProcessItem>
|
||||
{
|
||||
private long _lastIdleTime;
|
||||
private long _lastSysTime;
|
||||
|
||||
public ProcessSystemProvider()
|
||||
@@ -69,23 +70,53 @@ namespace ProcessHacker
|
||||
Win32.ZwQuerySystemInformation(Win32.SYSTEM_INFORMATION_CLASS.SystemBasicInformation, ref basic,
|
||||
Marshal.SizeOf(basic), out retLen);
|
||||
this.System = basic;
|
||||
this.ProcessorPerfArray = new Win32.SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION[this.System.NumberOfProcessors];
|
||||
|
||||
this.UpdateProcessorPerf();
|
||||
_lastSysTime = this.ProcessorPerf.KernelTime + this.ProcessorPerf.UserTime;
|
||||
_lastIdleTime = this.ProcessorPerf.IdleTime;
|
||||
}
|
||||
|
||||
public Win32.SYSTEM_BASIC_INFORMATION System { get; private set; }
|
||||
public Win32.SYSTEM_PERFORMANCE_INFORMATION Performance { get; private set; }
|
||||
public Win32.SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION ProcessorPerf { get; private set; }
|
||||
public Win32.SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION[] ProcessorPerfArray { get; private set; }
|
||||
public float CurrentCPUUsage { get; private set; }
|
||||
public int PIDWithMostCPUUsage { get; private set; }
|
||||
|
||||
private void UpdateProcessorPerf()
|
||||
{
|
||||
int retLen;
|
||||
Win32.SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION procPerf = new Win32.SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION();
|
||||
using (MemoryAlloc data =
|
||||
new MemoryAlloc(Marshal.SizeOf(typeof(Win32.SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION)) *
|
||||
this.ProcessorPerfArray.Length))
|
||||
{
|
||||
int retLen;
|
||||
|
||||
Win32.ZwQuerySystemInformation(Win32.SYSTEM_INFORMATION_CLASS.SystemProcessorTimes,
|
||||
ref procPerf, Marshal.SizeOf(procPerf), out retLen);
|
||||
this.ProcessorPerf = procPerf;
|
||||
Win32.ZwQuerySystemInformation(Win32.SYSTEM_INFORMATION_CLASS.SystemProcessorTimes,
|
||||
data, data.Size, out retLen);
|
||||
|
||||
var newAverages = new Win32.SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION();
|
||||
|
||||
for (int i = 0; i < this.ProcessorPerfArray.Length; i++)
|
||||
{
|
||||
this.ProcessorPerfArray[i] = data.ReadStruct<Win32.SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION>(
|
||||
i);
|
||||
newAverages.DpcTime += this.ProcessorPerfArray[i].DpcTime
|
||||
/ this.ProcessorPerfArray.Length;
|
||||
newAverages.IdleTime += this.ProcessorPerfArray[i].IdleTime
|
||||
/ this.ProcessorPerfArray.Length;
|
||||
newAverages.InterruptCount += this.ProcessorPerfArray[i].InterruptCount
|
||||
/ this.ProcessorPerfArray.Length;
|
||||
newAverages.InterruptTime += this.ProcessorPerfArray[i].InterruptTime
|
||||
/ this.ProcessorPerfArray.Length;
|
||||
newAverages.KernelTime += this.ProcessorPerfArray[i].KernelTime
|
||||
/ this.ProcessorPerfArray.Length;
|
||||
newAverages.UserTime += this.ProcessorPerfArray[i].UserTime
|
||||
/ this.ProcessorPerfArray.Length;
|
||||
}
|
||||
|
||||
this.ProcessorPerf = newAverages;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdatePerformance()
|
||||
@@ -113,12 +144,17 @@ namespace ProcessHacker
|
||||
|
||||
_lastSysTime = thisSysTime;
|
||||
|
||||
long thisIdleTime = this.ProcessorPerf.IdleTime;
|
||||
long idleTime = thisIdleTime - _lastIdleTime;
|
||||
|
||||
_lastIdleTime = thisIdleTime;
|
||||
|
||||
// set System Idle Process CPU time
|
||||
if (procs.ContainsKey(0))
|
||||
{
|
||||
Win32.SystemProcess proc = procs[0];
|
||||
|
||||
proc.Process.KernelTime = this.ProcessorPerf.IdleTime * 4; // must not be divided by 4
|
||||
proc.Process.KernelTime = this.ProcessorPerf.IdleTime * this.System.NumberOfProcessors;
|
||||
procs.Remove(0);
|
||||
procs.Add(0, proc);
|
||||
}
|
||||
@@ -130,7 +166,7 @@ namespace ProcessHacker
|
||||
{
|
||||
ProcessId = -2,
|
||||
InheritedFromProcessId = 0,
|
||||
KernelTime = this.ProcessorPerf.DpcTime * 4,
|
||||
KernelTime = this.ProcessorPerf.DpcTime * this.System.NumberOfProcessors,
|
||||
SessionId = -1
|
||||
}
|
||||
});
|
||||
@@ -142,11 +178,13 @@ namespace ProcessHacker
|
||||
{
|
||||
ProcessId = -3,
|
||||
InheritedFromProcessId = 0,
|
||||
KernelTime = this.ProcessorPerf.InterruptTime * 4,
|
||||
KernelTime = this.ProcessorPerf.InterruptTime * this.System.NumberOfProcessors,
|
||||
SessionId = -1
|
||||
}
|
||||
});
|
||||
|
||||
float mostCPUUsage = 0;
|
||||
|
||||
// look for dead processes
|
||||
foreach (int pid in Dictionary.Keys)
|
||||
{
|
||||
@@ -306,8 +344,14 @@ namespace ProcessHacker
|
||||
|
||||
try
|
||||
{
|
||||
newitem.CPUUsage = ((float)(newitem.LastTime - item.LastTime) * 100 / sysTime) /
|
||||
newitem.CPUUsage = (float)(newitem.LastTime - item.LastTime) * 100 / sysTime /
|
||||
this.System.NumberOfProcessors;
|
||||
|
||||
if (pid != 0 && newitem.CPUUsage > mostCPUUsage)
|
||||
{
|
||||
mostCPUUsage = newitem.CPUUsage;
|
||||
this.PIDWithMostCPUUsage = pid;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{ }
|
||||
@@ -349,6 +393,9 @@ namespace ProcessHacker
|
||||
}
|
||||
}
|
||||
|
||||
if (thisSysTime != 0)
|
||||
this.CurrentCPUUsage = (float)(sysTime - idleTime) / (sysTime);
|
||||
|
||||
Dictionary = newdictionary;
|
||||
|
||||
wtsEnumData.Memory.Dispose();
|
||||
|
||||
@@ -610,7 +610,8 @@ namespace ProcessHacker
|
||||
|
||||
[DllImport("ntdll.dll", SetLastError = true)]
|
||||
public static extern uint ZwQuerySystemInformation(SYSTEM_INFORMATION_CLASS SystemInformationClass,
|
||||
ref SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION SystemInformation, int SystemInformationLength, out int ReturnLength);
|
||||
[MarshalAs(UnmanagedType.LPArray)] SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION[] SystemInformation,
|
||||
int SystemInformationLength, out int ReturnLength);
|
||||
|
||||
[DllImport("ntdll.dll", SetLastError = true)]
|
||||
public static extern uint ZwQuerySystemInformation(SYSTEM_INFORMATION_CLASS SystemInformationClass,
|
||||
|
||||
Reference in New Issue
Block a user