* ExtendedTools: added Disk tab

* AvgCpuPlugin: fixed calculation bug
* fixed network list saving
* added callbacks to PH_ADDITIONAL_TAB_PAGE
* moved PhUnloadPlugins() call to allow plugins to save settings
* fixed thread list bug

git-svn-id: svn://svn.code.sf.net/p/processhacker/code@4485 21ef857c-d57f-4fe0-8362-d861dc6d29cd
This commit is contained in:
wj32
2011-08-20 06:51:52 +00:00
parent 64330d1e53
commit e3317f25c4
26 changed files with 2066 additions and 100 deletions
+2
View File
@@ -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:
+1 -1
View File
@@ -233,7 +233,7 @@ VOID PhMwpNotifyTabControl(
);
VOID PhMwpSelectionChangedTabControl(
VOID
__in ULONG OldIndex
);
PPH_ADDITIONAL_TAB_PAGE PhMwpAddTabPage(
+12
View File
@@ -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
@@ -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;
+49 -22
View File
@@ -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(
+41
View File
@@ -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
+3 -1
View File
@@ -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));
+1
View File
@@ -32,6 +32,7 @@ PPH_FULL_STRING PhGetTreeNewText(
__in ULONG MaximumNumberOfColumns
);
PHLIBAPI
PPH_LIST PhGetGenericTreeNewLines(
__in HWND TreeNewHandle,
__in ULONG Mode
+7
View File
@@ -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,
+4 -6
View File
@@ -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);
@@ -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
@@ -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
/////////////////////////////////////////////////////////////////////////////
@@ -84,6 +84,7 @@
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
<CallingConvention>StdCall</CallingConvention>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<TreatWarningAsError>true</TreatWarningAsError>
</ClCompile>
<Link>
<AdditionalDependencies>ProcessHacker.lib;ntdll.lib;%(AdditionalDependencies)</AdditionalDependencies>
@@ -107,6 +108,7 @@
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<CallingConvention>StdCall</CallingConvention>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<TreatWarningAsError>true</TreatWarningAsError>
</ClCompile>
<Link>
<AdditionalDependencies>ProcessHacker.lib;ntdll.lib;%(AdditionalDependencies)</AdditionalDependencies>
@@ -128,6 +130,7 @@
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<CallingConvention>StdCall</CallingConvention>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<TreatWarningAsError>true</TreatWarningAsError>
</ClCompile>
<Link>
<AdditionalDependencies>ProcessHacker.lib;ntdll.lib;%(AdditionalDependencies)</AdditionalDependencies>
@@ -155,6 +158,7 @@
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<CallingConvention>StdCall</CallingConvention>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<TreatWarningAsError>true</TreatWarningAsError>
</ClCompile>
<Link>
<AdditionalDependencies>ProcessHacker.lib;ntdll.lib;%(AdditionalDependencies)</AdditionalDependencies>
@@ -168,6 +172,8 @@
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="disktab.c" />
<ClCompile Include="etwdisk.c" />
<ClCompile Include="etwmon.c" />
<ClCompile Include="treeext.c" />
<ClCompile Include="etwstat.c" />
@@ -183,6 +189,7 @@
<ClCompile Include="wswatch.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="disktabp.h" />
<ClInclude Include="etwmon.h" />
<ClInclude Include="exttools.h" />
<ClInclude Include="resource.h" />
@@ -54,6 +54,12 @@
<ClCompile Include="treeext.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="etwdisk.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="disktab.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="resource.h">
@@ -65,6 +71,9 @@
<ClInclude Include="etwmon.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="disktabp.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="CHANGELOG.txt" />
+858
View File
@@ -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 <http://www.gnu.org/licenses/>.
*/
#include "exttools.h"
#include "etwmon.h"
#include "resource.h"
#include <colmgr.h>
#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);
}
+126
View File
@@ -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
+545
View File
@@ -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 <http://www.gnu.org/licenses/>.
*/
#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++;
}
+216 -21
View File
@@ -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;
}
+53 -29
View File
@@ -3,45 +3,42 @@
#include <evntcons.h>
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
+1 -1
View File
@@ -45,7 +45,7 @@ INT_PTR CALLBACK EtpDiskNetworkPageDlgProc(
__in LPARAM lParam
);
VOID EtEtwProcessPropertiesInitializing(
VOID EtProcessEtwPropertiesInitializing(
__in PVOID Parameter
)
{
@@ -33,6 +33,8 @@ VOID NTAPI NetworkItemsUpdatedCallback(
__in_opt PVOID Context
);
VOID EtpUpdateDiskInformation();
static PH_CALLBACK_REGISTRATION EtpProcessesUpdatedCallbackRegistration;
static PH_CALLBACK_REGISTRATION EtpNetworkItemsUpdatedCallbackRegistration;
+1 -1
View File
@@ -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)
{
+91 -6
View File
@@ -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
+11 -6
View File
@@ -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(
+8 -2
View File
@@ -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
+4 -4
View File
@@ -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
)
{