diff --git a/2.x/trunk/CHANGELOG.txt b/2.x/trunk/CHANGELOG.txt
index 5c288a185..dd2f9367b 100644
--- a/2.x/trunk/CHANGELOG.txt
+++ b/2.x/trunk/CHANGELOG.txt
@@ -10,6 +10,7 @@ Process Hacker
* Extended header context menu
* Removed tooltip text truncation
* Updated ExtendedTools plugin:
+ * Added Disk tab
* Added Hard Faults, Hard Faults Delta and Peak Threads
columns to process tree list
* Added Firewall Status column
@@ -24,6 +25,7 @@ Process Hacker
* Fixed state highlighting bug
* Fixed command line propagation for -elevate
* Fixed tree list mouse wheel handling
+ * Fixed saving network list
2.19
* NEW/IMPROVED:
diff --git a/2.x/trunk/ProcessHacker/include/mainwndp.h b/2.x/trunk/ProcessHacker/include/mainwndp.h
index 2f717bc01..438a4f2a1 100644
--- a/2.x/trunk/ProcessHacker/include/mainwndp.h
+++ b/2.x/trunk/ProcessHacker/include/mainwndp.h
@@ -233,7 +233,7 @@ VOID PhMwpNotifyTabControl(
);
VOID PhMwpSelectionChangedTabControl(
- VOID
+ __in ULONG OldIndex
);
PPH_ADDITIONAL_TAB_PAGE PhMwpAddTabPage(
diff --git a/2.x/trunk/ProcessHacker/include/phapp.h b/2.x/trunk/ProcessHacker/include/phapp.h
index 47fe94b17..8a542d40c 100644
--- a/2.x/trunk/ProcessHacker/include/phapp.h
+++ b/2.x/trunk/ProcessHacker/include/phapp.h
@@ -295,14 +295,17 @@ typedef struct _PH_TN_COLUMN_MENU_DATA
#define PH_TN_COLUMN_MENU_SIZE_COLUMN_TO_FIT_ID ((ULONG)-3)
#define PH_TN_COLUMN_MENU_SIZE_ALL_COLUMNS_TO_FIT_ID ((ULONG)-4)
+PHAPPAPI
VOID PhInitializeTreeNewColumnMenu(
__inout PPH_TN_COLUMN_MENU_DATA Data
);
+PHAPPAPI
BOOLEAN PhHandleTreeNewColumnMenu(
__inout PPH_TN_COLUMN_MENU_DATA Data
);
+PHAPPAPI
VOID PhDeleteTreeNewColumnMenu(
__in PPH_TN_COLUMN_MENU_DATA Data
);
@@ -461,6 +464,13 @@ typedef HWND (NTAPI *PPH_TAB_PAGE_CREATE_FUNCTION)(
__in PVOID Context
);
+typedef VOID (NTAPI *PPH_TAB_PAGE_CALLBACK_FUNCTION)(
+ __in PVOID Parameter1,
+ __in PVOID Parameter2,
+ __in PVOID Parameter3,
+ __in PVOID Context
+ );
+
typedef struct _PH_ADDITIONAL_TAB_PAGE
{
PWSTR Text;
@@ -468,6 +478,8 @@ typedef struct _PH_ADDITIONAL_TAB_PAGE
PPH_TAB_PAGE_CREATE_FUNCTION CreateFunction;
HWND WindowHandle;
INT Index;
+ PPH_TAB_PAGE_CALLBACK_FUNCTION SelectionChangedCallback;
+ PPH_TAB_PAGE_CALLBACK_FUNCTION SaveContentCallback;
} PH_ADDITIONAL_TAB_PAGE, *PPH_ADDITIONAL_TAB_PAGE;
#define PH_NOTIFY_MINIMUM 0x1
diff --git a/2.x/trunk/ProcessHacker/include/uimodels.h b/2.x/trunk/ProcessHacker/include/uimodels.h
index eeffde39e..837365be9 100644
--- a/2.x/trunk/ProcessHacker/include/uimodels.h
+++ b/2.x/trunk/ProcessHacker/include/uimodels.h
@@ -589,6 +589,7 @@ typedef struct _PH_THREAD_NODE
WCHAR CpuUsageText[PH_INT32_STR_LEN_1];
PPH_STRING CyclesDeltaText; // used for Context Switches Delta as well
+ PPH_STRING StartAddressText;
PPH_STRING PriorityText;
} PH_THREAD_NODE, *PPH_THREAD_NODE;
diff --git a/2.x/trunk/ProcessHacker/mainwnd.c b/2.x/trunk/ProcessHacker/mainwnd.c
index 7b8180d95..8952ead00 100644
--- a/2.x/trunk/ProcessHacker/mainwnd.c
+++ b/2.x/trunk/ProcessHacker/mainwnd.c
@@ -60,6 +60,7 @@ static INT ProcessesTabIndex;
static INT ServicesTabIndex;
static INT NetworkTabIndex;
static INT MaxTabIndex;
+static INT OldTabIndex;
static PPH_LIST AdditionalTabPageList = NULL;
static HWND ProcessTreeListHandle;
static HWND ServiceTreeListHandle;
@@ -240,7 +241,7 @@ BOOLEAN PhMainWndInitialization(
PhLogInitialization();
PhQueueItemGlobalWorkQueue(PhMwpDelayedLoadFunction, NULL);
- PhMwpSelectionChangedTabControl();
+ PhMwpSelectionChangedTabControl(-1);
// Perform a layout.
SendMessage(PhMainWndHandle, WM_SIZE, 0, 0);
@@ -605,6 +606,11 @@ VOID PhMwpOnDestroy(
ULONG mask;
ULONG i;
+ // Notify plugins that we are shutting down.
+
+ if (PhPluginsEnabled)
+ PhUnloadPlugins();
+
if (!PhMainWndExiting)
ProcessHacker_SaveAllSettings(PhMainWndHandle);
@@ -619,11 +625,6 @@ VOID PhMwpOnDestroy(
PhRemoveNotifyIcon(i);
}
- // Notify plugins that we are shutting down.
-
- if (PhPluginsEnabled)
- PhUnloadPlugins();
-
PostQuitMessage(0);
}
@@ -763,7 +764,6 @@ VOID PhMwpOnCommand(
{
ULONG mode;
ULONG selectedTab;
- PPH_LIST lines = NULL;
if (PhEndsWithString2(fileName, L".csv", TRUE))
mode = PH_EXPORT_MODE_CSV;
@@ -775,27 +775,35 @@ VOID PhMwpOnCommand(
selectedTab = TabCtrl_GetCurSel(TabControlHandle);
if (selectedTab == ProcessesTabIndex)
+ {
PhWriteProcessTree(fileStream, mode);
+ }
else if (selectedTab == ServicesTabIndex)
+ {
PhWriteServiceList(fileStream, mode);
+ }
else if (selectedTab == NetworkTabIndex)
- lines = PhGetListViewLines(NetworkTreeListHandle, mode);
-
- if (lines)
+ {
+ PhWriteNetworkList(fileStream, mode);
+ }
+ else if (AdditionalTabPageList)
{
ULONG i;
- for (i = 0; i < lines->Count; i++)
+ for (i = 0; i < AdditionalTabPageList->Count; i++)
{
- PPH_STRING line;
+ PPH_ADDITIONAL_TAB_PAGE tabPage = AdditionalTabPageList->Items[i];
- line = lines->Items[i];
- PhWriteStringAsAnsiFileStream(fileStream, &line->sr);
- PhDereferenceObject(line);
- PhWriteStringAsAnsiFileStream2(fileStream, L"\r\n");
+ if (tabPage->Index == selectedTab)
+ {
+ if (tabPage->SaveContentCallback)
+ {
+ tabPage->SaveContentCallback(fileStream, UlongToPtr(mode), NULL, tabPage->Context);
+ }
+
+ break;
+ }
}
-
- PhDereferenceObject(lines);
}
PhDereferenceObject(fileStream);
@@ -2934,14 +2942,18 @@ VOID PhMwpNotifyTabControl(
__in NMHDR *Header
)
{
- if (Header->code == TCN_SELCHANGE)
+ if (Header->code == TCN_SELCHANGING)
{
- PhMwpSelectionChangedTabControl();
+ OldTabIndex = TabCtrl_GetCurSel(TabControlHandle);
+ }
+ else if (Header->code == TCN_SELCHANGE)
+ {
+ PhMwpSelectionChangedTabControl(OldTabIndex);
}
}
VOID PhMwpSelectionChangedTabControl(
- VOID
+ __in ULONG OldIndex
)
{
INT selectedIndex;
@@ -2989,6 +3001,18 @@ VOID PhMwpSelectionChangedTabControl(
{
PPH_ADDITIONAL_TAB_PAGE tabPage = AdditionalTabPageList->Items[i];
+ if (tabPage->SelectionChangedCallback)
+ {
+ if (tabPage->Index == OldIndex)
+ {
+ tabPage->SelectionChangedCallback((PVOID)FALSE, 0, 0, tabPage->Context);
+ }
+ else if (tabPage->Index == selectedIndex)
+ {
+ tabPage->SelectionChangedCallback((PVOID)TRUE, 0, 0, tabPage->Context);
+ }
+ }
+
ShowWindow(tabPage->WindowHandle, selectedIndex == tabPage->Index ? SW_SHOW : SW_HIDE);
}
}
@@ -3025,8 +3049,11 @@ VOID PhMwpSelectTabPage(
__in ULONG Index
)
{
+ INT oldIndex;
+
+ oldIndex = TabCtrl_GetCurSel(TabControlHandle);
TabCtrl_SetCurSel(TabControlHandle, Index);
- PhMwpSelectionChangedTabControl();
+ PhMwpSelectionChangedTabControl(oldIndex);
}
static int __cdecl IconProcessesCpuUsageCompare(
diff --git a/2.x/trunk/ProcessHacker/sdk/phapppub.h b/2.x/trunk/ProcessHacker/sdk/phapppub.h
index d603761a7..47bb4f6c1 100644
--- a/2.x/trunk/ProcessHacker/sdk/phapppub.h
+++ b/2.x/trunk/ProcessHacker/sdk/phapppub.h
@@ -395,6 +395,38 @@ PhWritePhTextHeader(
__inout PPH_FILE_STREAM FileStream
);
+typedef struct _PH_TN_COLUMN_MENU_DATA
+{
+ HWND TreeNewHandle;
+ PPH_TREENEW_HEADER_MOUSE_EVENT MouseEvent;
+ ULONG DefaultSortColumn;
+ PH_SORT_ORDER DefaultSortOrder;
+
+ struct _PH_EMENU_ITEM *Menu;
+ struct _PH_EMENU_ITEM *Selection;
+ ULONG ProcessedId;
+} PH_TN_COLUMN_MENU_DATA, *PPH_TN_COLUMN_MENU_DATA;
+
+#define PH_TN_COLUMN_MENU_HIDE_COLUMN_ID ((ULONG)-1)
+#define PH_TN_COLUMN_MENU_CHOOSE_COLUMNS_ID ((ULONG)-2)
+#define PH_TN_COLUMN_MENU_SIZE_COLUMN_TO_FIT_ID ((ULONG)-3)
+#define PH_TN_COLUMN_MENU_SIZE_ALL_COLUMNS_TO_FIT_ID ((ULONG)-4)
+
+PHAPPAPI
+VOID PhInitializeTreeNewColumnMenu(
+ __inout PPH_TN_COLUMN_MENU_DATA Data
+ );
+
+PHAPPAPI
+BOOLEAN PhHandleTreeNewColumnMenu(
+ __inout PPH_TN_COLUMN_MENU_DATA Data
+ );
+
+PHAPPAPI
+VOID PhDeleteTreeNewColumnMenu(
+ __in PPH_TN_COLUMN_MENU_DATA Data
+ );
+
// mainwnd
#define PH_MAINWND_CLASS_NAME L"ProcessHacker"
@@ -462,6 +494,13 @@ typedef HWND (NTAPI *PPH_TAB_PAGE_CREATE_FUNCTION)(
__in PVOID Context
);
+typedef VOID (NTAPI *PPH_TAB_PAGE_CALLBACK_FUNCTION)(
+ __in PVOID Parameter1,
+ __in PVOID Parameter2,
+ __in PVOID Parameter3,
+ __in PVOID Context
+ );
+
typedef struct _PH_ADDITIONAL_TAB_PAGE
{
PWSTR Text;
@@ -469,6 +508,8 @@ typedef struct _PH_ADDITIONAL_TAB_PAGE
PPH_TAB_PAGE_CREATE_FUNCTION CreateFunction;
HWND WindowHandle;
INT Index;
+ PPH_TAB_PAGE_CALLBACK_FUNCTION SelectionChangedCallback;
+ PPH_TAB_PAGE_CALLBACK_FUNCTION SaveContentCallback;
} PH_ADDITIONAL_TAB_PAGE, *PPH_ADDITIONAL_TAB_PAGE;
#define PH_NOTIFY_MINIMUM 0x1
diff --git a/2.x/trunk/ProcessHacker/thrdlist.c b/2.x/trunk/ProcessHacker/thrdlist.c
index f90b65165..48b21d76b 100644
--- a/2.x/trunk/ProcessHacker/thrdlist.c
+++ b/2.x/trunk/ProcessHacker/thrdlist.c
@@ -302,6 +302,7 @@ VOID PhpDestroyThreadNode(
PhEmCallObjectOperation(EmThreadNodeType, ThreadNode, EmObjectDelete);
if (ThreadNode->CyclesDeltaText) PhDereferenceObject(ThreadNode->CyclesDeltaText);
+ if (ThreadNode->StartAddressText) PhDereferenceObject(ThreadNode->StartAddressText);
if (ThreadNode->PriorityText) PhDereferenceObject(ThreadNode->PriorityText);
PhDereferenceObject(ThreadNode->ThreadItem);
@@ -551,7 +552,8 @@ BOOLEAN NTAPI PhpThreadTreeNewCallback(
}
break;
case PHTHTLC_STARTADDRESS:
- getCellText->Text = PhGetStringRef(threadItem->StartAddressString);
+ PhSwapReference(&node->StartAddressText, threadItem->StartAddressString);
+ getCellText->Text = PhGetStringRef(node->StartAddressText);
break;
case PHTHTLC_PRIORITY:
PhSwapReference2(&node->PriorityText, PhGetThreadPriorityWin32String(threadItem->PriorityWin32));
diff --git a/2.x/trunk/phlib/include/cpysave.h b/2.x/trunk/phlib/include/cpysave.h
index e3482dcf3..12faa3b83 100644
--- a/2.x/trunk/phlib/include/cpysave.h
+++ b/2.x/trunk/phlib/include/cpysave.h
@@ -32,6 +32,7 @@ PPH_FULL_STRING PhGetTreeNewText(
__in ULONG MaximumNumberOfColumns
);
+PHLIBAPI
PPH_LIST PhGetGenericTreeNewLines(
__in HWND TreeNewHandle,
__in ULONG Mode
diff --git a/2.x/trunk/phlib/include/emenu.h b/2.x/trunk/phlib/include/emenu.h
index 6f3fc9534..1f4a0d0ff 100644
--- a/2.x/trunk/phlib/include/emenu.h
+++ b/2.x/trunk/phlib/include/emenu.h
@@ -40,6 +40,7 @@ typedef struct _PH_EMENU_ITEM
typedef struct _PH_EMENU_ITEM PH_EMENU, *PPH_EMENU;
+PHLIBAPI
PPH_EMENU_ITEM PhCreateEMenuItem(
__in ULONG Flags,
__in ULONG Id,
@@ -90,8 +91,10 @@ VOID PhRemoveAllEMenuItems(
__inout PPH_EMENU_ITEM Parent
);
+PHLIBAPI
PPH_EMENU PhCreateEMenu();
+PHLIBAPI
VOID PhDestroyEMenu(
__in PPH_EMENU Menu
);
@@ -122,6 +125,7 @@ VOID PhPopupMenuToEMenuItem(
__in HMENU PopupMenu
);
+PHLIBAPI
VOID PhLoadResourceEMenuItem(
__inout PPH_EMENU_ITEM MenuItem,
__in HINSTANCE InstanceHandle,
@@ -132,6 +136,7 @@ VOID PhLoadResourceEMenuItem(
#define PH_EMENU_SHOW_NONOTIFY 0x1
#define PH_EMENU_SHOW_LEFTRIGHT 0x2
+PHLIBAPI
PPH_EMENU_ITEM PhShowEMenu(
__in PPH_EMENU Menu,
__in HWND WindowHandle,
@@ -143,6 +148,7 @@ PPH_EMENU_ITEM PhShowEMenu(
// Convenience functions
+PHLIBAPI
BOOLEAN PhSetFlagsEMenuItem(
__in PPH_EMENU_ITEM Item,
__in ULONG Id,
@@ -159,6 +165,7 @@ FORCEINLINE BOOLEAN PhEnableEMenuItem(
return PhSetFlagsEMenuItem(Item, Id, PH_EMENU_DISABLED, Enable ? 0 : PH_EMENU_DISABLED);
}
+PHLIBAPI
VOID PhSetFlagsAllEMenuItems(
__in PPH_EMENU_ITEM Item,
__in ULONG Mask,
diff --git a/2.x/trunk/plugins-extra/AvgCpuPlugin/main.c b/2.x/trunk/plugins-extra/AvgCpuPlugin/main.c
index 2a411af2d..abbe729ad 100644
--- a/2.x/trunk/plugins-extra/AvgCpuPlugin/main.c
+++ b/2.x/trunk/plugins-extra/AvgCpuPlugin/main.c
@@ -214,10 +214,9 @@ VOID ProcessesUpdatedHandler(
do
{
sum += extension->CpuHistory[i];
+ i++;
- if (i != HISTORY_SIZE)
- i++;
- else
+ if (i == HISTORY_SIZE)
i = 0;
} while (--count != 0);
@@ -237,10 +236,9 @@ VOID ProcessesUpdatedHandler(
do
{
sum += extension->CpuHistory[i];
+ i++;
- if (i != HISTORY_SIZE)
- i++;
- else
+ if (i == HISTORY_SIZE)
i = 0;
} while (--count != 0);
diff --git a/2.x/trunk/plugins/ExtendedTools/CHANGELOG.txt b/2.x/trunk/plugins/ExtendedTools/CHANGELOG.txt
index 9522d87e0..d0eb84101 100644
--- a/2.x/trunk/plugins/ExtendedTools/CHANGELOG.txt
+++ b/2.x/trunk/plugins/ExtendedTools/CHANGELOG.txt
@@ -1,4 +1,5 @@
1.5
+ * Added Disk tab
* Added Hard Faults, Hard Faults Delta and Peak Threads columns
to process tree list
* Added Firewall Status column to network list
diff --git a/2.x/trunk/plugins/ExtendedTools/ExtendedTools.rc b/2.x/trunk/plugins/ExtendedTools/ExtendedTools.rc
index 28fed0802..0e9cf1bf5 100644
--- a/2.x/trunk/plugins/ExtendedTools/ExtendedTools.rc
+++ b/2.x/trunk/plugins/ExtendedTools/ExtendedTools.rc
@@ -372,6 +372,18 @@ BEGIN
END
END
+IDR_DISK MENU
+BEGIN
+ POPUP "Disk"
+ BEGIN
+ MENUITEM "&Go to Process\aEnter", ID_DISK_GOTOPROCESS
+ MENUITEM SEPARATOR
+ MENUITEM "Open &File Location\aCtrl+Enter", ID_DISK_OPENFILELOCATION
+ MENUITEM "&Copy\aCtrl+C", ID_DISK_COPY
+ MENUITEM "P&roperties", ID_DISK_PROPERTIES
+ END
+END
+
#endif // English (Australia) resources
/////////////////////////////////////////////////////////////////////////////
diff --git a/2.x/trunk/plugins/ExtendedTools/ExtendedTools.vcxproj b/2.x/trunk/plugins/ExtendedTools/ExtendedTools.vcxproj
index bdcbe1eb9..d01b30555 100644
--- a/2.x/trunk/plugins/ExtendedTools/ExtendedTools.vcxproj
+++ b/2.x/trunk/plugins/ExtendedTools/ExtendedTools.vcxproj
@@ -84,6 +84,7 @@
EditAndContinue
StdCall
true
+ true
ProcessHacker.lib;ntdll.lib;%(AdditionalDependencies)
@@ -107,6 +108,7 @@
ProgramDatabase
StdCall
true
+ true
ProcessHacker.lib;ntdll.lib;%(AdditionalDependencies)
@@ -128,6 +130,7 @@
ProgramDatabase
StdCall
true
+ true
ProcessHacker.lib;ntdll.lib;%(AdditionalDependencies)
@@ -155,6 +158,7 @@
ProgramDatabase
StdCall
true
+ true
ProcessHacker.lib;ntdll.lib;%(AdditionalDependencies)
@@ -168,6 +172,8 @@
+
+
@@ -183,6 +189,7 @@
+
diff --git a/2.x/trunk/plugins/ExtendedTools/ExtendedTools.vcxproj.filters b/2.x/trunk/plugins/ExtendedTools/ExtendedTools.vcxproj.filters
index 3de8851c4..9fd7af168 100644
--- a/2.x/trunk/plugins/ExtendedTools/ExtendedTools.vcxproj.filters
+++ b/2.x/trunk/plugins/ExtendedTools/ExtendedTools.vcxproj.filters
@@ -54,6 +54,12 @@
Source Files
+
+ Source Files
+
+
+ Source Files
+
@@ -65,6 +71,9 @@
Header Files
+
+ Header Files
+
diff --git a/2.x/trunk/plugins/ExtendedTools/disktab.c b/2.x/trunk/plugins/ExtendedTools/disktab.c
new file mode 100644
index 000000000..9913124d2
--- /dev/null
+++ b/2.x/trunk/plugins/ExtendedTools/disktab.c
@@ -0,0 +1,858 @@
+/*
+ * Process Hacker Extended Tools -
+ * ETW disk monitoring
+ *
+ * Copyright (C) 2011 wj32
+ *
+ * This file is part of Process Hacker.
+ *
+ * Process Hacker is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Process Hacker is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Process Hacker. If not, see .
+ */
+
+#include "exttools.h"
+#include "etwmon.h"
+#include "resource.h"
+#include
+#include "disktabp.h"
+
+static BOOLEAN DiskTreeNewCreated = FALSE;
+static HWND DiskTreeNewHandle;
+static ULONG DiskTreeNewSortColumn;
+static PH_SORT_ORDER DiskTreeNewSortOrder;
+
+static PPH_HASHTABLE DiskNodeHashtable; // hashtable of all nodes
+static PPH_LIST DiskNodeList; // list of all nodes
+
+static PH_CALLBACK_REGISTRATION DiskItemAddedRegistration;
+static PH_CALLBACK_REGISTRATION DiskItemModifiedRegistration;
+static PH_CALLBACK_REGISTRATION DiskItemRemovedRegistration;
+static PH_CALLBACK_REGISTRATION DiskItemsUpdatedRegistration;
+static BOOLEAN DiskNeedsRedraw = FALSE;
+
+VOID EtInitializeDiskTab()
+{
+ PH_ADDITIONAL_TAB_PAGE tabPage;
+
+ memset(&tabPage, 0, sizeof(PH_ADDITIONAL_TAB_PAGE));
+ tabPage.Text = L"Disk";
+ tabPage.CreateFunction = EtpDiskTabCreateFunction;
+ tabPage.Index = MAXINT;
+ tabPage.SaveContentCallback = EtpDiskTabSaveContentCallback;
+ ProcessHacker_AddTabPage(PhMainWndHandle, &tabPage);
+}
+
+HWND NTAPI EtpDiskTabCreateFunction(
+ __in PVOID Context
+ )
+{
+ HWND hwnd;
+
+ hwnd = CreateWindow(
+ PH_TREENEW_CLASSNAME,
+ NULL,
+ WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_BORDER | TN_STYLE_ICONS | TN_STYLE_DOUBLE_BUFFERED,
+ 0,
+ 0,
+ 3,
+ 3,
+ PhMainWndHandle,
+ (HMENU)PhPluginReserveIds(1),
+ PluginInstance->DllBase,
+ NULL
+ );
+
+ if (!hwnd)
+ return NULL;
+
+ DiskTreeNewCreated = TRUE;
+
+ DiskNodeHashtable = PhCreateHashtable(
+ sizeof(PET_DISK_NODE),
+ EtpDiskNodeHashtableCompareFunction,
+ EtpDiskNodeHashtableHashFunction,
+ 100
+ );
+ DiskNodeList = PhCreateList(100);
+
+ EtInitializeDiskTreeList(hwnd);
+
+ PhRegisterCallback(
+ &EtDiskItemAddedEvent,
+ EtpDiskItemAddedHandler,
+ NULL,
+ &DiskItemAddedRegistration
+ );
+ PhRegisterCallback(
+ &EtDiskItemModifiedEvent,
+ EtpDiskItemModifiedHandler,
+ NULL,
+ &DiskItemModifiedRegistration
+ );
+ PhRegisterCallback(
+ &EtDiskItemRemovedEvent,
+ EtpDiskItemRemovedHandler,
+ NULL,
+ &DiskItemRemovedRegistration
+ );
+ PhRegisterCallback(
+ &EtDiskItemsUpdatedEvent,
+ EtpDiskItemsUpdatedHandler,
+ NULL,
+ &DiskItemsUpdatedRegistration
+ );
+
+ EtInitializeDiskInformation();
+
+ return hwnd;
+}
+
+VOID NTAPI EtpDiskTabSaveContentCallback(
+ __in PVOID Parameter1,
+ __in PVOID Parameter2,
+ __in PVOID Parameter3,
+ __in PVOID Context
+ )
+{
+ PPH_FILE_STREAM fileStream = Parameter1;
+ ULONG mode = PtrToUlong(Parameter2);
+
+ EtWriteDiskList(fileStream, mode);
+}
+
+BOOLEAN EtpDiskNodeHashtableCompareFunction(
+ __in PVOID Entry1,
+ __in PVOID Entry2
+ )
+{
+ PET_DISK_NODE diskNode1 = *(PET_DISK_NODE *)Entry1;
+ PET_DISK_NODE diskNode2 = *(PET_DISK_NODE *)Entry2;
+
+ return diskNode1->DiskItem == diskNode2->DiskItem;
+}
+
+ULONG EtpDiskNodeHashtableHashFunction(
+ __in PVOID Entry
+ )
+{
+#ifdef _M_IX86
+ return PhHashInt32((ULONG)(*(PET_DISK_NODE *)Entry)->DiskItem);
+#else
+ return PhHashInt64((ULONG64)(*(PET_DISK_NODE *)Entry)->DiskItem);
+#endif
+}
+
+VOID EtInitializeDiskTreeList(
+ __in HWND hwnd
+ )
+{
+ DiskTreeNewHandle = hwnd;
+ PhSetControlTheme(DiskTreeNewHandle, L"explorer");
+ SendMessage(TreeNew_GetTooltips(DiskTreeNewHandle), TTM_SETDELAYTIME, TTDT_AUTOPOP, 0x7fff);
+
+ TreeNew_SetCallback(hwnd, EtpDiskTreeNewCallback, NULL);
+
+ TreeNew_SetRedraw(hwnd, FALSE);
+
+ // Default columns
+ PhAddTreeNewColumn(hwnd, ETDSTNC_NAME, TRUE, L"Name", 100, PH_ALIGN_LEFT, 0, 0);
+ PhAddTreeNewColumn(hwnd, ETDSTNC_FILE, TRUE, L"File", 400, PH_ALIGN_LEFT, 1, 0);
+ PhAddTreeNewColumnEx(hwnd, ETDSTNC_READRATEAVERAGE, TRUE, L"Read Rate Average", 70, PH_ALIGN_RIGHT, 2, DT_RIGHT, TRUE);
+ PhAddTreeNewColumnEx(hwnd, ETDSTNC_WRITERATEAVERAGE, TRUE, L"Write Rate Average", 70, PH_ALIGN_RIGHT, 3, DT_RIGHT, TRUE);
+ PhAddTreeNewColumnEx(hwnd, ETDSTNC_TOTALRATEAVERAGE, TRUE, L"Total Rate Average", 70, PH_ALIGN_RIGHT, 4, DT_RIGHT, TRUE);
+
+ TreeNew_SetRedraw(hwnd, TRUE);
+
+ TreeNew_SetSort(hwnd, ETDSTNC_TOTALRATEAVERAGE, DescendingSortOrder);
+
+ EtLoadSettingsDiskTreeList();
+}
+
+VOID EtLoadSettingsDiskTreeList()
+{
+ PPH_STRING settings;
+ PH_INTEGER_PAIR sortSettings;
+
+ settings = PhGetStringSetting(SETTING_NAME_DISK_TREE_LIST_COLUMNS);
+ PhCmLoadSettings(DiskTreeNewHandle, &settings->sr);
+ PhDereferenceObject(settings);
+
+ sortSettings = PhGetIntegerPairSetting(SETTING_NAME_DISK_TREE_LIST_SORT);
+ TreeNew_SetSort(DiskTreeNewHandle, (ULONG)sortSettings.X, (PH_SORT_ORDER)sortSettings.Y);
+}
+
+VOID EtSaveSettingsDiskTreeList()
+{
+ PPH_STRING settings;
+ PH_INTEGER_PAIR sortSettings;
+ ULONG sortColumn;
+ PH_SORT_ORDER sortOrder;
+
+ if (!DiskTreeNewCreated)
+ return;
+
+ settings = PhCmSaveSettings(DiskTreeNewHandle);
+ PhSetStringSetting2(SETTING_NAME_DISK_TREE_LIST_COLUMNS, &settings->sr);
+ PhDereferenceObject(settings);
+
+ TreeNew_GetSort(DiskTreeNewHandle, &sortColumn, &sortOrder);
+ sortSettings.X = sortColumn;
+ sortSettings.Y = sortOrder;
+ PhSetIntegerPairSetting(SETTING_NAME_DISK_TREE_LIST_SORT, sortSettings);
+}
+
+PET_DISK_NODE EtAddDiskNode(
+ __in PET_DISK_ITEM DiskItem
+ )
+{
+ PET_DISK_NODE diskNode;
+
+ diskNode = PhAllocate(sizeof(ET_DISK_NODE));
+ memset(diskNode, 0, sizeof(ET_DISK_NODE));
+ PhInitializeTreeNewNode(&diskNode->Node);
+
+ diskNode->DiskItem = DiskItem;
+ PhReferenceObject(DiskItem);
+
+ memset(diskNode->TextCache, 0, sizeof(PH_STRINGREF) * ETDSTNC_MAXIMUM);
+ diskNode->Node.TextCache = diskNode->TextCache;
+ diskNode->Node.TextCacheSize = ETDSTNC_MAXIMUM;
+
+ diskNode->ProcessNameText = EtpGetDiskItemProcessName(DiskItem);
+
+ PhAddEntryHashtable(DiskNodeHashtable, &diskNode);
+ PhAddItemList(DiskNodeList, diskNode);
+
+ TreeNew_NodesStructured(DiskTreeNewHandle);
+
+ return diskNode;
+}
+
+PET_DISK_NODE EtFindDiskNode(
+ __in PET_DISK_ITEM DiskItem
+ )
+{
+ ET_DISK_NODE lookupDiskNode;
+ PET_DISK_NODE lookupDiskNodePtr = &lookupDiskNode;
+ PET_DISK_NODE *diskNode;
+
+ lookupDiskNode.DiskItem = DiskItem;
+
+ diskNode = (PET_DISK_NODE *)PhFindEntryHashtable(
+ DiskNodeHashtable,
+ &lookupDiskNodePtr
+ );
+
+ if (diskNode)
+ return *diskNode;
+ else
+ return NULL;
+}
+
+VOID EtRemoveDiskNode(
+ __in PET_DISK_NODE DiskNode
+ )
+{
+ ULONG index;
+
+ // Remove from the hashtable/list and cleanup.
+
+ PhRemoveEntryHashtable(DiskNodeHashtable, &DiskNode);
+
+ if ((index = PhFindItemList(DiskNodeList, DiskNode)) != -1)
+ PhRemoveItemList(DiskNodeList, index);
+
+ if (DiskNode->ProcessNameText) PhDereferenceObject(DiskNode->ProcessNameText);
+ if (DiskNode->ReadRateAverageText) PhDereferenceObject(DiskNode->ReadRateAverageText);
+ if (DiskNode->WriteRateAverageText) PhDereferenceObject(DiskNode->WriteRateAverageText);
+ if (DiskNode->TotalRateAverageText) PhDereferenceObject(DiskNode->TotalRateAverageText);
+ if (DiskNode->TooltipText) PhDereferenceObject(DiskNode->TooltipText);
+
+ PhDereferenceObject(DiskNode->DiskItem);
+
+ PhFree(DiskNode);
+
+ TreeNew_NodesStructured(DiskTreeNewHandle);
+}
+
+VOID EtUpdateDiskNode(
+ __in PET_DISK_NODE DiskNode
+ )
+{
+ memset(DiskNode->TextCache, 0, sizeof(PH_STRINGREF) * ETDSTNC_MAXIMUM);
+ PhSwapReference(&DiskNode->TooltipText, NULL);
+
+ PhInvalidateTreeNewNode(&DiskNode->Node, TN_CACHE_ICON);
+ TreeNew_NodesStructured(DiskTreeNewHandle);
+}
+
+VOID EtpFormatRate(
+ __in ULONG64 ValuePerPeriod,
+ __inout PPH_STRING *Buffer,
+ __out PPH_STRINGREF String
+ )
+{
+ ULONG64 number;
+
+ number = ValuePerPeriod;
+ number *= 1000;
+ number /= PhGetIntegerSetting(L"UpdateInterval");
+
+ if (number != 0)
+ {
+ PH_FORMAT format[2];
+
+ PhInitFormatSize(&format[0], number);
+ PhInitFormatS(&format[1], L"/s");
+ PhSwapReference2(Buffer, PhFormat(format, 2, 0));
+ *String = (*Buffer)->sr;
+ }
+}
+
+#define SORT_FUNCTION(Column) EtpDiskTreeNewCompare##Column
+
+#define BEGIN_SORT_FUNCTION(Column) static int __cdecl EtpDiskTreeNewCompare##Column( \
+ __in const void *_elem1, \
+ __in const void *_elem2 \
+ ) \
+{ \
+ PET_DISK_NODE node1 = *(PET_DISK_NODE *)_elem1; \
+ PET_DISK_NODE node2 = *(PET_DISK_NODE *)_elem2; \
+ PET_DISK_ITEM diskItem1 = node1->DiskItem; \
+ PET_DISK_ITEM diskItem2 = node2->DiskItem; \
+ int sortResult = 0;
+
+#define END_SORT_FUNCTION \
+ if (sortResult == 0) \
+ sortResult = PhCompareString(diskItem1->FileNameWin32, diskItem2->FileNameWin32, TRUE); \
+ \
+ return PhModifySort(sortResult, DiskTreeNewSortOrder); \
+}
+
+BEGIN_SORT_FUNCTION(Process)
+{
+ sortResult = PhCompareString(node1->ProcessNameText, node2->ProcessNameText, TRUE);
+}
+END_SORT_FUNCTION
+
+BEGIN_SORT_FUNCTION(File)
+{
+ sortResult = PhCompareString(diskItem1->FileNameWin32, diskItem2->FileNameWin32, TRUE);
+}
+END_SORT_FUNCTION
+
+BEGIN_SORT_FUNCTION(ReadRateAverage)
+{
+ sortResult = uint64cmp(diskItem1->ReadAverage, diskItem2->ReadAverage);
+}
+END_SORT_FUNCTION
+
+BEGIN_SORT_FUNCTION(WriteRateAverage)
+{
+ sortResult = uint64cmp(diskItem1->WriteAverage, diskItem2->WriteAverage);
+}
+END_SORT_FUNCTION
+
+BEGIN_SORT_FUNCTION(TotalRateAverage)
+{
+ sortResult = uint64cmp(diskItem1->ReadAverage + diskItem1->WriteAverage, diskItem2->ReadAverage + diskItem2->WriteAverage);
+}
+END_SORT_FUNCTION
+
+BOOLEAN NTAPI EtpDiskTreeNewCallback(
+ __in HWND hwnd,
+ __in PH_TREENEW_MESSAGE Message,
+ __in_opt PVOID Parameter1,
+ __in_opt PVOID Parameter2,
+ __in_opt PVOID Context
+ )
+{
+ PET_DISK_NODE node;
+
+ switch (Message)
+ {
+ case TreeNewGetChildren:
+ {
+ PPH_TREENEW_GET_CHILDREN getChildren = Parameter1;
+
+ if (!getChildren->Node)
+ {
+ static PVOID sortFunctions[] =
+ {
+ SORT_FUNCTION(Process),
+ SORT_FUNCTION(File),
+ SORT_FUNCTION(ReadRateAverage),
+ SORT_FUNCTION(WriteRateAverage),
+ SORT_FUNCTION(TotalRateAverage)
+ };
+ int (__cdecl *sortFunction)(const void *, const void *);
+
+ if (DiskTreeNewSortColumn < ETDSTNC_MAXIMUM)
+ sortFunction = sortFunctions[DiskTreeNewSortColumn];
+ else
+ sortFunction = NULL;
+
+ if (sortFunction)
+ {
+ qsort(DiskNodeList->Items, DiskNodeList->Count, sizeof(PVOID), sortFunction);
+ }
+
+ getChildren->Children = (PPH_TREENEW_NODE *)DiskNodeList->Items;
+ getChildren->NumberOfChildren = DiskNodeList->Count;
+ }
+ }
+ return TRUE;
+ case TreeNewIsLeaf:
+ {
+ PPH_TREENEW_IS_LEAF isLeaf = Parameter1;
+
+ isLeaf->IsLeaf = TRUE;
+ }
+ return TRUE;
+ case TreeNewGetCellText:
+ {
+ PPH_TREENEW_GET_CELL_TEXT getCellText = Parameter1;
+ PET_DISK_ITEM diskItem;
+
+ node = (PET_DISK_NODE)getCellText->Node;
+ diskItem = node->DiskItem;
+
+ switch (getCellText->Id)
+ {
+ case ETDSTNC_NAME:
+ getCellText->Text = node->ProcessNameText->sr;
+ break;
+ case ETDSTNC_FILE:
+ getCellText->Text = diskItem->FileNameWin32->sr;
+ break;
+ case ETDSTNC_READRATEAVERAGE:
+ EtpFormatRate(diskItem->ReadAverage, &node->ReadRateAverageText, &getCellText->Text);
+ break;
+ case ETDSTNC_WRITERATEAVERAGE:
+ EtpFormatRate(diskItem->WriteAverage, &node->WriteRateAverageText, &getCellText->Text);
+ break;
+ case ETDSTNC_TOTALRATEAVERAGE:
+ EtpFormatRate(diskItem->ReadAverage + diskItem->WriteAverage, &node->TotalRateAverageText, &getCellText->Text);
+ break;
+ default:
+ return FALSE;
+ }
+
+ getCellText->Flags = TN_CACHE;
+ }
+ return TRUE;
+ case TreeNewGetNodeIcon:
+ {
+ PPH_TREENEW_GET_NODE_ICON getNodeIcon = Parameter1;
+
+ node = (PET_DISK_NODE)getNodeIcon->Node;
+
+ if (node->DiskItem->ProcessIconValid)
+ {
+ // TODO: Check if the icon handle is actually valid, since the process item
+ // might get destroyed while the disk node is still valid.
+ getNodeIcon->Icon = node->DiskItem->ProcessIcon;
+ }
+ else
+ {
+ PhGetStockApplicationIcon(&getNodeIcon->Icon, NULL);
+ }
+
+ getNodeIcon->Flags = TN_CACHE;
+ }
+ return TRUE;
+ case TreeNewGetCellTooltip:
+ {
+ PPH_TREENEW_GET_CELL_TOOLTIP getCellTooltip = Parameter1;
+ PPH_PROCESS_ITEM processItem;
+
+ node = (PET_DISK_NODE)getCellTooltip->Node;
+
+ if (getCellTooltip->Column->Id != 0)
+ return FALSE;
+
+ if (!node->TooltipText)
+ {
+ if (processItem = PhReferenceProcessItem(node->DiskItem->ProcessId))
+ {
+ node->TooltipText = PhCreateString(L"TODO"); // TODO
+ PhDereferenceObject(processItem);
+ }
+ }
+
+ if (!PhIsNullOrEmptyString(node->TooltipText))
+ {
+ getCellTooltip->Text = node->TooltipText->sr;
+ getCellTooltip->Unfolding = FALSE;
+ getCellTooltip->MaximumWidth = 550;
+ }
+ else
+ {
+ return FALSE;
+ }
+ }
+ return TRUE;
+ case TreeNewSortChanged:
+ {
+ TreeNew_GetSort(hwnd, &DiskTreeNewSortColumn, &DiskTreeNewSortOrder);
+ // Force a rebuild to sort the items.
+ TreeNew_NodesStructured(hwnd);
+ }
+ return TRUE;
+ case TreeNewKeyDown:
+ {
+ PPH_TREENEW_KEY_EVENT keyEvent = Parameter1;
+
+ switch (keyEvent->VirtualKey)
+ {
+ case 'C':
+ if (GetKeyState(VK_CONTROL) < 0)
+ EtHandleDiskCommand(ID_DISK_COPY);
+ break;
+ case VK_RETURN:
+ EtHandleDiskCommand(ID_DISK_GOTOPROCESS);
+ break;
+ }
+ }
+ return TRUE;
+ case TreeNewHeaderRightClick:
+ {
+ PH_TN_COLUMN_MENU_DATA data;
+
+ data.TreeNewHandle = hwnd;
+ data.MouseEvent = Parameter1;
+ data.DefaultSortColumn = 0;
+ data.DefaultSortOrder = AscendingSortOrder;
+ PhInitializeTreeNewColumnMenu(&data);
+
+ data.Selection = PhShowEMenu(data.Menu, hwnd, PH_EMENU_SHOW_LEFTRIGHT | PH_EMENU_SHOW_NONOTIFY,
+ PH_ALIGN_LEFT | PH_ALIGN_TOP, data.MouseEvent->ScreenLocation.x, data.MouseEvent->ScreenLocation.y);
+ PhHandleTreeNewColumnMenu(&data);
+ PhDeleteTreeNewColumnMenu(&data);
+ }
+ return TRUE;
+ case TreeNewLeftDoubleClick:
+ {
+ EtHandleDiskCommand(ID_DISK_GOTOPROCESS);
+ }
+ return TRUE;
+ case TreeNewContextMenu:
+ {
+ PPH_TREENEW_MOUSE_EVENT mouseEvent = Parameter1;
+
+ EtShowDiskContextMenu(mouseEvent->Location);
+ }
+ return TRUE;
+ case TreeNewDestroying:
+ {
+ EtSaveSettingsDiskTreeList();
+ }
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+PPH_STRING EtpGetDiskItemProcessName(
+ __in PET_DISK_ITEM DiskItem
+ )
+{
+ PH_FORMAT format[4];
+
+ if (!DiskItem->ProcessId)
+ return PhCreateString(L"No Process");
+
+ PhInitFormatS(&format[1], L" (");
+ PhInitFormatU(&format[2], (ULONG)DiskItem->ProcessId);
+ PhInitFormatC(&format[3], ')');
+
+ if (DiskItem->ProcessName)
+ PhInitFormatSR(&format[0], DiskItem->ProcessName->sr);
+ else
+ PhInitFormatS(&format[0], L"Unknown Process");
+
+ return PhFormat(format, 4, 96);
+}
+
+PET_DISK_ITEM EtGetSelectedDiskItem()
+{
+ PET_DISK_ITEM diskItem = NULL;
+ ULONG i;
+
+ for (i = 0; i < DiskNodeList->Count; i++)
+ {
+ PET_DISK_NODE node = DiskNodeList->Items[i];
+
+ if (node->Node.Selected)
+ {
+ diskItem = node->DiskItem;
+ break;
+ }
+ }
+
+ return diskItem;
+}
+
+VOID EtGetSelectedDiskItems(
+ __out PET_DISK_ITEM **DiskItems,
+ __out PULONG NumberOfDiskItems
+ )
+{
+ PPH_LIST list;
+ ULONG i;
+
+ list = PhCreateList(2);
+
+ for (i = 0; i < DiskNodeList->Count; i++)
+ {
+ PET_DISK_NODE node = DiskNodeList->Items[i];
+
+ if (node->Node.Selected)
+ {
+ PhAddItemList(list, node->DiskItem);
+ }
+ }
+
+ *DiskItems = PhAllocateCopy(list->Items, sizeof(PVOID) * list->Count);
+ *NumberOfDiskItems = list->Count;
+
+ PhDereferenceObject(list);
+}
+
+VOID EtDeselectAllDiskNodes()
+{
+ TreeNew_DeselectRange(DiskTreeNewHandle, 0, -1);
+}
+
+VOID EtSelectAndEnsureVisibleDiskNode(
+ __in PET_DISK_NODE DiskNode
+ )
+{
+ EtDeselectAllDiskNodes();
+
+ if (!DiskNode->Node.Visible)
+ return;
+
+ TreeNew_SetFocusNode(DiskTreeNewHandle, &DiskNode->Node);
+ TreeNew_SetMarkNode(DiskTreeNewHandle, &DiskNode->Node);
+ TreeNew_SelectRange(DiskTreeNewHandle, DiskNode->Node.Index, DiskNode->Node.Index);
+ TreeNew_EnsureVisible(DiskTreeNewHandle, &DiskNode->Node);
+}
+
+VOID EtCopyDiskList()
+{
+ PPH_FULL_STRING text;
+
+ text = PhGetTreeNewText(DiskTreeNewHandle, ETDSTNC_MAXIMUM);
+ PhSetClipboardStringEx(DiskTreeNewHandle, text->Buffer, text->Length);
+ PhDereferenceObject(text);
+}
+
+VOID EtWriteDiskList(
+ __inout PPH_FILE_STREAM FileStream,
+ __in ULONG Mode
+ )
+{
+ PPH_LIST lines;
+ ULONG i;
+
+ lines = PhGetGenericTreeNewLines(DiskTreeNewHandle, Mode);
+
+ for (i = 0; i < lines->Count; i++)
+ {
+ PPH_STRING line;
+
+ line = lines->Items[i];
+ PhWriteStringAsAnsiFileStream(FileStream, &line->sr);
+ PhDereferenceObject(line);
+ PhWriteStringAsAnsiFileStream2(FileStream, L"\r\n");
+ }
+
+ PhDereferenceObject(lines);
+}
+
+VOID EtHandleDiskCommand(
+ __in ULONG Id
+ )
+{
+ switch (Id)
+ {
+ case ID_DISK_GOTOPROCESS:
+ {
+
+ }
+ break;
+ }
+}
+
+VOID EtpInitializeDiskMenu(
+ __in PPH_EMENU Menu,
+ __in PET_DISK_ITEM *DiskItems,
+ __in ULONG NumberOfDiskItems
+ )
+{
+ if (NumberOfDiskItems == 0)
+ {
+ PhSetFlagsAllEMenuItems(Menu, PH_EMENU_DISABLED, PH_EMENU_DISABLED);
+ }
+ else if (NumberOfDiskItems == 1)
+ {
+ NOTHING;
+ }
+ else
+ {
+ PhSetFlagsAllEMenuItems(Menu, PH_EMENU_DISABLED, PH_EMENU_DISABLED);
+ PhEnableEMenuItem(Menu, ID_DISK_COPY, TRUE);
+ }
+}
+
+VOID EtShowDiskContextMenu(
+ __in POINT Location
+ )
+{
+ PET_DISK_ITEM *diskItems;
+ ULONG numberOfDiskItems;
+
+ EtGetSelectedDiskItems(&diskItems, &numberOfDiskItems);
+
+ if (numberOfDiskItems != 0)
+ {
+ PPH_EMENU menu;
+ PPH_EMENU_ITEM item;
+
+ menu = PhCreateEMenu();
+ PhLoadResourceEMenuItem(menu, PluginInstance->DllBase, MAKEINTRESOURCE(IDR_DISK), 0);
+ PhSetFlagsEMenuItem(menu, ID_DISK_GOTOPROCESS, PH_EMENU_DEFAULT, PH_EMENU_DEFAULT);
+
+ EtpInitializeDiskMenu(menu, diskItems, numberOfDiskItems);
+
+ item = PhShowEMenu(
+ menu,
+ PhMainWndHandle,
+ PH_EMENU_SHOW_LEFTRIGHT,
+ PH_ALIGN_LEFT | PH_ALIGN_TOP,
+ Location.x,
+ Location.y
+ );
+
+ if (item)
+ {
+ EtHandleDiskCommand(item->Id);
+ }
+
+ PhDestroyEMenu(menu);
+ }
+
+ PhFree(diskItems);
+}
+
+static VOID NTAPI EtpDiskItemAddedHandler(
+ __in_opt PVOID Parameter,
+ __in_opt PVOID Context
+ )
+{
+ PET_DISK_ITEM diskItem = (PET_DISK_ITEM)Parameter;
+
+ PhReferenceObject(diskItem);
+ ProcessHacker_Invoke(PhMainWndHandle, EtpOnDiskItemAdded, diskItem);
+}
+
+static VOID NTAPI EtpDiskItemModifiedHandler(
+ __in_opt PVOID Parameter,
+ __in_opt PVOID Context
+ )
+{
+ ProcessHacker_Invoke(PhMainWndHandle, EtpOnDiskItemModified, (PET_DISK_ITEM)Parameter);
+}
+
+static VOID NTAPI EtpDiskItemRemovedHandler(
+ __in_opt PVOID Parameter,
+ __in_opt PVOID Context
+ )
+{
+ ProcessHacker_Invoke(PhMainWndHandle, EtpOnDiskItemRemoved, (PET_DISK_ITEM)Parameter);
+}
+
+static VOID NTAPI EtpDiskItemsUpdatedHandler(
+ __in_opt PVOID Parameter,
+ __in_opt PVOID Context
+ )
+{
+ ProcessHacker_Invoke(PhMainWndHandle, EtpOnDiskItemsUpdated, NULL);
+}
+
+static VOID NTAPI EtpOnDiskItemAdded(
+ __in PVOID Parameter
+ )
+{
+ PET_DISK_ITEM diskItem = Parameter;
+ PET_DISK_NODE diskNode;
+
+ if (!DiskNeedsRedraw)
+ {
+ TreeNew_SetRedraw(DiskTreeNewHandle, FALSE);
+ DiskNeedsRedraw = TRUE;
+ }
+
+ diskNode = EtAddDiskNode(diskItem);
+ PhDereferenceObject(diskItem);
+}
+
+static VOID NTAPI EtpOnDiskItemModified(
+ __in PVOID Parameter
+ )
+{
+ PET_DISK_ITEM diskItem = Parameter;
+
+ EtUpdateDiskNode(EtFindDiskNode(diskItem));
+}
+
+static VOID NTAPI EtpOnDiskItemRemoved(
+ __in PVOID Parameter
+ )
+{
+ PET_DISK_ITEM diskItem = Parameter;
+
+ if (!DiskNeedsRedraw)
+ {
+ TreeNew_SetRedraw(DiskTreeNewHandle, FALSE);
+ DiskNeedsRedraw = TRUE;
+ }
+
+ EtRemoveDiskNode(EtFindDiskNode(diskItem));
+}
+
+static VOID NTAPI EtpOnDiskItemsUpdated(
+ __in PVOID Parameter
+ )
+{
+ ULONG i;
+
+ if (DiskNeedsRedraw)
+ {
+ TreeNew_SetRedraw(DiskTreeNewHandle, TRUE);
+ DiskNeedsRedraw = FALSE;
+ }
+
+ // Text invalidation
+
+ for (i = 0; i < DiskNodeList->Count; i++)
+ {
+ PET_DISK_NODE node = DiskNodeList->Items[i];
+
+ // The name and file name never change, so we don't invalidate that.
+ memset(&node->TextCache[2], 0, sizeof(PH_STRINGREF) * (ETDSTNC_MAXIMUM - 2));
+ }
+
+ InvalidateRect(DiskTreeNewHandle, NULL, FALSE);
+}
diff --git a/2.x/trunk/plugins/ExtendedTools/disktabp.h b/2.x/trunk/plugins/ExtendedTools/disktabp.h
new file mode 100644
index 000000000..c905d4e1b
--- /dev/null
+++ b/2.x/trunk/plugins/ExtendedTools/disktabp.h
@@ -0,0 +1,126 @@
+#ifndef DISKTABP_H
+#define DISKTABP_H
+
+HWND NTAPI EtpDiskTabCreateFunction(
+ __in PVOID Context
+ );
+
+VOID NTAPI EtpDiskTabSaveContentCallback(
+ __in PVOID Parameter1,
+ __in PVOID Parameter2,
+ __in PVOID Parameter3,
+ __in PVOID Context
+ );
+
+BOOLEAN EtpDiskNodeHashtableCompareFunction(
+ __in PVOID Entry1,
+ __in PVOID Entry2
+ );
+
+ULONG EtpDiskNodeHashtableHashFunction(
+ __in PVOID Entry
+ );
+
+VOID EtInitializeDiskTreeList(
+ __in HWND hwnd
+ );
+
+PET_DISK_NODE EtAddDiskNode(
+ __in PET_DISK_ITEM DiskItem
+ );
+
+PET_DISK_NODE EtFindDiskNode(
+ __in PET_DISK_ITEM DiskItem
+ );
+
+VOID EtRemoveDiskNode(
+ __in PET_DISK_NODE DiskNode
+ );
+
+VOID EtUpdateDiskNode(
+ __in PET_DISK_NODE DiskNode
+ );
+
+BOOLEAN NTAPI EtpDiskTreeNewCallback(
+ __in HWND hwnd,
+ __in PH_TREENEW_MESSAGE Message,
+ __in_opt PVOID Parameter1,
+ __in_opt PVOID Parameter2,
+ __in_opt PVOID Context
+ );
+
+PPH_STRING EtpGetDiskItemProcessName(
+ __in PET_DISK_ITEM DiskItem
+ );
+
+PET_DISK_ITEM EtGetSelectedDiskItem();
+
+VOID EtGetSelectedDiskItems(
+ __out PET_DISK_ITEM **DiskItems,
+ __out PULONG NumberOfDiskItems
+ );
+
+VOID EtDeselectAllDiskNodes();
+
+VOID EtSelectAndEnsureVisibleDiskNode(
+ __in PET_DISK_NODE DiskNode
+ );
+
+VOID EtCopyDiskList();
+
+VOID EtWriteDiskList(
+ __inout PPH_FILE_STREAM FileStream,
+ __in ULONG Mode
+ );
+
+VOID EtHandleDiskCommand(
+ __in ULONG Id
+ );
+
+VOID EtpInitializeDiskMenu(
+ __in PPH_EMENU Menu,
+ __in PET_DISK_ITEM *DiskItems,
+ __in ULONG NumberOfDiskItems
+ );
+
+VOID EtShowDiskContextMenu(
+ __in POINT Location
+ );
+
+VOID NTAPI EtpDiskItemAddedHandler(
+ __in_opt PVOID Parameter,
+ __in_opt PVOID Context
+ );
+
+VOID NTAPI EtpDiskItemModifiedHandler(
+ __in_opt PVOID Parameter,
+ __in_opt PVOID Context
+ );
+
+VOID NTAPI EtpDiskItemRemovedHandler(
+ __in_opt PVOID Parameter,
+ __in_opt PVOID Context
+ );
+
+VOID NTAPI EtpDiskItemsUpdatedHandler(
+ __in_opt PVOID Parameter,
+ __in_opt PVOID Context
+ );
+
+VOID NTAPI EtpOnDiskItemAdded(
+ __in PVOID Parameter
+ );
+
+VOID NTAPI EtpOnDiskItemModified(
+ __in PVOID Parameter
+ );
+
+VOID NTAPI EtpOnDiskItemRemoved(
+ __in PVOID Parameter
+ );
+
+VOID NTAPI EtpOnDiskItemsUpdated(
+ __in PVOID Parameter
+ );
+
+#endif
diff --git a/2.x/trunk/plugins/ExtendedTools/etwdisk.c b/2.x/trunk/plugins/ExtendedTools/etwdisk.c
new file mode 100644
index 000000000..f39537012
--- /dev/null
+++ b/2.x/trunk/plugins/ExtendedTools/etwdisk.c
@@ -0,0 +1,545 @@
+/*
+ * Process Hacker Extended Tools -
+ * ETW disk monitoring
+ *
+ * Copyright (C) 2011 wj32
+ *
+ * This file is part of Process Hacker.
+ *
+ * Process Hacker is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Process Hacker is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Process Hacker. If not, see .
+ */
+
+#include "exttools.h"
+#include "etwmon.h"
+
+typedef struct _ETP_DISK_PACKET
+{
+ SINGLE_LIST_ENTRY ListEntry;
+ ET_ETW_DISK_EVENT Event;
+ PPH_STRING FileName;
+} ETP_DISK_PACKET, *PETP_DISK_PACKET;
+
+VOID NTAPI EtpDiskItemDeleteProcedure(
+ __in PVOID Object,
+ __in ULONG Flags
+ );
+
+BOOLEAN NTAPI EtpDiskHashtableCompareFunction(
+ __in PVOID Entry1,
+ __in PVOID Entry2
+ );
+
+ULONG NTAPI EtpDiskHashtableHashFunction(
+ __in PVOID Entry
+ );
+
+VOID NTAPI ProcessesUpdatedCallback(
+ __in_opt PVOID Parameter,
+ __in_opt PVOID Context
+ );
+
+BOOLEAN EtDiskEnabled = FALSE;
+
+PPH_OBJECT_TYPE EtDiskItemType;
+PPH_HASHTABLE EtDiskHashtable;
+PH_QUEUED_LOCK EtDiskHashtableLock = PH_QUEUED_LOCK_INIT;
+LIST_ENTRY EtDiskAgeListHead;
+PH_CALLBACK_DECLARE(EtDiskItemAddedEvent);
+PH_CALLBACK_DECLARE(EtDiskItemModifiedEvent);
+PH_CALLBACK_DECLARE(EtDiskItemRemovedEvent);
+PH_CALLBACK_DECLARE(EtDiskItemsUpdatedEvent);
+
+PH_FREE_LIST EtDiskPacketFreeList;
+SLIST_HEADER EtDiskPacketListHead;
+PPH_HASHTABLE EtFileNameHashtable;
+PH_QUEUED_LOCK EtFileNameHashtableLock = PH_QUEUED_LOCK_INIT;
+
+static PH_CALLBACK_REGISTRATION ProcessesUpdatedCallbackRegistration;
+
+VOID EtInitializeDiskInformation()
+{
+ NTSTATUS status;
+
+ EtDiskEnabled = TRUE;
+
+ if (!NT_SUCCESS(status = PhCreateObjectType(
+ &EtDiskItemType,
+ L"DiskItem",
+ 0,
+ EtpDiskItemDeleteProcedure
+ )))
+ PhRaiseStatus(status);
+
+ EtDiskHashtable = PhCreateHashtable(
+ sizeof(PET_DISK_ITEM),
+ EtpDiskHashtableCompareFunction,
+ EtpDiskHashtableHashFunction,
+ 128
+ );
+ InitializeListHead(&EtDiskAgeListHead);
+
+ PhInitializeFreeList(&EtDiskPacketFreeList, sizeof(ETP_DISK_PACKET), 64);
+ RtlInitializeSListHead(&EtDiskPacketListHead);
+ EtFileNameHashtable = PhCreateSimpleHashtable(128);
+
+ // Collect all existing file names.
+ EtStartEtwRundown();
+
+ PhRegisterCallback(
+ &PhProcessesUpdatedEvent,
+ ProcessesUpdatedCallback,
+ NULL,
+ &ProcessesUpdatedCallbackRegistration
+ );
+}
+
+PET_DISK_ITEM EtCreateDiskItem()
+{
+ PET_DISK_ITEM diskItem;
+
+ if (!NT_SUCCESS(PhCreateObject(
+ &diskItem,
+ sizeof(ET_DISK_ITEM),
+ 0,
+ EtDiskItemType
+ )))
+ return NULL;
+
+ memset(diskItem, 0, sizeof(ET_DISK_ITEM));
+
+ return diskItem;
+}
+
+VOID NTAPI EtpDiskItemDeleteProcedure(
+ __in PVOID Object,
+ __in ULONG Flags
+ )
+{
+ PET_DISK_ITEM diskItem = Object;
+
+ if (diskItem->FileName) PhDereferenceObject(diskItem->FileName);
+ if (diskItem->FileNameWin32) PhDereferenceObject(diskItem->FileNameWin32);
+ if (diskItem->ProcessName) PhDereferenceObject(diskItem->ProcessName);
+}
+
+// Copied from srvprv.c
+/**
+ * Generates a hash code for a string, case-insensitive.
+ *
+ * \param String The string.
+ * \param Count The number of characters to hash.
+ */
+FORCEINLINE ULONG EtpHashStringIgnoreCase(
+ __in PWSTR String,
+ __in ULONG Count
+ )
+{
+ ULONG hash = Count;
+
+ if (Count == 0)
+ return 0;
+
+ do
+ {
+ hash = RtlUpcaseUnicodeChar(*String) + (hash << 6) + (hash << 16) - hash;
+ String++;
+ } while (--Count != 0);
+
+ return hash;
+}
+
+BOOLEAN NTAPI EtpDiskHashtableCompareFunction(
+ __in PVOID Entry1,
+ __in PVOID Entry2
+ )
+{
+ PET_DISK_ITEM diskItem1 = *(PET_DISK_ITEM *)Entry1;
+ PET_DISK_ITEM diskItem2 = *(PET_DISK_ITEM *)Entry2;
+
+ return diskItem1->ProcessId == diskItem2->ProcessId && PhEqualString(diskItem1->FileName, diskItem2->FileName, TRUE);
+}
+
+ULONG NTAPI EtpDiskHashtableHashFunction(
+ __in PVOID Entry
+ )
+{
+ PET_DISK_ITEM diskItem = *(PET_DISK_ITEM *)Entry;
+
+ return ((ULONG)diskItem->ProcessId / 4) ^ EtpHashStringIgnoreCase(diskItem->FileName->Buffer, diskItem->FileName->Length / sizeof(WCHAR));
+}
+
+PET_DISK_ITEM EtReferenceDiskItem(
+ __in HANDLE ProcessId,
+ __in PPH_STRING FileName
+ )
+{
+ ET_DISK_ITEM lookupDiskItem;
+ PET_DISK_ITEM lookupDiskItemPtr = &lookupDiskItem;
+ PET_DISK_ITEM *diskItemPtr;
+ PET_DISK_ITEM diskItem;
+
+ lookupDiskItem.ProcessId = ProcessId;
+ lookupDiskItem.FileName = FileName;
+
+ PhAcquireQueuedLockShared(&EtDiskHashtableLock);
+
+ diskItemPtr = (PET_DISK_ITEM *)PhFindEntryHashtable(
+ EtDiskHashtable,
+ &lookupDiskItemPtr
+ );
+
+ if (diskItemPtr)
+ {
+ diskItem = *diskItemPtr;
+ PhReferenceObject(diskItem);
+ }
+ else
+ {
+ diskItem = NULL;
+ }
+
+ PhReleaseQueuedLockShared(&EtDiskHashtableLock);
+
+ return diskItem;
+}
+
+__assumeLocked VOID EtpRemoveDiskItem(
+ __in PET_DISK_ITEM DiskItem
+ )
+{
+ RemoveEntryList(&DiskItem->AgeListEntry);
+ PhRemoveEntryHashtable(EtDiskHashtable, &DiskItem);
+ PhDereferenceObject(DiskItem);
+}
+
+VOID EtDiskProcessDiskEvent(
+ __in PET_ETW_DISK_EVENT Event
+ )
+{
+ PETP_DISK_PACKET packet;
+
+ if (!EtDiskEnabled)
+ return;
+
+ packet = PhAllocateFromFreeList(&EtDiskPacketFreeList);
+ memcpy(&packet->Event, Event, sizeof(ET_ETW_DISK_EVENT));
+ packet->FileName = EtFileObjectToFileName(Event->FileObject);
+ RtlInterlockedPushEntrySList(&EtDiskPacketListHead, &packet->ListEntry);
+}
+
+VOID EtDiskProcessFileEvent(
+ __in PET_ETW_FILE_EVENT Event
+ )
+{
+ PH_KEY_VALUE_PAIR pair;
+ PPH_KEY_VALUE_PAIR realPair;
+
+ if (!EtDiskEnabled)
+ return;
+
+ if (Event->Type == EtEtwFileCreateType || Event->Type == EtEtwFileRundownType)
+ {
+ pair.Key = Event->FileObject;
+ pair.Value = NULL;
+
+ PhAcquireQueuedLockExclusive(&EtFileNameHashtableLock);
+
+ realPair = PhAddEntryHashtableEx(EtFileNameHashtable, &pair, NULL);
+ PhSwapReference2(&realPair->Value, PhCreateStringEx(Event->FileName.Buffer, Event->FileName.Length));
+
+ PhReleaseQueuedLockExclusive(&EtFileNameHashtableLock);
+ }
+ else if (Event->Type == EtEtwFileDeleteType)
+ {
+ pair.Key = Event->FileObject;
+
+ PhAcquireQueuedLockExclusive(&EtFileNameHashtableLock);
+
+ realPair = PhFindEntryHashtable(EtFileNameHashtable, &pair);
+
+ if (realPair)
+ {
+ PhDereferenceObject(realPair->Value);
+ PhRemoveEntryHashtable(EtFileNameHashtable, &pair);
+ }
+
+ PhReleaseQueuedLockExclusive(&EtFileNameHashtableLock);
+ }
+}
+
+PPH_STRING EtFileObjectToFileName(
+ __in PVOID FileObject
+ )
+{
+ PH_KEY_VALUE_PAIR pair;
+ PPH_KEY_VALUE_PAIR realPair;
+ PPH_STRING fileName;
+
+ pair.Key = FileObject;
+ fileName = NULL;
+
+ PhAcquireQueuedLockShared(&EtFileNameHashtableLock);
+
+ realPair = PhFindEntryHashtable(EtFileNameHashtable, &pair);
+
+ if (realPair)
+ {
+ fileName = realPair->Value;
+ PhReferenceObject(fileName);
+ }
+
+ PhReleaseQueuedLockShared(&EtFileNameHashtableLock);
+
+ return fileName;
+}
+
+VOID EtpProcessDiskPacket(
+ __in PETP_DISK_PACKET Packet,
+ __in ULONG RunId
+ )
+{
+ PET_ETW_DISK_EVENT diskEvent;
+ PET_DISK_ITEM diskItem;
+ BOOLEAN added = FALSE;
+
+ diskEvent = &Packet->Event;
+
+ // We only process non-zero read/write events.
+ if (diskEvent->Type != EtEtwDiskReadType && diskEvent->Type != EtEtwDiskWriteType)
+ return;
+ if (diskEvent->TransferSize == 0)
+ return;
+
+ // Ignore packets with no file name - this is useless to the user.
+ if (!Packet->FileName)
+ return;
+
+ diskItem = EtReferenceDiskItem(diskEvent->ClientId.UniqueProcess, Packet->FileName);
+
+ if (!diskItem)
+ {
+ PPH_PROCESS_ITEM processItem;
+
+ // Disk item not found (or the address was re-used), create it.
+
+ diskItem = EtCreateDiskItem();
+
+ diskItem->ProcessId = diskEvent->ClientId.UniqueProcess;
+ diskItem->FileName = Packet->FileName;
+ PhReferenceObject(Packet->FileName);
+ diskItem->FileNameWin32 = PhGetFileName(diskItem->FileName);
+
+ if (processItem = PhReferenceProcessItem(diskItem->ProcessId))
+ {
+ diskItem->ProcessName = processItem->ProcessName;
+ PhReferenceObject(processItem->ProcessName);
+
+ if (PhTestEvent(&processItem->Stage1Event))
+ {
+ diskItem->ProcessIcon = processItem->SmallIcon;
+ diskItem->ProcessIconValid = TRUE;
+ }
+
+ PhDereferenceObject(processItem);
+ }
+
+ // Add the disk item to the age list.
+ diskItem->AddTime = RunId;
+ diskItem->FreshTime = RunId;
+ InsertHeadList(&EtDiskAgeListHead, &diskItem->AgeListEntry);
+
+ // Add the disk item to the hashtable.
+ PhAcquireQueuedLockExclusive(&EtDiskHashtableLock);
+ PhAddEntryHashtable(EtDiskHashtable, &diskItem);
+ PhReleaseQueuedLockExclusive(&EtDiskHashtableLock);
+
+ // Raise the disk item added event.
+ PhInvokeCallback(&EtDiskItemAddedEvent, diskItem);
+ added = TRUE;
+ }
+
+ // Accumulate statistics for this update period.
+ if (diskEvent->Type == EtEtwDiskReadType)
+ diskItem->ReadDelta += diskEvent->TransferSize;
+ else
+ diskItem->WriteDelta += diskEvent->TransferSize;
+
+ if (!added)
+ {
+ if (diskItem->FreshTime != RunId)
+ {
+ diskItem->FreshTime = RunId;
+ RemoveEntryList(&diskItem->AgeListEntry);
+ InsertHeadList(&EtDiskAgeListHead, &diskItem->AgeListEntry);
+ }
+
+ PhDereferenceObject(diskItem);
+ }
+}
+
+ULONG64 EtpCalculateAverage(
+ __in PULONG64 Buffer,
+ __in ULONG BufferSize,
+ __in ULONG BufferPosition,
+ __in ULONG BufferCount,
+ __in ULONG NumberToConsider
+ )
+{
+ ULONG64 sum;
+ ULONG i;
+ ULONG count;
+
+ sum = 0;
+ i = BufferPosition;
+
+ if (NumberToConsider > BufferCount)
+ NumberToConsider = BufferCount;
+
+ if (NumberToConsider == 0)
+ return 0;
+
+ count = NumberToConsider;
+
+ do
+ {
+ sum += Buffer[i];
+ i++;
+
+ if (i == BufferSize)
+ i = 0;
+ } while (--count != 0);
+
+ return sum / NumberToConsider;
+}
+
+static VOID NTAPI ProcessesUpdatedCallback(
+ __in_opt PVOID Parameter,
+ __in_opt PVOID Context
+ )
+{
+ static ULONG runCount = 0;
+
+ PSINGLE_LIST_ENTRY listEntry;
+ PLIST_ENTRY ageListEntry;
+
+ // Process incoming disk event packets.
+
+ listEntry = RtlInterlockedFlushSList(&EtDiskPacketListHead);
+
+ while (listEntry)
+ {
+ PETP_DISK_PACKET packet;
+
+ packet = CONTAINING_RECORD(listEntry, ETP_DISK_PACKET, ListEntry);
+ listEntry = listEntry->Next;
+
+ EtpProcessDiskPacket(packet, runCount);
+
+ if (packet->FileName)
+ PhDereferenceObject(packet->FileName);
+
+ PhFreeToFreeList(&EtDiskPacketFreeList, packet);
+ }
+
+ // Remove old entries.
+
+ ageListEntry = EtDiskAgeListHead.Blink;
+
+ while (ageListEntry != &EtDiskAgeListHead)
+ {
+ PET_DISK_ITEM diskItem;
+
+ diskItem = CONTAINING_RECORD(ageListEntry, ET_DISK_ITEM, AgeListEntry);
+ ageListEntry = ageListEntry->Blink;
+
+ if (runCount - diskItem->FreshTime < HISTORY_SIZE) // must compare like this to avoid overflow/underflow problems
+ break;
+
+ PhInvokeCallback(&EtDiskItemRemovedEvent, diskItem);
+
+ PhAcquireQueuedLockExclusive(&EtDiskHashtableLock);
+ EtpRemoveDiskItem(diskItem);
+ PhReleaseQueuedLockExclusive(&EtDiskHashtableLock);
+ }
+
+ // Update existing items.
+
+ ageListEntry = EtDiskAgeListHead.Flink;
+
+ while (ageListEntry != &EtDiskAgeListHead)
+ {
+ PET_DISK_ITEM diskItem;
+
+ diskItem = CONTAINING_RECORD(ageListEntry, ET_DISK_ITEM, AgeListEntry);
+
+ // Update statistics.
+
+ if (diskItem->HistoryPosition != 0)
+ diskItem->HistoryPosition--;
+ else
+ diskItem->HistoryPosition = HISTORY_SIZE - 1;
+
+ diskItem->ReadHistory[diskItem->HistoryPosition] = diskItem->ReadDelta;
+ diskItem->WriteHistory[diskItem->HistoryPosition] = diskItem->WriteDelta;
+
+ if (diskItem->HistoryCount < HISTORY_SIZE)
+ diskItem->HistoryCount++;
+
+ diskItem->ReadTotal += diskItem->ReadDelta;
+ diskItem->WriteTotal += diskItem->WriteDelta;
+ diskItem->ReadDelta = 0;
+ diskItem->WriteDelta = 0;
+ diskItem->ReadAverage = EtpCalculateAverage(diskItem->ReadHistory, HISTORY_SIZE, diskItem->HistoryPosition, diskItem->HistoryCount, HISTORY_SIZE);
+ diskItem->WriteAverage = EtpCalculateAverage(diskItem->WriteHistory, HISTORY_SIZE, diskItem->HistoryPosition, diskItem->HistoryCount, HISTORY_SIZE);
+
+ if (diskItem->AddTime != runCount)
+ {
+ BOOLEAN modified = FALSE;
+ PPH_PROCESS_ITEM processItem;
+
+ if (!diskItem->ProcessName || !diskItem->ProcessIconValid)
+ {
+ if (processItem = PhReferenceProcessItem(diskItem->ProcessId))
+ {
+ if (!diskItem->ProcessName)
+ {
+ diskItem->ProcessName = processItem->ProcessName;
+ PhReferenceObject(processItem->ProcessName);
+ modified = TRUE;
+ }
+
+ if (!diskItem->ProcessIconValid && PhTestEvent(&processItem->Stage1Event))
+ {
+ diskItem->ProcessIcon = processItem->SmallIcon;
+ diskItem->ProcessIconValid = TRUE;
+ modified = TRUE;
+ }
+
+ PhDereferenceObject(processItem);
+ }
+ }
+
+ if (modified)
+ {
+ // Raise the disk item modified event.
+ PhInvokeCallback(&EtDiskItemModifiedEvent, diskItem);
+ }
+ }
+
+ ageListEntry = ageListEntry->Flink;
+ }
+
+ PhInvokeCallback(&EtDiskItemsUpdatedEvent, NULL);
+ runCount++;
+}
diff --git a/2.x/trunk/plugins/ExtendedTools/etwmon.c b/2.x/trunk/plugins/ExtendedTools/etwmon.c
index 4f2b5e3cf..83faa615b 100644
--- a/2.x/trunk/plugins/ExtendedTools/etwmon.c
+++ b/2.x/trunk/plugins/ExtendedTools/etwmon.c
@@ -35,24 +35,44 @@ NTSTATUS EtpEtwMonitorThreadStart(
__in PVOID Parameter
);
+ULONG NTAPI EtpRundownEtwBufferCallback(
+ __in PEVENT_TRACE_LOGFILE Buffer
+ );
+
+VOID NTAPI EtpRundownEtwEventCallback(
+ __in PEVENT_RECORD EventRecord
+ );
+
+NTSTATUS EtpRundownEtwMonitorThreadStart(
+ __in PVOID Parameter
+ );
+
static GUID SystemTraceControlGuid_I = { 0x9e814aad, 0x3204, 0x11d2, { 0x9a, 0x82, 0x00, 0x60, 0x08, 0xa8, 0x69, 0x39 } };
+static GUID KernelRundownGuid_I = { 0x3b9c9951, 0x3480, 0x4220, { 0x93, 0x77, 0x9c, 0x8e, 0x51, 0x84, 0xf5, 0xcd } };
static GUID DiskIoGuid_I = { 0x3d6fa8d4, 0xfe05, 0x11d0, { 0x9d, 0xda, 0x00, 0xc0, 0x4f, 0xd7, 0xba, 0x7c } };
+static GUID FileIoGuid_I = { 0x90cbdc39, 0x4a3e, 0x11d1, { 0x84, 0xf4, 0x00, 0x00, 0xf8, 0x04, 0x64, 0xe3 } };
static GUID TcpIpGuid_I = { 0x9a280ac0, 0xc8e0, 0x11d1, { 0x84, 0xe2, 0x00, 0xc0, 0x4f, 0xb9, 0x98, 0xa2 } };
static GUID UdpIpGuid_I = { 0xbf3a50c5, 0xa9c9, 0x4988, { 0xa0, 0x05, 0x2d, 0xf0, 0xb7, 0xc8, 0x0f, 0x80 } };
-// ETW interfacing layer
+// ETW tracing layer
BOOLEAN EtEtwEnabled;
static PH_STRINGREF EtpLoggerName = PH_STRINGREF_INIT(KERNEL_LOGGER_NAME);
static TRACEHANDLE EtpSessionHandle;
-static TRACEHANDLE EtpTraceHandle;
static PEVENT_TRACE_PROPERTIES EtpTraceProperties;
-static EVENT_TRACE_LOGFILE EtpLogFile;
static BOOLEAN EtpEtwActive;
static BOOLEAN EtpStartedSession;
static BOOLEAN EtpEtwExiting;
static HANDLE EtpEtwMonitorThreadHandle;
+// ETW rundown layer
+
+static PH_STRINGREF EtpRundownLoggerName = PH_STRINGREF_INIT(L"PhEtRundownLogger");
+static TRACEHANDLE EtpRundownSessionHandle;
+static PEVENT_TRACE_PROPERTIES EtpRundownTraceProperties;
+static BOOLEAN EtpRundownActive;
+static HANDLE EtpRundownEtwMonitorThreadHandle;
+
VOID EtEtwMonitorInitialization()
{
if (PhElevated && PhGetIntegerSetting(SETTING_NAME_ENABLE_ETW_MONITOR))
@@ -71,6 +91,12 @@ VOID EtEtwMonitorUninitialization()
EtpEtwExiting = TRUE;
EtStopEtwSession();
}
+
+ if (EtpRundownActive)
+ {
+ EtpRundownTraceProperties->LogFileNameOffset = 0;
+ ControlTrace(0, EtpRundownLoggerName.Buffer, EtpRundownTraceProperties, EVENT_TRACE_CONTROL_STOP);
+ }
}
VOID EtStartEtwSession()
@@ -92,7 +118,7 @@ VOID EtStartEtwSession()
EtpTraceProperties->MinimumBuffers = 1;
EtpTraceProperties->LogFileMode = EVENT_TRACE_REAL_TIME_MODE;
EtpTraceProperties->FlushTimer = 1;
- EtpTraceProperties->EnableFlags = EVENT_TRACE_FLAG_DISK_IO | EVENT_TRACE_FLAG_NETWORK_TCPIP;
+ EtpTraceProperties->EnableFlags = EVENT_TRACE_FLAG_DISK_IO | EVENT_TRACE_FLAG_DISK_FILE_IO | EVENT_TRACE_FLAG_NETWORK_TCPIP;
EtpTraceProperties->LogFileNameOffset = 0;
EtpTraceProperties->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES);
@@ -165,6 +191,7 @@ VOID NTAPI EtpEtwEventCallback(
ET_ETW_DISK_EVENT diskEvent;
memset(&diskEvent, 0, sizeof(ET_ETW_DISK_EVENT));
+ diskEvent.Type = -1;
switch (EventTrace->Header.Class.Type)
{
@@ -178,7 +205,7 @@ VOID NTAPI EtpEtwEventCallback(
break;
}
- if (diskEvent.Type != 0)
+ if (diskEvent.Type != -1)
{
DiskIo_TypeGroup1 *data = EventTrace->MofData;
@@ -189,8 +216,45 @@ VOID NTAPI EtpEtwEventCallback(
}
diskEvent.TransferSize = data->TransferSize;
+ diskEvent.FileObject = (PVOID)data->FileObject;
+ diskEvent.HighResResponseTime = data->HighResResponseTime;
EtProcessDiskEvent(&diskEvent);
+ EtDiskProcessDiskEvent(&diskEvent);
+ }
+ }
+ else if (memcmp(&EventTrace->Header.Guid, &FileIoGuid_I, sizeof(GUID)) == 0)
+ {
+ // FileIo
+
+ ET_ETW_FILE_EVENT fileEvent;
+
+ memset(&fileEvent, 0, sizeof(ET_ETW_FILE_EVENT));
+ fileEvent.Type = -1;
+
+ switch (EventTrace->Header.Class.Type)
+ {
+ case 0: // Name
+ fileEvent.Type = EtEtwFileNameType;
+ break;
+ case 32: // FileCreate
+ fileEvent.Type = EtEtwFileCreateType;
+ break;
+ case 35: // FileDelete
+ fileEvent.Type = EtEtwFileDeleteType;
+ break;
+ default:
+ break;
+ }
+
+ if (fileEvent.Type != -1)
+ {
+ FileIo_Name *data = EventTrace->MofData;
+
+ fileEvent.FileObject = (PVOID)data->FileObject;
+ PhInitializeStringRef(&fileEvent.FileName, data->FileName);
+
+ EtDiskProcessFileEvent(&fileEvent);
}
}
else if (
@@ -203,22 +267,23 @@ VOID NTAPI EtpEtwEventCallback(
ET_ETW_NETWORK_EVENT networkEvent;
memset(&networkEvent, 0, sizeof(ET_ETW_NETWORK_EVENT));
+ networkEvent.Type = -1;
switch (EventTrace->Header.Class.Type)
{
- case 10: // send
+ case EVENT_TRACE_TYPE_SEND: // send
networkEvent.Type = EtEtwNetworkSendType;
networkEvent.ProtocolType = PH_IPV4_NETWORK_TYPE;
break;
- case 11: // receive
+ case EVENT_TRACE_TYPE_RECEIVE: // receive
networkEvent.Type = EtEtwNetworkReceiveType;
networkEvent.ProtocolType = PH_IPV4_NETWORK_TYPE;
break;
- case 26: // send ipv6
+ case EVENT_TRACE_TYPE_SEND + 16: // send ipv6
networkEvent.Type = EtEtwNetworkSendType;
networkEvent.ProtocolType = PH_IPV6_NETWORK_TYPE;
break;
- case 27: // receive ipv6
+ case EVENT_TRACE_TYPE_RECEIVE + 16: // receive ipv6
networkEvent.Type = EtEtwNetworkReceiveType;
networkEvent.ProtocolType = PH_IPV6_NETWORK_TYPE;
break;
@@ -229,7 +294,7 @@ VOID NTAPI EtpEtwEventCallback(
else
networkEvent.ProtocolType |= PH_UDP_PROTOCOL_TYPE;
- if (networkEvent.Type != 0)
+ if (networkEvent.Type != -1)
{
PH_IP_ENDPOINT source;
PH_IP_ENDPOINT destination;
@@ -273,29 +338,30 @@ VOID NTAPI EtpEtwEventCallback(
}
}
-NTSTATUS NTAPI EtpEtwMonitorThreadStart(
+NTSTATUS EtpEtwMonitorThreadStart(
__in PVOID Parameter
)
{
ULONG result;
+ EVENT_TRACE_LOGFILE logFile;
+ TRACEHANDLE traceHandle;
- memset(&EtpLogFile, 0, sizeof(EVENT_TRACE_LOGFILE));
- EtpLogFile.LoggerName = EtpLoggerName.Buffer;
- EtpLogFile.ProcessTraceMode = PROCESS_TRACE_MODE_REAL_TIME;
- EtpLogFile.BufferCallback = EtpEtwBufferCallback;
- EtpLogFile.EventCallback = EtpEtwEventCallback;
- EtpLogFile.IsKernelTrace = TRUE;
+ memset(&logFile, 0, sizeof(EVENT_TRACE_LOGFILE));
+ logFile.LoggerName = EtpLoggerName.Buffer;
+ logFile.ProcessTraceMode = PROCESS_TRACE_MODE_REAL_TIME;
+ logFile.BufferCallback = EtpEtwBufferCallback;
+ logFile.EventCallback = EtpEtwEventCallback;
while (TRUE)
{
- EtpTraceHandle = OpenTrace(&EtpLogFile);
+ traceHandle = OpenTrace(&logFile);
- if (EtpTraceHandle != INVALID_PROCESSTRACE_HANDLE)
+ if (traceHandle != INVALID_PROCESSTRACE_HANDLE)
{
- while (!EtpEtwExiting && (result = ProcessTrace(&EtpTraceHandle, 1, NULL, NULL)) == ERROR_SUCCESS)
+ while (!EtpEtwExiting && (result = ProcessTrace(&traceHandle, 1, NULL, NULL)) == ERROR_SUCCESS)
NOTHING;
- CloseTrace(EtpTraceHandle);
+ CloseTrace(traceHandle);
}
if (EtpEtwExiting)
@@ -315,3 +381,132 @@ NTSTATUS NTAPI EtpEtwMonitorThreadStart(
return STATUS_SUCCESS;
}
+
+ULONG EtStartEtwRundown()
+{
+ ULONG result;
+ ULONG bufferSize;
+
+ bufferSize = sizeof(EVENT_TRACE_PROPERTIES) + EtpRundownLoggerName.Length + sizeof(WCHAR);
+
+ if (!EtpRundownTraceProperties)
+ EtpRundownTraceProperties = PhAllocate(bufferSize);
+
+ memset(EtpRundownTraceProperties, 0, sizeof(EVENT_TRACE_PROPERTIES));
+
+ EtpRundownTraceProperties->Wnode.BufferSize = bufferSize;
+ EtpRundownTraceProperties->Wnode.ClientContext = 1;
+ EtpRundownTraceProperties->Wnode.Flags = WNODE_FLAG_TRACED_GUID;
+ EtpRundownTraceProperties->MinimumBuffers = 1;
+ EtpRundownTraceProperties->LogFileMode = EVENT_TRACE_REAL_TIME_MODE;
+ EtpRundownTraceProperties->FlushTimer = 1;
+ EtpRundownTraceProperties->LogFileNameOffset = 0;
+ EtpRundownTraceProperties->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES);
+
+ result = StartTrace(&EtpRundownSessionHandle, EtpRundownLoggerName.Buffer, EtpRundownTraceProperties);
+
+ if (result == ERROR_ALREADY_EXISTS)
+ {
+ EtpRundownTraceProperties->LogFileNameOffset = 0;
+ ControlTrace(0, EtpRundownLoggerName.Buffer, EtpRundownTraceProperties, EVENT_TRACE_CONTROL_STOP);
+ // ControlTrace screws up the structure.
+ EtpRundownTraceProperties->Wnode.BufferSize = bufferSize;
+ EtpRundownTraceProperties->LogFileNameOffset = 0;
+ EtpRundownTraceProperties->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES);
+ result = StartTrace(&EtpRundownSessionHandle, EtpRundownLoggerName.Buffer, EtpRundownTraceProperties);
+ }
+
+ if (result != ERROR_SUCCESS)
+ return result;
+
+ result = EnableTraceEx(&KernelRundownGuid_I, NULL, EtpRundownSessionHandle, 1, 0, 0x10, 0, 0, NULL);
+
+ if (result != ERROR_SUCCESS)
+ {
+ EtpRundownTraceProperties->LogFileNameOffset = 0;
+ ControlTrace(0, EtpRundownLoggerName.Buffer, EtpRundownTraceProperties, EVENT_TRACE_CONTROL_STOP);
+ return result;
+ }
+
+ EtpRundownActive = TRUE;
+ EtpRundownEtwMonitorThreadHandle = PhCreateThread(0, EtpRundownEtwMonitorThreadStart, NULL);
+
+ return result;
+}
+
+ULONG NTAPI EtpRundownEtwBufferCallback(
+ __in PEVENT_TRACE_LOGFILE Buffer
+ )
+{
+ return !EtpEtwExiting;
+}
+
+VOID NTAPI EtpRundownEtwEventCallback(
+ __in PEVENT_RECORD EventRecord
+ )
+{
+ // TODO: Find a way to call CloseTrace when the enumeration finishes so we can
+ // stop the trace cleanly.
+
+ if (memcmp(&EventRecord->EventHeader.ProviderId, &FileIoGuid_I, sizeof(GUID)) == 0)
+ {
+ // FileIo
+
+ ET_ETW_FILE_EVENT fileEvent;
+
+ memset(&fileEvent, 0, sizeof(ET_ETW_FILE_EVENT));
+ fileEvent.Type = -1;
+
+ switch (EventRecord->EventHeader.EventDescriptor.Opcode)
+ {
+ case 36: // FileRundown
+ fileEvent.Type = EtEtwFileRundownType;
+ break;
+ default:
+ break;
+ }
+
+ if (fileEvent.Type != -1)
+ {
+ FileIo_Name *data = EventRecord->UserData;
+
+ fileEvent.FileObject = (PVOID)data->FileObject;
+ PhInitializeStringRef(&fileEvent.FileName, data->FileName);
+
+ EtDiskProcessFileEvent(&fileEvent);
+ }
+ }
+}
+
+NTSTATUS EtpRundownEtwMonitorThreadStart(
+ __in PVOID Parameter
+ )
+{
+ EVENT_TRACE_LOGFILE logFile;
+ TRACEHANDLE traceHandle;
+
+ memset(&logFile, 0, sizeof(EVENT_TRACE_LOGFILE));
+ logFile.LoggerName = EtpRundownLoggerName.Buffer;
+ logFile.ProcessTraceMode = PROCESS_TRACE_MODE_REAL_TIME | PROCESS_TRACE_MODE_EVENT_RECORD;
+ logFile.BufferCallback = EtpRundownEtwBufferCallback;
+ logFile.EventRecordCallback = EtpRundownEtwEventCallback;
+ logFile.Context = &traceHandle;
+
+ traceHandle = OpenTrace(&logFile);
+
+ if (traceHandle != INVALID_PROCESSTRACE_HANDLE)
+ {
+ ProcessTrace(&traceHandle, 1, NULL, NULL);
+
+ if (traceHandle != 0)
+ CloseTrace(traceHandle);
+
+ EtpRundownTraceProperties->LogFileNameOffset = 0;
+ ControlTrace(0, EtpRundownLoggerName.Buffer, EtpRundownTraceProperties, EVENT_TRACE_CONTROL_STOP);
+ }
+
+ NtClose(EtpRundownEtwMonitorThreadHandle);
+ EtpRundownEtwMonitorThreadHandle = NULL;
+
+ return STATUS_SUCCESS;
+}
diff --git a/2.x/trunk/plugins/ExtendedTools/etwmon.h b/2.x/trunk/plugins/ExtendedTools/etwmon.h
index 8e75fcb16..935f85789 100644
--- a/2.x/trunk/plugins/ExtendedTools/etwmon.h
+++ b/2.x/trunk/plugins/ExtendedTools/etwmon.h
@@ -3,45 +3,42 @@
#include
-typedef ULONG wmi_uint32;
-typedef ULONG wmi_IPAddrV4;
-typedef IN6_ADDR wmi_IPAddrV6;
-typedef USHORT wmi_Port;
-
typedef struct
{
- wmi_uint32 LowPart;
- wmi_uint32 HighPart;
-} wmi_uint64;
-
-typedef struct
-{
- wmi_uint32 DiskNumber;
- wmi_uint32 IrpFlags;
- wmi_uint32 TransferSize;
- wmi_uint32 ResponseTime;
- wmi_uint64 ByteOffset;
- // Other members not included.
+ ULONG DiskNumber;
+ ULONG IrpFlags;
+ ULONG TransferSize;
+ ULONG ResponseTime;
+ ULONG64 ByteOffset;
+ ULONG_PTR FileObject;
+ ULONG_PTR Irp;
+ ULONG64 HighResResponseTime;
} DiskIo_TypeGroup1;
typedef struct
{
- wmi_uint32 PID;
- wmi_uint32 size;
- wmi_IPAddrV4 daddr;
- wmi_IPAddrV4 saddr;
- wmi_Port dport;
- wmi_Port sport;
+ ULONG_PTR FileObject;
+ WCHAR FileName[1];
+} FileIo_Name;
+
+typedef struct
+{
+ ULONG PID;
+ ULONG size;
+ ULONG daddr;
+ ULONG saddr;
+ USHORT dport;
+ USHORT sport;
} TcpIpOrUdpIp_IPV4_Header;
typedef struct
{
- wmi_uint32 PID;
- wmi_uint32 size;
- wmi_IPAddrV6 daddr;
- wmi_IPAddrV6 saddr;
- wmi_Port dport;
- wmi_Port sport;
+ ULONG PID;
+ ULONG size;
+ IN6_ADDR daddr;
+ IN6_ADDR saddr;
+ USHORT dport;
+ USHORT sport;
} TcpIpOrUdpIp_IPV6_Header;
// etwmon
@@ -56,12 +53,18 @@ VOID EtStopEtwSession();
VOID EtFlushEtwSession();
+ULONG EtStartEtwRundown();
+
// etwstat
typedef enum _ET_ETW_EVENT_TYPE
{
EtEtwDiskReadType = 1,
EtEtwDiskWriteType,
+ EtEtwFileNameType,
+ EtEtwFileCreateType,
+ EtEtwFileDeleteType,
+ EtEtwFileRundownType,
EtEtwNetworkReceiveType,
EtEtwNetworkSendType
} ET_ETW_EVENT_TYPE;
@@ -71,8 +74,17 @@ typedef struct _ET_ETW_DISK_EVENT
ET_ETW_EVENT_TYPE Type;
CLIENT_ID ClientId;
ULONG TransferSize;
+ PVOID FileObject;
+ ULONG64 HighResResponseTime;
} ET_ETW_DISK_EVENT, *PET_ETW_DISK_EVENT;
+typedef struct _ET_ETW_FILE_EVENT
+{
+ ET_ETW_EVENT_TYPE Type;
+ PVOID FileObject;
+ PH_STRINGREF FileName;
+} ET_ETW_FILE_EVENT, *PET_ETW_FILE_EVENT;
+
typedef struct _ET_ETW_NETWORK_EVENT
{
ET_ETW_EVENT_TYPE Type;
@@ -83,6 +95,8 @@ typedef struct _ET_ETW_NETWORK_EVENT
PH_IP_ENDPOINT RemoteEndpoint;
} ET_ETW_NETWORK_EVENT, *PET_ETW_NETWORK_EVENT;
+// etwstat
+
VOID EtProcessDiskEvent(
__in PET_ETW_DISK_EVENT Event
);
@@ -91,4 +105,14 @@ VOID EtProcessNetworkEvent(
__in PET_ETW_NETWORK_EVENT Event
);
+// etwdisk
+
+VOID EtDiskProcessDiskEvent(
+ __in PET_ETW_DISK_EVENT Event
+ );
+
+VOID EtDiskProcessFileEvent(
+ __in PET_ETW_FILE_EVENT Event
+ );
+
#endif
diff --git a/2.x/trunk/plugins/ExtendedTools/etwprprp.c b/2.x/trunk/plugins/ExtendedTools/etwprprp.c
index 17b6ac797..06350f117 100644
--- a/2.x/trunk/plugins/ExtendedTools/etwprprp.c
+++ b/2.x/trunk/plugins/ExtendedTools/etwprprp.c
@@ -45,7 +45,7 @@ INT_PTR CALLBACK EtpDiskNetworkPageDlgProc(
__in LPARAM lParam
);
-VOID EtEtwProcessPropertiesInitializing(
+VOID EtProcessEtwPropertiesInitializing(
__in PVOID Parameter
)
{
diff --git a/2.x/trunk/plugins/ExtendedTools/etwstat.c b/2.x/trunk/plugins/ExtendedTools/etwstat.c
index 83cef31b3..39e316c56 100644
--- a/2.x/trunk/plugins/ExtendedTools/etwstat.c
+++ b/2.x/trunk/plugins/ExtendedTools/etwstat.c
@@ -33,6 +33,8 @@ VOID NTAPI NetworkItemsUpdatedCallback(
__in_opt PVOID Context
);
+VOID EtpUpdateDiskInformation();
+
static PH_CALLBACK_REGISTRATION EtpProcessesUpdatedCallbackRegistration;
static PH_CALLBACK_REGISTRATION EtpNetworkItemsUpdatedCallbackRegistration;
diff --git a/2.x/trunk/plugins/ExtendedTools/etwsys.c b/2.x/trunk/plugins/ExtendedTools/etwsys.c
index 8bd88bce2..79560e04b 100644
--- a/2.x/trunk/plugins/ExtendedTools/etwsys.c
+++ b/2.x/trunk/plugins/ExtendedTools/etwsys.c
@@ -65,7 +65,7 @@ static PH_GRAPH_STATE NetworkGraphState;
static RECT EtpNormalGraphTextMargin = { 5, 5, 5, 5 };
static RECT EtpNormalGraphTextPadding = { 3, 3, 3, 3 };
-VOID EtEtwShowSystemDialog()
+VOID EtShowEtwSystemDialog()
{
if (!EtpEtwSysWindowHandle)
{
diff --git a/2.x/trunk/plugins/ExtendedTools/exttools.h b/2.x/trunk/plugins/ExtendedTools/exttools.h
index b7510a3e2..7b2cc1068 100644
--- a/2.x/trunk/plugins/ExtendedTools/exttools.h
+++ b/2.x/trunk/plugins/ExtendedTools/exttools.h
@@ -11,22 +11,107 @@ extern HWND ProcessTreeNewHandle;
extern HWND NetworkTreeNewHandle;
#define SETTING_PREFIX L"ProcessHacker.ExtendedTools."
+#define SETTING_NAME_DISK_TREE_LIST_COLUMNS (SETTING_PREFIX L"DiskTreeListColumns")
+#define SETTING_NAME_DISK_TREE_LIST_SORT (SETTING_PREFIX L"DiskTreeListSort")
#define SETTING_NAME_ENABLE_ETW_MONITOR (SETTING_PREFIX L"EnableEtwMonitor")
#define SETTING_NAME_ETWSYS_ALWAYS_ON_TOP (SETTING_PREFIX L"EtwSysAlwaysOnTop")
#define SETTING_NAME_ETWSYS_WINDOW_POSITION (SETTING_PREFIX L"EtwSysWindowPosition")
#define SETTING_NAME_ETWSYS_WINDOW_SIZE (SETTING_PREFIX L"EtwSysWindowSize")
#define SETTING_NAME_MEMORY_LISTS_WINDOW_POSITION (SETTING_PREFIX L"MemoryListsWindowPosition")
+#define HISTORY_SIZE 60
+
+typedef struct _ET_DISK_ITEM
+{
+ LIST_ENTRY AgeListEntry;
+ ULONG AddTime;
+ ULONG FreshTime;
+
+ HANDLE ProcessId;
+ PPH_STRING FileName;
+ PPH_STRING FileNameWin32;
+
+ PPH_STRING ProcessName;
+ HICON ProcessIcon;
+ BOOLEAN ProcessIconValid;
+
+ ULONG64 ReadTotal;
+ ULONG64 WriteTotal;
+ ULONG64 ReadDelta;
+ ULONG64 WriteDelta;
+ ULONG64 ReadAverage;
+ ULONG64 WriteAverage;
+
+ ULONG64 ReadHistory[HISTORY_SIZE];
+ ULONG64 WriteHistory[HISTORY_SIZE];
+ ULONG HistoryCount;
+ ULONG HistoryPosition;
+} ET_DISK_ITEM, *PET_DISK_ITEM;
+
// etwmon
extern BOOLEAN EtEtwEnabled;
+// etwdisk
+
+extern BOOLEAN EtDiskEnabled;
+
+extern PPH_OBJECT_TYPE EtDiskItemType;
+extern PH_CALLBACK EtDiskItemAddedEvent;
+extern PH_CALLBACK EtDiskItemModifiedEvent;
+extern PH_CALLBACK EtDiskItemRemovedEvent;
+extern PH_CALLBACK EtDiskItemsUpdatedEvent;
+
+VOID EtInitializeDiskInformation();
+
+PET_DISK_ITEM EtCreateDiskItem();
+
+PET_DISK_ITEM EtReferenceDiskItem(
+ __in HANDLE ProcessId,
+ __in PPH_STRING FileName
+ );
+
+PPH_STRING EtFileObjectToFileName(
+ __in PVOID FileObject
+ );
+
// etwprprp
-VOID EtEtwProcessPropertiesInitializing(
+VOID EtProcessEtwPropertiesInitializing(
__in PVOID Parameter
);
+// disktab
+
+#define ETDSTNC_NAME 0
+#define ETDSTNC_FILE 1
+#define ETDSTNC_READRATEAVERAGE 2
+#define ETDSTNC_WRITERATEAVERAGE 3
+#define ETDSTNC_TOTALRATEAVERAGE 4
+#define ETDSTNC_MAXIMUM 5
+
+typedef struct _ET_DISK_NODE
+{
+ PH_TREENEW_NODE Node;
+
+ PET_DISK_ITEM DiskItem;
+
+ PH_STRINGREF TextCache[ETDSTNC_MAXIMUM];
+
+ PPH_STRING ProcessNameText;
+ PPH_STRING ReadRateAverageText;
+ PPH_STRING WriteRateAverageText;
+ PPH_STRING TotalRateAverageText;
+
+ PPH_STRING TooltipText;
+} ET_DISK_NODE, *PET_DISK_NODE;
+
+VOID EtInitializeDiskTab();
+
+VOID EtLoadSettingsDiskTreeList();
+
+VOID EtSaveSettingsDiskTreeList();
+
// treeext
#define ETPRTNC_DISKREADS 1
@@ -54,11 +139,11 @@ VOID EtEtwProcessPropertiesInitializing(
#define ETPRTNC_PEAKTHREADS 23
#define ETPRTNC_MAXIMUM 23
-VOID EtEtwProcessTreeNewInitializing(
+VOID EtProcessTreeNewInitializing(
__in PVOID Parameter
);
-VOID EtEtwProcessTreeNewMessage(
+VOID EtProcessTreeNewMessage(
__in PVOID Parameter
);
@@ -75,11 +160,11 @@ VOID EtEtwProcessTreeNewMessage(
#define ETNETNC_FIREWALLSTATUS 11
#define ETNETNC_MAXIMUM 11
-VOID EtEtwNetworkTreeNewInitializing(
+VOID EtNetworkTreeNewInitializing(
__in PVOID Parameter
);
-VOID EtEtwNetworkTreeNewMessage(
+VOID EtNetworkTreeNewMessage(
__in PVOID Parameter
);
@@ -122,7 +207,7 @@ VOID EtEtwStatisticsUninitialization();
// etwsys
-VOID EtEtwShowSystemDialog();
+VOID EtShowEtwSystemDialog();
// memlists
diff --git a/2.x/trunk/plugins/ExtendedTools/main.c b/2.x/trunk/plugins/ExtendedTools/main.c
index 26e55b5a7..64ce96560 100644
--- a/2.x/trunk/plugins/ExtendedTools/main.c
+++ b/2.x/trunk/plugins/ExtendedTools/main.c
@@ -281,6 +281,8 @@ LOGICAL DllMain(
{
static PH_SETTING_CREATE settings[] =
{
+ { StringSettingType, SETTING_NAME_DISK_TREE_LIST_COLUMNS, L"" },
+ { IntegerPairSettingType, SETTING_NAME_DISK_TREE_LIST_SORT, L"4,2" }, // 4, DescendingSortOrder
{ IntegerSettingType, SETTING_NAME_ENABLE_ETW_MONITOR, L"1" },
{ IntegerSettingType, SETTING_NAME_ETWSYS_ALWAYS_ON_TOP, L"0" },
{ IntegerPairSettingType, SETTING_NAME_ETWSYS_WINDOW_POSITION, L"400,400" },
@@ -310,6 +312,7 @@ VOID NTAPI UnloadCallback(
__in_opt PVOID Context
)
{
+ EtSaveSettingsDiskTreeList();
EtEtwStatisticsUninitialization();
}
@@ -332,7 +335,7 @@ VOID NTAPI MenuItemCallback(
{
case ID_VIEW_DISKANDNETWORK:
{
- EtEtwShowSystemDialog();
+ EtShowEtwSystemDialog();
}
break;
case ID_VIEW_MEMORYLISTS:
@@ -375,9 +378,9 @@ VOID NTAPI TreeNewMessageCallback(
PPH_PLUGIN_TREENEW_MESSAGE message = Parameter;
if (message->TreeNewHandle == ProcessTreeNewHandle)
- EtEtwProcessTreeNewMessage(Parameter);
+ EtProcessTreeNewMessage(Parameter);
else if (message->TreeNewHandle == NetworkTreeNewHandle)
- EtEtwNetworkTreeNewMessage(Parameter);
+ EtNetworkTreeNewMessage(Parameter);
}
VOID NTAPI MainWindowShowingCallback(
@@ -391,6 +394,8 @@ VOID NTAPI MainWindowShowingCallback(
{
// This will get inserted before Memory Lists.
PhPluginAddMenuItem(PluginInstance, PH_MENU_ITEM_LOCATION_VIEW, L"System Information", ID_VIEW_DISKANDNETWORK, L"Disk and Network", NULL);
+
+ EtInitializeDiskTab();
}
}
@@ -399,7 +404,7 @@ VOID NTAPI ProcessPropertiesInitializingCallback(
__in_opt PVOID Context
)
{
- EtEtwProcessPropertiesInitializing(Parameter);
+ EtProcessEtwPropertiesInitializing(Parameter);
}
VOID NTAPI HandlePropertiesInitializingCallback(
@@ -516,7 +521,7 @@ VOID NTAPI ProcessTreeNewInitializingCallback(
PPH_PLUGIN_TREENEW_INFORMATION treeNewInfo = Parameter;
ProcessTreeNewHandle = treeNewInfo->TreeNewHandle;
- EtEtwProcessTreeNewInitializing(Parameter);
+ EtProcessTreeNewInitializing(Parameter);
}
VOID NTAPI NetworkTreeNewInitializingCallback(
@@ -527,7 +532,7 @@ VOID NTAPI NetworkTreeNewInitializingCallback(
PPH_PLUGIN_TREENEW_INFORMATION treeNewInfo = Parameter;
NetworkTreeNewHandle = treeNewInfo->TreeNewHandle;
- EtEtwNetworkTreeNewInitializing(Parameter);
+ EtNetworkTreeNewInitializing(Parameter);
}
static VOID NTAPI ProcessesUpdatedCallback(
diff --git a/2.x/trunk/plugins/ExtendedTools/resource.h b/2.x/trunk/plugins/ExtendedTools/resource.h
index d792a87ea..c0fb9ef87 100644
--- a/2.x/trunk/plugins/ExtendedTools/resource.h
+++ b/2.x/trunk/plugins/ExtendedTools/resource.h
@@ -22,6 +22,8 @@
#define IDD_OPTIONS 109
#define IDD_WSWATCH 110
#define IDR_EMPTYMEMLISTS 111
+#define IDR_MENU1 112
+#define IDR_DISK 112
#define IDC_LIST 1001
#define IDC_REFRESH 1002
#define IDC_SEQUENCENUMBER 1003
@@ -78,13 +80,17 @@
#define ID_EMPTY_EMPTYMODIFIEDPAGELIST 40002
#define ID_EMPTY_EMPTYSTANDBYLIST 40003
#define ID_EMPTY_EMPTYPRIORITY0STANDBYLIST 40004
+#define ID_DISK_GOTOPROCESS 40005
+#define ID_DISK_COPY 40006
+#define ID_DISK_PROPERTIES 40007
+#define ID_DISK_OPENFILELOCATION 40008
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
-#define _APS_NEXT_RESOURCE_VALUE 112
-#define _APS_NEXT_COMMAND_VALUE 40005
+#define _APS_NEXT_RESOURCE_VALUE 113
+#define _APS_NEXT_COMMAND_VALUE 40009
#define _APS_NEXT_CONTROL_VALUE 1052
#define _APS_NEXT_SYMED_VALUE 109
#endif
diff --git a/2.x/trunk/plugins/ExtendedTools/treeext.c b/2.x/trunk/plugins/ExtendedTools/treeext.c
index 842b7ad4d..d80f694e0 100644
--- a/2.x/trunk/plugins/ExtendedTools/treeext.c
+++ b/2.x/trunk/plugins/ExtendedTools/treeext.c
@@ -82,7 +82,7 @@ VOID EtpAddTreeNewColumn(
);
}
-VOID EtEtwProcessTreeNewInitializing(
+VOID EtProcessTreeNewInitializing(
__in PVOID Parameter
)
{
@@ -123,7 +123,7 @@ VOID EtEtwProcessTreeNewInitializing(
}
}
-VOID EtEtwProcessTreeNewMessage(
+VOID EtProcessTreeNewMessage(
__in PVOID Parameter
)
{
@@ -350,7 +350,7 @@ LONG EtpProcessTreeNewSortFunction(
return result;
}
-VOID EtEtwNetworkTreeNewInitializing(
+VOID EtNetworkTreeNewInitializing(
__in PVOID Parameter
)
{
@@ -390,7 +390,7 @@ VOID EtpUpdateFirewallStatus(
}
}
-VOID EtEtwNetworkTreeNewMessage(
+VOID EtNetworkTreeNewMessage(
__in PVOID Parameter
)
{