diff --git a/trunk/CHANGELOG.txt b/trunk/CHANGELOG.txt
index c7685705c..509c9d854 100644
--- a/trunk/CHANGELOG.txt
+++ b/trunk/CHANGELOG.txt
@@ -23,6 +23,8 @@ Process Hacker
* Custom module information querying; can now display the modules for protected processes
* Displays service DLL paths
* Thread list displays cycles instead of context switches on Windows Vista
+ * GUI threads are highlighted (with KProcessHacker)
+ * Suspended and GUI thread highlighting can be configured
* FIXED:
* #2642442 - "System Information label text gets clipped"
* #2694437 - "Crash when sorting the process list"
diff --git a/trunk/KProcessHacker/i386/kprocesshacker.sys b/trunk/KProcessHacker/i386/kprocesshacker.sys
index 3f49db79d..ed33b4dca 100644
Binary files a/trunk/KProcessHacker/i386/kprocesshacker.sys and b/trunk/KProcessHacker/i386/kprocesshacker.sys differ
diff --git a/trunk/KProcessHacker/kph_nt.c b/trunk/KProcessHacker/kph_nt.c
index a1345e46a..02f8d270a 100644
--- a/trunk/KProcessHacker/kph_nt.c
+++ b/trunk/KProcessHacker/kph_nt.c
@@ -100,6 +100,48 @@ NTSTATUS KphGetContextThread(
return status;
}
+NTSTATUS KphGetThreadWin32Thread(
+ HANDLE ThreadHandle,
+ PVOID *Win32Thread,
+ KPROCESSOR_MODE AccessMode
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ PETHREAD threadObject;
+ PVOID win32Thread;
+
+ if (AccessMode == UserMode)
+ {
+ __try
+ {
+ ProbeForWrite(Win32Thread, sizeof(PVOID), 1);
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ return STATUS_ACCESS_VIOLATION;
+ }
+ }
+
+ status = ObReferenceObjectByHandle(ThreadHandle, 0, *PsThreadType, KernelMode, &threadObject, NULL);
+
+ if (!NT_SUCCESS(status))
+ return status;
+
+ win32Thread = PsGetThreadWin32Thread(threadObject);
+ ObDereferenceObject(threadObject);
+
+ __try
+ {
+ *Win32Thread = win32Thread;
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ return STATUS_ACCESS_VIOLATION;
+ }
+
+ return status;
+}
+
NTSTATUS KphOpenProcess(
PHANDLE ProcessHandle,
ACCESS_MASK DesiredAccess,
diff --git a/trunk/KProcessHacker/kph_nt.h b/trunk/KProcessHacker/kph_nt.h
index 22cf9c0ee..4f797bea9 100644
--- a/trunk/KProcessHacker/kph_nt.h
+++ b/trunk/KProcessHacker/kph_nt.h
@@ -36,19 +36,23 @@ NTSTATUS NTAPI ObOpenObjectByName(
PHANDLE Handle
);
-NTSTATUS PsGetContextThread(
+NTSTATUS NTAPI PsGetContextThread(
PETHREAD Thread,
PCONTEXT ThreadContext,
KPROCESSOR_MODE PreviousMode
);
+PVOID NTAPI PsGetThreadWin32Thread(
+ PETHREAD Thread
+ );
+
NTSTATUS NTAPI PsLookupProcessThreadByCid(
PCLIENT_ID ClientId,
PEPROCESS *Process,
PETHREAD *Thread
);
-NTSTATUS PsSetContextThread(
+NTSTATUS NTAPI PsSetContextThread(
PETHREAD Thread,
PCONTEXT ThreadContext,
KPROCESSOR_MODE PreviousMode
@@ -104,6 +108,12 @@ NTSTATUS KphGetContextThread(
KPROCESSOR_MODE AccessMode
);
+NTSTATUS KphGetThreadWin32Thread(
+ HANDLE ThreadHandle,
+ PVOID *Win32Thread,
+ KPROCESSOR_MODE AccessMode
+ );
+
NTSTATUS KphOpenProcess(
PHANDLE ProcessHandle,
ACCESS_MASK DesiredAccess,
diff --git a/trunk/KProcessHacker/kprocesshacker.c b/trunk/KProcessHacker/kprocesshacker.c
index 9a006c9b0..6384caafb 100644
--- a/trunk/KProcessHacker/kprocesshacker.c
+++ b/trunk/KProcessHacker/kprocesshacker.c
@@ -294,6 +294,8 @@ char *GetIoControlName(ULONG ControlCode)
return "KphGetContextThread";
else if (ControlCode == KPH_SETCONTEXTTHREAD)
return "KphSetContextThread";
+ else if (ControlCode == KPH_GETTHREADWIN32THREAD)
+ return "KphGetThreadWin32Thread";
else
return "Unknown";
}
@@ -853,6 +855,26 @@ NTSTATUS KphIoControl(PDEVICE_OBJECT DeviceObject, PIRP Irp)
}
break;
+ case KPH_GETTHREADWIN32THREAD:
+ {
+ HANDLE threadHandle;
+
+ if (inLength < 4 || outLength < 4)
+ {
+ status = STATUS_BUFFER_TOO_SMALL;
+ goto IoControlEnd;
+ }
+
+ threadHandle = *(HANDLE *)dataBuffer;
+ status = KphGetThreadWin32Thread(threadHandle, (PVOID *)dataBuffer, KernelMode);
+
+ if (!NT_SUCCESS(status))
+ goto IoControlEnd;
+
+ retLength = 4;
+ }
+ break;
+
default:
{
dprintf("KProcessHacker: unrecognized IOCTL code 0x%08x\n", controlCode);
diff --git a/trunk/KProcessHacker/kprocesshacker.h b/trunk/KProcessHacker/kprocesshacker.h
index a9adb4248..d58a3d2fd 100644
--- a/trunk/KProcessHacker/kprocesshacker.h
+++ b/trunk/KProcessHacker/kprocesshacker.h
@@ -65,6 +65,7 @@ typedef struct _SYSTEM_HANDLE_INFORMATION
#define KPH_OPENPROCESSJOB KPH_CTL_CODE(17)
#define KPH_GETCONTEXTTHREAD KPH_CTL_CODE(18)
#define KPH_SETCONTEXTTHREAD KPH_CTL_CODE(19)
+#define KPH_GETTHREADWIN32THREAD KPH_CTL_CODE(20)
NTSTATUS KphCreate(PDEVICE_OBJECT DeviceObject, PIRP Irp);
NTSTATUS KphClose(PDEVICE_OBJECT DeviceObject, PIRP Irp);
diff --git a/trunk/ProcessHacker/Components/ThreadList.cs b/trunk/ProcessHacker/Components/ThreadList.cs
index 8bba70843..a87ba5a4d 100644
--- a/trunk/ProcessHacker/Components/ThreadList.cs
+++ b/trunk/ProcessHacker/Components/ThreadList.cs
@@ -260,8 +260,10 @@ namespace ProcessHacker
private System.Drawing.Color GetThreadColor(ThreadItem titem)
{
- if (titem.WaitReason == Win32.KWAIT_REASON.Suspended)
- return System.Drawing.Color.LightGray;
+ if (Properties.Settings.Default.UseColorSuspended && titem.WaitReason == Win32.KWAIT_REASON.Suspended)
+ return Properties.Settings.Default.ColorSuspended;
+ else if (Properties.Settings.Default.UseColorGuiThreads && titem.IsGuiThread)
+ return Properties.Settings.Default.ColorGuiThreads;
return System.Drawing.SystemColors.Window;
}
diff --git a/trunk/ProcessHacker/Forms/HackerWindow.cs b/trunk/ProcessHacker/Forms/HackerWindow.cs
index 66d2e92eb..ecde1f1fa 100644
--- a/trunk/ProcessHacker/Forms/HackerWindow.cs
+++ b/trunk/ProcessHacker/Forms/HackerWindow.cs
@@ -1799,10 +1799,10 @@ namespace ProcessHacker
ColumnSettings.LoadSettings(Properties.Settings.Default.ServiceListViewColumns, listServices.List);
ColumnSettings.LoadSettings(Properties.Settings.Default.NetworkListViewColumns, listNetwork.List);
- HighlightingContext.Colors[ListViewItemState.New] = Properties.Settings.Default.ColorNewProcesses;
- HighlightingContext.Colors[ListViewItemState.Removed] = Properties.Settings.Default.ColorRemovedProcesses;
- TreeNodeAdv.StateColors[TreeNodeAdv.NodeState.New] = Properties.Settings.Default.ColorNewProcesses;
- TreeNodeAdv.StateColors[TreeNodeAdv.NodeState.Removed] = Properties.Settings.Default.ColorRemovedProcesses;
+ HighlightingContext.Colors[ListViewItemState.New] = Properties.Settings.Default.ColorNew;
+ HighlightingContext.Colors[ListViewItemState.Removed] = Properties.Settings.Default.ColorRemoved;
+ TreeNodeAdv.StateColors[TreeNodeAdv.NodeState.New] = Properties.Settings.Default.ColorNew;
+ TreeNodeAdv.StateColors[TreeNodeAdv.NodeState.Removed] = Properties.Settings.Default.ColorRemoved;
Program.ImposterNames = new System.Collections.Specialized.StringCollection();
diff --git a/trunk/ProcessHacker/Forms/OptionsWindow.cs b/trunk/ProcessHacker/Forms/OptionsWindow.cs
index cee69650d..8fbd88415 100644
--- a/trunk/ProcessHacker/Forms/OptionsWindow.cs
+++ b/trunk/ProcessHacker/Forms/OptionsWindow.cs
@@ -65,8 +65,8 @@ namespace ProcessHacker
textImposterNames.Text = Properties.Settings.Default.ImposterNames;
textHighlightingDuration.Value = Properties.Settings.Default.HighlightingDuration;
- colorNewProcesses.Color = Properties.Settings.Default.ColorNewProcesses;
- colorRemovedProcesses.Color = Properties.Settings.Default.ColorRemovedProcesses;
+ colorNewProcesses.Color = Properties.Settings.Default.ColorNew;
+ colorRemovedProcesses.Color = Properties.Settings.Default.ColorRemoved;
this.InitializeHighlightingColors();
checkPlotterAntialias.Checked = Properties.Settings.Default.PlotterAntialias;
@@ -193,6 +193,10 @@ namespace ProcessHacker
"Executables are sometimes \"packed\" to reduce their size.\n" +
"\"Dangerous processes\" includes processes with invalid signatures and unverified " +
"processes with the name of a system process.");
+ AddToList("ColorSuspended", "Suspended Threads",
+ "Threads that are suspended from execution.");
+ AddToList("ColorGuiThreads", "GUI Threads",
+ "Threads that have made at least one GUI-related system call.");
foreach (ListViewItem item in listHighlightingColors.Items)
{
@@ -280,8 +284,8 @@ namespace ProcessHacker
Program.HackerWindow.NetworkProvider.Interval = Properties.Settings.Default.RefreshInterval;
Properties.Settings.Default.HighlightingDuration = (int)textHighlightingDuration.Value;
- Properties.Settings.Default.ColorNewProcesses = colorNewProcesses.Color;
- Properties.Settings.Default.ColorRemovedProcesses = colorRemovedProcesses.Color;
+ Properties.Settings.Default.ColorNew = colorNewProcesses.Color;
+ Properties.Settings.Default.ColorRemoved = colorRemovedProcesses.Color;
foreach (ListViewItem item in listHighlightingColors.Items)
{
@@ -299,10 +303,10 @@ namespace ProcessHacker
// apply the settings immediately if we can
HighlightingContext.HighlightingDuration = Properties.Settings.Default.HighlightingDuration;
- HighlightingContext.Colors[ListViewItemState.New] = Properties.Settings.Default.ColorNewProcesses;
- HighlightingContext.Colors[ListViewItemState.Removed] = Properties.Settings.Default.ColorRemovedProcesses;
- TreeNodeAdv.StateColors[TreeNodeAdv.NodeState.New] = Properties.Settings.Default.ColorNewProcesses;
- TreeNodeAdv.StateColors[TreeNodeAdv.NodeState.Removed] = Properties.Settings.Default.ColorRemovedProcesses;
+ HighlightingContext.Colors[ListViewItemState.New] = Properties.Settings.Default.ColorNew;
+ HighlightingContext.Colors[ListViewItemState.Removed] = Properties.Settings.Default.ColorRemoved;
+ TreeNodeAdv.StateColors[TreeNodeAdv.NodeState.New] = Properties.Settings.Default.ColorNew;
+ TreeNodeAdv.StateColors[TreeNodeAdv.NodeState.Removed] = Properties.Settings.Default.ColorRemoved;
if (checkReplaceTaskManager.Enabled)
{
diff --git a/trunk/ProcessHacker/KProcessHacker.cs b/trunk/ProcessHacker/KProcessHacker.cs
index 284629634..524898f22 100644
--- a/trunk/ProcessHacker/KProcessHacker.cs
+++ b/trunk/ProcessHacker/KProcessHacker.cs
@@ -60,7 +60,8 @@ namespace ProcessHacker
GetHandleObjectName,
KphOpenProcessJob,
KphGetContextThread,
- KphSetContextThread
+ KphSetContextThread,
+ KphGetThreadWin32Thread
}
private string _deviceName;
@@ -224,6 +225,16 @@ namespace ProcessHacker
_fileHandle.IoControl(CtlCode(Control.KphGetContextThread), data, null);
}
+ public int KphGetThreadWin32Thread(Win32.ThreadHandle threadHandle)
+ {
+ byte[] inData = Misc.IntToBytes(threadHandle, Misc.Endianness.Little);
+ byte[] outData = new byte[4];
+
+ _fileHandle.IoControl(CtlCode(Control.KphGetThreadWin32Thread), inData, outData);
+
+ return Misc.BytesToInt(outData, Misc.Endianness.Little);
+ }
+
public int KphOpenProcess(int pid, Win32.PROCESS_RIGHTS desiredAccess)
{
byte[] inData = new byte[8];
diff --git a/trunk/ProcessHacker/Properties/Settings.Designer.cs b/trunk/ProcessHacker/Properties/Settings.Designer.cs
index 5e35e6ff9..1a56dd8a3 100644
--- a/trunk/ProcessHacker/Properties/Settings.Designer.cs
+++ b/trunk/ProcessHacker/Properties/Settings.Designer.cs
@@ -362,24 +362,24 @@ namespace ProcessHacker.Properties {
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("Chartreuse")]
- public global::System.Drawing.Color ColorNewProcesses {
+ public global::System.Drawing.Color ColorNew {
get {
- return ((global::System.Drawing.Color)(this["ColorNewProcesses"]));
+ return ((global::System.Drawing.Color)(this["ColorNew"]));
}
set {
- this["ColorNewProcesses"] = value;
+ this["ColorNew"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("255, 60, 40")]
- public global::System.Drawing.Color ColorRemovedProcesses {
+ public global::System.Drawing.Color ColorRemoved {
get {
- return ((global::System.Drawing.Color)(this["ColorRemovedProcesses"]));
+ return ((global::System.Drawing.Color)(this["ColorRemoved"]));
}
set {
- this["ColorRemovedProcesses"] = value;
+ this["ColorRemoved"] = value;
}
}
@@ -1200,5 +1200,53 @@ namespace ProcessHacker.Properties {
this["ServiceMiniListColumns"] = value;
}
}
+
+ [global::System.Configuration.UserScopedSettingAttribute()]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Configuration.DefaultSettingValueAttribute("Silver")]
+ public global::System.Drawing.Color ColorSuspended {
+ get {
+ return ((global::System.Drawing.Color)(this["ColorSuspended"]));
+ }
+ set {
+ this["ColorSuspended"] = value;
+ }
+ }
+
+ [global::System.Configuration.UserScopedSettingAttribute()]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Configuration.DefaultSettingValueAttribute("True")]
+ public bool UseColorSuspended {
+ get {
+ return ((bool)(this["UseColorSuspended"]));
+ }
+ set {
+ this["UseColorSuspended"] = value;
+ }
+ }
+
+ [global::System.Configuration.UserScopedSettingAttribute()]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Configuration.DefaultSettingValueAttribute("255, 255, 128")]
+ public global::System.Drawing.Color ColorGuiThreads {
+ get {
+ return ((global::System.Drawing.Color)(this["ColorGuiThreads"]));
+ }
+ set {
+ this["ColorGuiThreads"] = value;
+ }
+ }
+
+ [global::System.Configuration.UserScopedSettingAttribute()]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Configuration.DefaultSettingValueAttribute("True")]
+ public bool UseColorGuiThreads {
+ get {
+ return ((bool)(this["UseColorGuiThreads"]));
+ }
+ set {
+ this["UseColorGuiThreads"] = value;
+ }
+ }
}
}
diff --git a/trunk/ProcessHacker/Properties/Settings.settings b/trunk/ProcessHacker/Properties/Settings.settings
index bb1994c04..e631f1d1d 100644
--- a/trunk/ProcessHacker/Properties/Settings.settings
+++ b/trunk/ProcessHacker/Properties/Settings.settings
@@ -86,10 +86,10 @@
http://www.google.com/search?q=%s
-
+
Chartreuse
-
+
255, 60, 40
@@ -296,5 +296,17 @@
+
+ Silver
+
+
+ True
+
+
+ 255, 255, 128
+
+
+ True
+
\ No newline at end of file
diff --git a/trunk/ProcessHacker/Providers/ThreadProvider.cs b/trunk/ProcessHacker/Providers/ThreadProvider.cs
index 8bd5fa3d4..84c40479d 100644
--- a/trunk/ProcessHacker/Providers/ThreadProvider.cs
+++ b/trunk/ProcessHacker/Providers/ThreadProvider.cs
@@ -46,6 +46,7 @@ namespace ProcessHacker
public uint StartAddressI;
public string StartAddress;
public Win32.KWAIT_REASON WaitReason;
+ public bool IsGuiThread;
public Win32.ThreadHandle ThreadQueryLimitedHandle;
}
@@ -170,6 +171,16 @@ namespace ProcessHacker
catch
{ }
+ if (Program.KPH != null)
+ {
+ try
+ {
+ item.IsGuiThread = Program.KPH.KphGetThreadWin32Thread(item.ThreadQueryLimitedHandle) != 0;
+ }
+ catch
+ { }
+ }
+
if (Program.WindowsVersion != WindowsVersion.XP)
{
try
@@ -237,6 +248,16 @@ namespace ProcessHacker
catch
{ }
+ if (Program.KPH != null)
+ {
+ try
+ {
+ newitem.IsGuiThread = Program.KPH.KphGetThreadWin32Thread(newitem.ThreadQueryLimitedHandle) != 0;
+ }
+ catch
+ { }
+ }
+
if (Program.WindowsVersion != WindowsVersion.XP)
{
try
@@ -266,6 +287,7 @@ namespace ProcessHacker
newitem.ContextSwitchesDelta != item.ContextSwitchesDelta ||
newitem.Cycles != item.Cycles ||
newitem.CyclesDelta != item.CyclesDelta ||
+ newitem.IsGuiThread != item.IsGuiThread ||
newitem.Priority != item.Priority ||
newitem.StartAddress != item.StartAddress ||
newitem.WaitReason != item.WaitReason
diff --git a/trunk/ProcessHacker/app.config b/trunk/ProcessHacker/app.config
index 456369319..16b22e8fd 100644
--- a/trunk/ProcessHacker/app.config
+++ b/trunk/ProcessHacker/app.config
@@ -91,10 +91,10 @@
http://www.google.com/search?q=%s
-
+
Chartreuse
-
+
255, 60, 40
@@ -301,6 +301,18 @@
+
+ Silver
+
+
+ True
+
+
+ 255, 255, 128
+
+
+ True
+
\ No newline at end of file