2 * PROJECT: ReactOS Task Manager
3 * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
4 * PURPOSE: Processes Page
5 * COPYRIGHT: Copyright 1999-2001 Brian Palmer <brianp@reactos.org>
6 * Copyright 2009 Maxime Vernier <maxime.vernier@gmail.com>
7 * Copyright 2022 Thamatip Chitpong <tangaming123456@outlook.com>
14 #include <ndk/psfuncs.h>
17 (x1 < x2 ? -1 : (x1 > x2 ? 1 : 0))
19 #define CONST_STR_LEN(str) (_countof(str) - 1)
24 } PROCESS_PAGE_LIST_ITEM
, *LPPROCESS_PAGE_LIST_ITEM
;
26 HWND hProcessPage
; /* Process List Property Page */
28 HWND hProcessPageListCtrl
; /* Process ListCtrl Window */
29 HWND hProcessPageHeaderCtrl
; /* Process Header Control */
30 static HWND hProcessPageEndProcessButton
; /* Process End Process button */
31 static HWND hProcessPageShowAllProcessesButton
;/* Process Show All Processes checkbox */
32 BOOL bProcessPageSelectionMade
= FALSE
; /* Is item in ListCtrl selected */
34 static int nProcessPageWidth
;
35 static int nProcessPageHeight
;
37 static HANDLE hProcessThread
= NULL
;
38 static DWORD dwProcessThread
;
41 int CALLBACK
ProcessPageCompareFunc(LPARAM lParam1
, LPARAM lParam2
, LPARAM lParamSort
);
42 void AddProcess(ULONG Index
);
43 void UpdateProcesses();
44 void gethmsfromlargeint(LARGE_INTEGER largeint
, DWORD
*dwHours
, DWORD
*dwMinutes
, DWORD
*dwSeconds
);
45 void ProcessPageOnNotify(WPARAM wParam
, LPARAM lParam
);
46 void ProcessPageShowContextMenu(DWORD dwProcessId
);
47 BOOL
PerfDataGetText(ULONG Index
, ULONG ColumnIndex
, LPTSTR lpText
, ULONG nMaxCount
);
48 DWORD WINAPI
ProcessPageRefreshThread(void *lpParameter
);
49 int ProcessRunning(ULONG ProcessId
);
55 LPPROCESS_PAGE_LIST_ITEM pData
;
56 for (i
= 0; i
< ListView_GetItemCount(hProcessPageListCtrl
); i
++)
58 memset(&item
, 0, sizeof(LV_ITEM
));
59 item
.mask
= LVIF_PARAM
;
61 (void)ListView_GetItem(hProcessPageListCtrl
, &item
);
62 pData
= (LPPROCESS_PAGE_LIST_ITEM
)item
.lParam
;
63 HeapFree(GetProcessHeap(), 0, pData
);
67 int ProcGetIndexByProcessId(DWORD dwProcessId
)
71 LPPROCESS_PAGE_LIST_ITEM pData
;
73 for (i
=0; i
<ListView_GetItemCount(hProcessPageListCtrl
); i
++)
75 memset(&item
, 0, sizeof(LV_ITEM
));
76 item
.mask
= LVIF_PARAM
;
78 (void)ListView_GetItem(hProcessPageListCtrl
, &item
);
79 pData
= (LPPROCESS_PAGE_LIST_ITEM
)item
.lParam
;
80 if (pData
->ProcessId
== dwProcessId
)
88 DWORD
GetSelectedProcessId(void)
93 if(ListView_GetSelectedCount(hProcessPageListCtrl
) == 1)
95 Index
= ListView_GetSelectionMark(hProcessPageListCtrl
);
97 memset(&lvitem
, 0, sizeof(LVITEM
));
99 lvitem
.mask
= LVIF_PARAM
;
100 lvitem
.iItem
= Index
;
102 (void)ListView_GetItem(hProcessPageListCtrl
, &lvitem
);
105 return ((LPPROCESS_PAGE_LIST_ITEM
)lvitem
.lParam
)->ProcessId
;
111 void ProcessPageUpdate(void)
113 /* Enable or disable the "End Process" button */
114 if (ListView_GetSelectedCount(hProcessPageListCtrl
))
115 EnableWindow(hProcessPageEndProcessButton
, TRUE
);
117 EnableWindow(hProcessPageEndProcessButton
, FALSE
);
121 ProcessPageWndProc(HWND hDlg
, UINT message
, WPARAM wParam
, LPARAM lParam
)
131 * Save the width and height
133 GetClientRect(hDlg
, &rc
);
134 nProcessPageWidth
= rc
.right
;
135 nProcessPageHeight
= rc
.bottom
;
137 /* Update window position */
138 SetWindowPos(hDlg
, NULL
, 15, 30, 0, 0, SWP_NOACTIVATE
|SWP_NOOWNERZORDER
|SWP_NOSIZE
|SWP_NOZORDER
);
141 * Get handles to the controls
143 hProcessPageListCtrl
= GetDlgItem(hDlg
, IDC_PROCESSLIST
);
144 hProcessPageHeaderCtrl
= ListView_GetHeader(hProcessPageListCtrl
);
145 hProcessPageEndProcessButton
= GetDlgItem(hDlg
, IDC_ENDPROCESS
);
146 hProcessPageShowAllProcessesButton
= GetDlgItem(hDlg
, IDC_SHOWALLPROCESSES
);
149 * Set the title, and extended window styles for the list control
151 SetWindowTextW(hProcessPageListCtrl
, L
"Processes");
152 (void)ListView_SetExtendedListViewStyle(hProcessPageListCtrl
, ListView_GetExtendedListViewStyle(hProcessPageListCtrl
) | LVS_EX_FULLROWSELECT
| LVS_EX_HEADERDRAGDROP
);
157 * Subclass the process list control so we can intercept WM_ERASEBKGND
159 OldProcessListWndProc
= (WNDPROC
)SetWindowLongPtrW(hProcessPageListCtrl
, GWLP_WNDPROC
, (LONG_PTR
)ProcessListWndProc
);
162 /* Start our refresh thread */
163 hProcessThread
= CreateThread(NULL
, 0, ProcessPageRefreshThread
, NULL
, 0, &dwProcessThread
);
172 /* Close the event handle, this will make the */
173 /* refresh thread exit when the wait fails */
175 EndLocalThread(&hProcessThread
, dwProcessThread
);
177 SaveColumnSettings();
182 /* Handle the button clicks */
183 switch (LOWORD(wParam
))
186 ProcessPage_OnEndProcess();
191 if (wParam
== SIZE_MINIMIZED
)
196 nXDifference
= cx
- nProcessPageWidth
;
197 nYDifference
= cy
- nProcessPageHeight
;
198 nProcessPageWidth
= cx
;
199 nProcessPageHeight
= cy
;
201 /* Reposition the application page's controls */
202 GetWindowRect(hProcessPageListCtrl
, &rc
);
203 cx
= (rc
.right
- rc
.left
) + nXDifference
;
204 cy
= (rc
.bottom
- rc
.top
) + nYDifference
;
205 SetWindowPos(hProcessPageListCtrl
, NULL
, 0, 0, cx
, cy
, SWP_NOACTIVATE
|SWP_NOOWNERZORDER
|SWP_NOMOVE
|SWP_NOZORDER
);
206 InvalidateRect(hProcessPageListCtrl
, NULL
, TRUE
);
208 GetClientRect(hProcessPageEndProcessButton
, &rc
);
209 MapWindowPoints(hProcessPageEndProcessButton
, hDlg
, (LPPOINT
)(PRECT
)(&rc
), sizeof(RECT
)/sizeof(POINT
));
210 cx
= rc
.left
+ nXDifference
;
211 cy
= rc
.top
+ nYDifference
;
212 SetWindowPos(hProcessPageEndProcessButton
, NULL
, cx
, cy
, 0, 0, SWP_NOACTIVATE
|SWP_NOOWNERZORDER
|SWP_NOSIZE
|SWP_NOZORDER
);
213 InvalidateRect(hProcessPageEndProcessButton
, NULL
, TRUE
);
215 GetClientRect(hProcessPageShowAllProcessesButton
, &rc
);
216 MapWindowPoints(hProcessPageShowAllProcessesButton
, hDlg
, (LPPOINT
)(PRECT
)(&rc
), sizeof(RECT
)/sizeof(POINT
));
218 cy
= rc
.top
+ nYDifference
;
219 SetWindowPos(hProcessPageShowAllProcessesButton
, NULL
, cx
, cy
, 0, 0, SWP_NOACTIVATE
|SWP_NOOWNERZORDER
|SWP_NOSIZE
|SWP_NOZORDER
);
220 InvalidateRect(hProcessPageShowAllProcessesButton
, NULL
, TRUE
);
224 ProcessPageOnNotify(wParam
, lParam
);
228 if (wParam
== VK_DELETE
)
229 ProcessPage_OnEndProcess();
236 void ProcessPageOnNotify(WPARAM wParam
, LPARAM lParam
)
243 LPPROCESS_PAGE_LIST_ITEM pData
;
245 pnmh
= (LPNMHDR
) lParam
;
246 pnmdi
= (NMLVDISPINFO
*) lParam
;
247 pnmhdr
= (LPNMHEADER
) lParam
;
249 if (pnmh
->hwndFrom
== hProcessPageListCtrl
)
253 case LVN_ITEMCHANGED
:
257 case LVN_GETDISPINFO
:
259 if (!(pnmdi
->item
.mask
& LVIF_TEXT
))
262 pData
= (LPPROCESS_PAGE_LIST_ITEM
)pnmdi
->item
.lParam
;
263 Index
= PerfDataGetProcessIndex(pData
->ProcessId
);
264 ColumnIndex
= pnmdi
->item
.iSubItem
;
266 PerfDataGetText(Index
, ColumnIndex
, pnmdi
->item
.pszText
, (ULONG
)pnmdi
->item
.cchTextMax
);
272 ProcessPageShowContextMenu(GetSelectedProcessId());
277 if (((LPNMLVKEYDOWN
)lParam
)->wVKey
== VK_DELETE
)
278 ProcessPage_OnEndProcess();
283 else if (pnmh
->hwndFrom
== hProcessPageHeaderCtrl
)
289 TaskManagerSettings
.SortColumn
= ColumnDataHints
[pnmhdr
->iItem
];
290 TaskManagerSettings
.SortAscending
= !TaskManagerSettings
.SortAscending
;
291 (void)ListView_SortItems(hProcessPageListCtrl
, ProcessPageCompareFunc
, NULL
);
295 case HDN_ITEMCHANGED
:
297 UpdateColumnDataHints();
303 UpdateColumnDataHints();
312 * Adapted from SH_FormatInteger in dll/win32/shell32/dialogs/filedefext.cpp.
317 _Out_writes_z_(cchResultMax
) LPWSTR pwszResult
,
318 _In_ UINT cchResultMax
)
322 INT cchGrouping
, cchResult
;
324 WCHAR wszDecimalSep
[8], wszThousandSep
[8];
325 WCHAR wszGrouping
[12];
327 /* Print the number in uniform mode */
328 StringCchPrintfW(wszNumber
, _countof(wszNumber
), L
"%I64u", Num
);
330 /* Get system strings for decimal and thousand separators */
331 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_SDECIMAL
, wszDecimalSep
, _countof(wszDecimalSep
));
332 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_STHOUSAND
, wszThousandSep
, _countof(wszThousandSep
));
334 /* Initialize format for printing the number in bytes */
335 ZeroMemory(&nf
, sizeof(nf
));
336 nf
.lpDecimalSep
= wszDecimalSep
;
337 nf
.lpThousandSep
= wszThousandSep
;
339 /* Get system string for groups separator */
340 cchGrouping
= GetLocaleInfoW(LOCALE_USER_DEFAULT
,
343 _countof(wszGrouping
));
345 /* Convert grouping specs from string to integer */
346 for (i
= 0; i
< cchGrouping
; i
++)
348 WCHAR wch
= wszGrouping
[i
];
350 if (wch
>= L
'0' && wch
<= L
'9')
351 nf
.Grouping
= nf
.Grouping
* 10 + (wch
- L
'0');
352 else if (wch
!= L
';')
356 if ((nf
.Grouping
% 10) == 0)
361 /* Format the number */
362 cchResult
= GetNumberFormatW(LOCALE_USER_DEFAULT
,
371 /* GetNumberFormatW returns number of characters including UNICODE_NULL */
372 return cchResult
- 1;
375 void ProcessPageShowContextMenu(DWORD dwProcessId
)
383 DWORD dwProcessPriorityClass
;
384 WCHAR strDebugger
[260];
385 DWORD dwDebuggerSize
;
388 if (dwProcessId
== 0)
391 memset(&si
, 0, sizeof(SYSTEM_INFO
));
396 hMenu
= LoadMenuW(hInst
, MAKEINTRESOURCEW(IDR_PROCESS_PAGE_CONTEXT
));
397 hSubMenu
= GetSubMenu(hMenu
, 0);
398 hPriorityMenu
= GetSubMenu(hSubMenu
, 4);
400 hProcess
= OpenProcess(PROCESS_QUERY_INFORMATION
, FALSE
, dwProcessId
);
401 dwProcessPriorityClass
= GetPriorityClass(hProcess
);
402 CloseHandle(hProcess
);
404 if (si
.dwNumberOfProcessors
< 2)
405 RemoveMenu(hSubMenu
, ID_PROCESS_PAGE_SETAFFINITY
, MF_BYCOMMAND
);
407 switch (dwProcessPriorityClass
) {
408 case REALTIME_PRIORITY_CLASS
:
409 CheckMenuRadioItem(hPriorityMenu
, ID_PROCESS_PAGE_SETPRIORITY_REALTIME
, ID_PROCESS_PAGE_SETPRIORITY_LOW
, ID_PROCESS_PAGE_SETPRIORITY_REALTIME
, MF_BYCOMMAND
);
411 case HIGH_PRIORITY_CLASS
:
412 CheckMenuRadioItem(hPriorityMenu
, ID_PROCESS_PAGE_SETPRIORITY_REALTIME
, ID_PROCESS_PAGE_SETPRIORITY_LOW
, ID_PROCESS_PAGE_SETPRIORITY_HIGH
, MF_BYCOMMAND
);
414 case ABOVE_NORMAL_PRIORITY_CLASS
:
415 CheckMenuRadioItem(hPriorityMenu
, ID_PROCESS_PAGE_SETPRIORITY_REALTIME
, ID_PROCESS_PAGE_SETPRIORITY_LOW
, ID_PROCESS_PAGE_SETPRIORITY_ABOVENORMAL
, MF_BYCOMMAND
);
417 case NORMAL_PRIORITY_CLASS
:
418 CheckMenuRadioItem(hPriorityMenu
, ID_PROCESS_PAGE_SETPRIORITY_REALTIME
, ID_PROCESS_PAGE_SETPRIORITY_LOW
, ID_PROCESS_PAGE_SETPRIORITY_NORMAL
, MF_BYCOMMAND
);
420 case BELOW_NORMAL_PRIORITY_CLASS
:
421 CheckMenuRadioItem(hPriorityMenu
, ID_PROCESS_PAGE_SETPRIORITY_REALTIME
, ID_PROCESS_PAGE_SETPRIORITY_LOW
, ID_PROCESS_PAGE_SETPRIORITY_BELOWNORMAL
, MF_BYCOMMAND
);
423 case IDLE_PRIORITY_CLASS
:
424 CheckMenuRadioItem(hPriorityMenu
, ID_PROCESS_PAGE_SETPRIORITY_REALTIME
, ID_PROCESS_PAGE_SETPRIORITY_LOW
, ID_PROCESS_PAGE_SETPRIORITY_LOW
, MF_BYCOMMAND
);
428 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
, L
"Software\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug", 0, KEY_READ
, &hKey
) == ERROR_SUCCESS
)
430 dwDebuggerSize
= sizeof(strDebugger
);
431 if (RegQueryValueExW(hKey
, L
"Debugger", NULL
, NULL
, (LPBYTE
)strDebugger
, &dwDebuggerSize
) == ERROR_SUCCESS
)
433 CharUpper(strDebugger
);
434 if (wcsstr(strDebugger
, L
"DRWTSN32"))
435 EnableMenuItem(hSubMenu
, ID_PROCESS_PAGE_DEBUG
, MF_BYCOMMAND
|MF_DISABLED
|MF_GRAYED
);
438 EnableMenuItem(hSubMenu
, ID_PROCESS_PAGE_DEBUG
, MF_BYCOMMAND
|MF_DISABLED
|MF_GRAYED
);
442 EnableMenuItem(hSubMenu
, ID_PROCESS_PAGE_DEBUG
, MF_BYCOMMAND
|MF_DISABLED
|MF_GRAYED
);
444 TrackPopupMenu(hSubMenu
, TPM_LEFTALIGN
|TPM_TOPALIGN
|TPM_LEFTBUTTON
, pt
.x
, pt
.y
, 0, hMainWnd
, NULL
);
448 void RefreshProcessPage(void)
451 /* Signal the event so that our refresh thread */
452 /* will wake up and refresh the process page */
453 PostThreadMessage(dwProcessThread
, WM_TIMER
, 0, 0);
457 DWORD WINAPI
ProcessPageRefreshThread(void *lpParameter
)
462 /* Wait for an the event or application close */
463 if (GetMessage(&msg
, NULL
, 0, 0) <= 0)
466 if (msg
.message
== WM_TIMER
) {
470 if (IsWindowVisible(hProcessPage
))
471 InvalidateRect(hProcessPageListCtrl
, NULL
, FALSE
);
479 void UpdateProcesses()
484 LPPROCESS_PAGE_LIST_ITEM pData
;
486 SendMessage(hProcessPageListCtrl
, WM_SETREDRAW
, FALSE
, 0);
488 /* Remove old processes */
489 for (i
= 0; i
< ListView_GetItemCount(hProcessPageListCtrl
); i
++)
491 memset(&item
, 0, sizeof (LV_ITEM
));
492 item
.mask
= LVIF_PARAM
;
494 (void)ListView_GetItem(hProcessPageListCtrl
, &item
);
495 pData
= (LPPROCESS_PAGE_LIST_ITEM
)item
.lParam
;
496 if (!ProcessRunning(pData
->ProcessId
))
498 (void)ListView_DeleteItem(hProcessPageListCtrl
, i
);
499 HeapFree(GetProcessHeap(), 0, pData
);
503 /* Check for difference in listview process and performance process counts */
504 if (ListView_GetItemCount(hProcessPageListCtrl
) != PerfDataGetProcessCount())
506 /* Add new processes by checking against the current items */
507 for (l
= 0; l
< PerfDataGetProcessCount(); l
++)
513 if (TaskManagerSettings
.SortColumn
!= -1)
515 (void)ListView_SortItems(hProcessPageListCtrl
, ProcessPageCompareFunc
, NULL
);
518 SendMessage(hProcessPageListCtrl
, WM_SETREDRAW
, TRUE
, 0);
520 /* Select first item if any */
521 if ((ListView_GetNextItem(hProcessPageListCtrl
, -1, LVNI_FOCUSED
| LVNI_SELECTED
) == -1) &&
522 (ListView_GetItemCount(hProcessPageListCtrl
) > 0) && !bProcessPageSelectionMade
)
524 ListView_SetItemState(hProcessPageListCtrl
, 0, LVIS_FOCUSED
| LVIS_SELECTED
, LVIS_FOCUSED
| LVIS_SELECTED
);
525 bProcessPageSelectionMade
= TRUE
;
530 bProcessPageSelectionMade = FALSE;
535 BOOL
ProcessRunning(ULONG ProcessId
)
540 if (ProcessId
== 0) {
544 hProcess
= OpenProcess(PROCESS_ALL_ACCESS
, FALSE
, ProcessId
);
545 if (hProcess
== NULL
) {
549 if (GetExitCodeProcess(hProcess
, &exitCode
)) {
550 CloseHandle(hProcess
);
551 return (exitCode
== STILL_ACTIVE
);
554 CloseHandle(hProcess
);
558 void AddProcess(ULONG Index
)
560 LPPROCESS_PAGE_LIST_ITEM pData
;
563 BOOL bAlreadyInList
= FALSE
;
566 pid
= PerfDataGetProcessId(Index
);
568 /* Check to see if it's already in our list */
569 for (i
=0; i
<ListView_GetItemCount(hProcessPageListCtrl
); i
++)
571 memset(&item
, 0, sizeof(LV_ITEM
));
572 item
.mask
= LVIF_PARAM
;
574 (void)ListView_GetItem(hProcessPageListCtrl
, &item
);
575 pData
= (LPPROCESS_PAGE_LIST_ITEM
)item
.lParam
;
576 if (pData
->ProcessId
== pid
)
578 bAlreadyInList
= TRUE
;
582 if (!bAlreadyInList
) /* Add */
584 pData
= (LPPROCESS_PAGE_LIST_ITEM
)HeapAlloc(GetProcessHeap(), 0, sizeof(PROCESS_PAGE_LIST_ITEM
));
585 pData
->ProcessId
= pid
;
587 /* Add the item to the list */
588 memset(&item
, 0, sizeof(LV_ITEM
));
589 item
.mask
= LVIF_TEXT
|LVIF_PARAM
;
590 item
.pszText
= LPSTR_TEXTCALLBACK
;
591 item
.iItem
= ListView_GetItemCount(hProcessPageListCtrl
);
592 item
.lParam
= (LPARAM
)pData
;
593 (void)ListView_InsertItem(hProcessPageListCtrl
, &item
);
597 BOOL
PerfDataGetText(ULONG Index
, ULONG ColumnIndex
, LPTSTR lpText
, ULONG nMaxCount
)
599 IO_COUNTERS iocounters
;
601 switch (ColumnDataHints
[ColumnIndex
])
603 case COLUMN_IMAGENAME
:
604 PerfDataGetImageName(Index
, lpText
, nMaxCount
);
608 StringCchPrintfW(lpText
, nMaxCount
, L
"%lu", PerfDataGetProcessId(Index
));
611 case COLUMN_USERNAME
:
612 PerfDataGetUserName(Index
, lpText
, nMaxCount
);
615 case COLUMN_COMMANDLINE
:
616 PerfDataGetCommandLine(Index
, lpText
, nMaxCount
);
619 case COLUMN_SESSIONID
:
620 StringCchPrintfW(lpText
, nMaxCount
, L
"%lu", PerfDataGetSessionId(Index
));
623 case COLUMN_CPUUSAGE
:
624 StringCchPrintfW(lpText
, nMaxCount
, L
"%02lu", PerfDataGetCPUUsage(Index
));
634 time
= PerfDataGetCPUTime(Index
);
635 gethmsfromlargeint(time
, &dwHours
, &dwMinutes
, &dwSeconds
);
636 StringCchPrintfW(lpText
, nMaxCount
, L
"%lu:%02lu:%02lu", dwHours
, dwMinutes
, dwSeconds
);
640 case COLUMN_MEMORYUSAGE
:
641 SH_FormatInteger(PerfDataGetWorkingSetSizeBytes(Index
) / 1024, lpText
, nMaxCount
);
642 StringCchCatW(lpText
, nMaxCount
, L
" K");
645 case COLUMN_PEAKMEMORYUSAGE
:
646 SH_FormatInteger(PerfDataGetPeakWorkingSetSizeBytes(Index
) / 1024, lpText
, nMaxCount
);
647 StringCchCatW(lpText
, nMaxCount
, L
" K");
650 case COLUMN_MEMORYUSAGEDELTA
:
651 SH_FormatInteger(PerfDataGetWorkingSetSizeDelta(Index
) / 1024, lpText
, nMaxCount
);
652 StringCchCatW(lpText
, nMaxCount
, L
" K");
655 case COLUMN_PAGEFAULTS
:
656 SH_FormatInteger(PerfDataGetPageFaultCount(Index
), lpText
, nMaxCount
);
659 case COLUMN_PAGEFAULTSDELTA
:
660 SH_FormatInteger(PerfDataGetPageFaultCountDelta(Index
), lpText
, nMaxCount
);
663 case COLUMN_VIRTUALMEMORYSIZE
:
664 SH_FormatInteger(PerfDataGetVirtualMemorySizeBytes(Index
) / 1024, lpText
, nMaxCount
);
665 StringCchCatW(lpText
, nMaxCount
, L
" K");
668 case COLUMN_PAGEDPOOL
:
669 SH_FormatInteger(PerfDataGetPagedPoolUsagePages(Index
) / 1024, lpText
, nMaxCount
);
670 StringCchCatW(lpText
, nMaxCount
, L
" K");
673 case COLUMN_NONPAGEDPOOL
:
674 SH_FormatInteger(PerfDataGetNonPagedPoolUsagePages(Index
) / 1024, lpText
, nMaxCount
);
675 StringCchCatW(lpText
, nMaxCount
, L
" K");
678 case COLUMN_BASEPRIORITY
:
679 StringCchPrintfW(lpText
, nMaxCount
, L
"%lu", PerfDataGetBasePriority(Index
));
682 case COLUMN_HANDLECOUNT
:
683 SH_FormatInteger(PerfDataGetHandleCount(Index
), lpText
, nMaxCount
);
686 case COLUMN_THREADCOUNT
:
687 SH_FormatInteger(PerfDataGetThreadCount(Index
), lpText
, nMaxCount
);
690 case COLUMN_USEROBJECTS
:
691 SH_FormatInteger(PerfDataGetUSERObjectCount(Index
), lpText
, nMaxCount
);
694 case COLUMN_GDIOBJECTS
:
695 SH_FormatInteger(PerfDataGetGDIObjectCount(Index
), lpText
, nMaxCount
);
699 PerfDataGetIOCounters(Index
, &iocounters
);
700 SH_FormatInteger(iocounters
.ReadOperationCount
, lpText
, nMaxCount
);
703 case COLUMN_IOWRITES
:
704 PerfDataGetIOCounters(Index
, &iocounters
);
705 SH_FormatInteger(iocounters
.WriteOperationCount
, lpText
, nMaxCount
);
709 PerfDataGetIOCounters(Index
, &iocounters
);
710 SH_FormatInteger(iocounters
.OtherOperationCount
, lpText
, nMaxCount
);
713 case COLUMN_IOREADBYTES
:
714 PerfDataGetIOCounters(Index
, &iocounters
);
715 SH_FormatInteger(iocounters
.ReadTransferCount
, lpText
, nMaxCount
);
718 case COLUMN_IOWRITEBYTES
:
719 PerfDataGetIOCounters(Index
, &iocounters
);
720 SH_FormatInteger(iocounters
.WriteTransferCount
, lpText
, nMaxCount
);
723 case COLUMN_IOOTHERBYTES
:
724 PerfDataGetIOCounters(Index
, &iocounters
);
725 SH_FormatInteger(iocounters
.OtherTransferCount
, lpText
, nMaxCount
);
733 void gethmsfromlargeint(LARGE_INTEGER largeint
, DWORD
*dwHours
, DWORD
*dwMinutes
, DWORD
*dwSeconds
)
736 *dwHours
= (DWORD
)(largeint
.QuadPart
/ 36000000000L);
737 *dwMinutes
= (DWORD
)((largeint
.QuadPart
% 36000000000L) / 600000000L);
738 *dwSeconds
= (DWORD
)(((largeint
.QuadPart
% 36000000000L) % 600000000L) / 10000000L);
740 *dwHours
= (DWORD
)(largeint
.QuadPart
/ 36000000000LL);
741 *dwMinutes
= (DWORD
)((largeint
.QuadPart
% 36000000000LL) / 600000000LL);
742 *dwSeconds
= (DWORD
)(((largeint
.QuadPart
% 36000000000LL) % 600000000LL) / 10000000LL);
746 int largeintcmp(LARGE_INTEGER l1
, LARGE_INTEGER l2
)
756 gethmsfromlargeint(l1
, &dwHours1
, &dwMinutes1
, &dwSeconds1
);
757 gethmsfromlargeint(l2
, &dwHours2
, &dwMinutes2
, &dwSeconds2
);
758 ret
= CMP(dwHours1
, dwHours2
);
761 ret
= CMP(dwMinutes1
, dwMinutes2
);
764 ret
= CMP(dwSeconds1
, dwSeconds2
);
770 int CALLBACK
ProcessPageCompareFunc(LPARAM lParam1
, LPARAM lParam2
, LPARAM lParamSort
)
773 LPPROCESS_PAGE_LIST_ITEM Param1
;
774 LPPROCESS_PAGE_LIST_ITEM Param2
;
783 IO_COUNTERS iocounters1
;
784 IO_COUNTERS iocounters2
;
788 if (TaskManagerSettings
.SortAscending
) {
789 Param1
= (LPPROCESS_PAGE_LIST_ITEM
)lParam1
;
790 Param2
= (LPPROCESS_PAGE_LIST_ITEM
)lParam2
;
792 Param1
= (LPPROCESS_PAGE_LIST_ITEM
)lParam2
;
793 Param2
= (LPPROCESS_PAGE_LIST_ITEM
)lParam1
;
795 IndexParam1
= PerfDataGetProcessIndex(Param1
->ProcessId
);
796 IndexParam2
= PerfDataGetProcessIndex(Param2
->ProcessId
);
798 if (TaskManagerSettings
.SortColumn
== COLUMN_IMAGENAME
)
800 PerfDataGetImageName(IndexParam1
, text1
, _countof(text1
));
801 PerfDataGetImageName(IndexParam2
, text2
, _countof(text2
));
802 ret
= _wcsicmp(text1
, text2
);
804 else if (TaskManagerSettings
.SortColumn
== COLUMN_PID
)
806 l1
= Param1
->ProcessId
;
807 l2
= Param2
->ProcessId
;
810 else if (TaskManagerSettings
.SortColumn
== COLUMN_USERNAME
)
812 PerfDataGetUserName(IndexParam1
, text1
, _countof(text1
));
813 PerfDataGetUserName(IndexParam2
, text2
, _countof(text2
));
814 ret
= _wcsicmp(text1
, text2
);
816 else if (TaskManagerSettings
.SortColumn
== COLUMN_COMMANDLINE
)
818 PerfDataGetCommandLine(IndexParam1
, text1
, _countof(text1
));
819 PerfDataGetCommandLine(IndexParam2
, text2
, _countof(text2
));
820 ret
= _wcsicmp(text1
, text2
);
822 else if (TaskManagerSettings
.SortColumn
== COLUMN_SESSIONID
)
824 l1
= PerfDataGetSessionId(IndexParam1
);
825 l2
= PerfDataGetSessionId(IndexParam2
);
828 else if (TaskManagerSettings
.SortColumn
== COLUMN_CPUUSAGE
)
830 l1
= PerfDataGetCPUUsage(IndexParam1
);
831 l2
= PerfDataGetCPUUsage(IndexParam2
);
834 else if (TaskManagerSettings
.SortColumn
== COLUMN_CPUTIME
)
836 time1
= PerfDataGetCPUTime(IndexParam1
);
837 time2
= PerfDataGetCPUTime(IndexParam2
);
838 ret
= largeintcmp(time1
, time2
);
840 else if (TaskManagerSettings
.SortColumn
== COLUMN_MEMORYUSAGE
)
842 l1
= PerfDataGetWorkingSetSizeBytes(IndexParam1
);
843 l2
= PerfDataGetWorkingSetSizeBytes(IndexParam2
);
846 else if (TaskManagerSettings
.SortColumn
== COLUMN_PEAKMEMORYUSAGE
)
848 l1
= PerfDataGetPeakWorkingSetSizeBytes(IndexParam1
);
849 l2
= PerfDataGetPeakWorkingSetSizeBytes(IndexParam2
);
852 else if (TaskManagerSettings
.SortColumn
== COLUMN_MEMORYUSAGEDELTA
)
854 l1
= PerfDataGetWorkingSetSizeDelta(IndexParam1
);
855 l2
= PerfDataGetWorkingSetSizeDelta(IndexParam2
);
858 else if (TaskManagerSettings
.SortColumn
== COLUMN_PAGEFAULTS
)
860 l1
= PerfDataGetPageFaultCount(IndexParam1
);
861 l2
= PerfDataGetPageFaultCount(IndexParam2
);
864 else if (TaskManagerSettings
.SortColumn
== COLUMN_PAGEFAULTSDELTA
)
866 l1
= PerfDataGetPageFaultCountDelta(IndexParam1
);
867 l2
= PerfDataGetPageFaultCountDelta(IndexParam2
);
870 else if (TaskManagerSettings
.SortColumn
== COLUMN_VIRTUALMEMORYSIZE
)
872 l1
= PerfDataGetVirtualMemorySizeBytes(IndexParam1
);
873 l2
= PerfDataGetVirtualMemorySizeBytes(IndexParam2
);
876 else if (TaskManagerSettings
.SortColumn
== COLUMN_PAGEDPOOL
)
878 l1
= PerfDataGetPagedPoolUsagePages(IndexParam1
);
879 l2
= PerfDataGetPagedPoolUsagePages(IndexParam2
);
882 else if (TaskManagerSettings
.SortColumn
== COLUMN_NONPAGEDPOOL
)
884 l1
= PerfDataGetNonPagedPoolUsagePages(IndexParam1
);
885 l2
= PerfDataGetNonPagedPoolUsagePages(IndexParam2
);
888 else if (TaskManagerSettings
.SortColumn
== COLUMN_BASEPRIORITY
)
890 l1
= PerfDataGetBasePriority(IndexParam1
);
891 l2
= PerfDataGetBasePriority(IndexParam2
);
894 else if (TaskManagerSettings
.SortColumn
== COLUMN_HANDLECOUNT
)
896 l1
= PerfDataGetHandleCount(IndexParam1
);
897 l2
= PerfDataGetHandleCount(IndexParam2
);
900 else if (TaskManagerSettings
.SortColumn
== COLUMN_THREADCOUNT
)
902 l1
= PerfDataGetThreadCount(IndexParam1
);
903 l2
= PerfDataGetThreadCount(IndexParam2
);
906 else if (TaskManagerSettings
.SortColumn
== COLUMN_USEROBJECTS
)
908 l1
= PerfDataGetUSERObjectCount(IndexParam1
);
909 l2
= PerfDataGetUSERObjectCount(IndexParam2
);
912 else if (TaskManagerSettings
.SortColumn
== COLUMN_GDIOBJECTS
)
914 l1
= PerfDataGetGDIObjectCount(IndexParam1
);
915 l2
= PerfDataGetGDIObjectCount(IndexParam2
);
918 else if (TaskManagerSettings
.SortColumn
== COLUMN_IOREADS
)
920 PerfDataGetIOCounters(IndexParam1
, &iocounters1
);
921 PerfDataGetIOCounters(IndexParam2
, &iocounters2
);
922 ull1
= iocounters1
.ReadOperationCount
;
923 ull2
= iocounters2
.ReadOperationCount
;
924 ret
= CMP(ull1
, ull2
);
926 else if (TaskManagerSettings
.SortColumn
== COLUMN_IOWRITES
)
928 PerfDataGetIOCounters(IndexParam1
, &iocounters1
);
929 PerfDataGetIOCounters(IndexParam2
, &iocounters2
);
930 ull1
= iocounters1
.WriteOperationCount
;
931 ull2
= iocounters2
.WriteOperationCount
;
932 ret
= CMP(ull1
, ull2
);
934 else if (TaskManagerSettings
.SortColumn
== COLUMN_IOOTHER
)
936 PerfDataGetIOCounters(IndexParam1
, &iocounters1
);
937 PerfDataGetIOCounters(IndexParam2
, &iocounters2
);
938 ull1
= iocounters1
.OtherOperationCount
;
939 ull2
= iocounters2
.OtherOperationCount
;
940 ret
= CMP(ull1
, ull2
);
942 else if (TaskManagerSettings
.SortColumn
== COLUMN_IOREADBYTES
)
944 PerfDataGetIOCounters(IndexParam1
, &iocounters1
);
945 PerfDataGetIOCounters(IndexParam2
, &iocounters2
);
946 ull1
= iocounters1
.ReadTransferCount
;
947 ull2
= iocounters2
.ReadTransferCount
;
948 ret
= CMP(ull1
, ull2
);
950 else if (TaskManagerSettings
.SortColumn
== COLUMN_IOWRITEBYTES
)
952 PerfDataGetIOCounters(IndexParam1
, &iocounters1
);
953 PerfDataGetIOCounters(IndexParam2
, &iocounters2
);
954 ull1
= iocounters1
.WriteTransferCount
;
955 ull2
= iocounters2
.WriteTransferCount
;
956 ret
= CMP(ull1
, ull2
);
958 else if (TaskManagerSettings
.SortColumn
== COLUMN_IOOTHERBYTES
)
960 PerfDataGetIOCounters(IndexParam1
, &iocounters1
);
961 PerfDataGetIOCounters(IndexParam2
, &iocounters2
);
962 ull1
= iocounters1
.OtherTransferCount
;
963 ull2
= iocounters2
.OtherTransferCount
;
964 ret
= CMP(ull1
, ull2
);
971 * Maps an NT "\Device\..." path to its Win32 "DOS" equivalent.
973 * @param[in] lpDevicePath
974 * The NT device path to convert.
976 * @param[out] lpDosPath
977 * Receives the converted Win32 path.
979 * @param[in] dwLength
980 * Size of the lpDosPath buffer in characters.
983 * The number of characters required (if lpDosPath == NULL or dwLength == 0),
984 * or actually written in the lpDosPath buffer, including the NULL terminator.
985 * Returns 0 in case of failure.
989 _In_ LPCWSTR lpDevicePath
,
990 _Out_writes_to_opt_(dwLength
, return)
992 _In_opt_ DWORD dwLength
)
995 WCHAR szDrive
[3] = L
"?:";
996 WCHAR szDeviceName
[MAX_PATH
];
998 /* Check if lpDevicePath is a device path */
999 if (_wcsnicmp(lpDevicePath
, L
"\\Device\\", CONST_STR_LEN(L
"\\Device\\")) != 0)
1004 for (szDrive
[0] = L
'A'; szDrive
[0] <= L
'`'; szDrive
[0]++)
1006 if (QueryDosDeviceW(szDrive
, szDeviceName
, _countof(szDeviceName
)) != 0)
1008 size_t len
= wcslen(szDeviceName
);
1010 if (_wcsnicmp(lpDevicePath
, szDeviceName
, len
) == 0)
1012 /* Get the required length, including the NULL terminator */
1013 dwRet
= _countof(szDrive
) + wcslen(lpDevicePath
+ len
);
1015 if (lpDosPath
&& (dwLength
>= dwRet
))
1017 StringCchPrintfW(lpDosPath
, dwLength
, L
"%s%s",
1018 szDrive
, lpDevicePath
+ len
);
1031 * Retrieves the Win32 path of an executable image, by handle.
1033 * @param[in] hProcess
1034 * Handle to the executable image; it should be opened with
1035 * PROCESS_QUERY_INFORMATION access rights.
1037 * @param[out] lpExePath
1038 * Receives the Win32 image path.
1040 * @param[in] dwLength
1041 * Size of the lpExePath buffer in characters.
1044 * The number of characters required (if lpExePath == NULL or dwLength == 0),
1045 * or actually written in the lpExePath buffer, including the NULL terminator.
1046 * Returns 0 in case of failure.
1049 GetProcessExecutablePath(
1050 _In_ HANDLE hProcess
,
1051 _Out_writes_to_opt_(dwLength
, return)
1053 _In_opt_ DWORD dwLength
)
1057 BYTE StaticBuffer
[sizeof(UNICODE_STRING
) + (MAX_PATH
* sizeof(WCHAR
))];
1058 PVOID DynamicBuffer
= NULL
;
1059 PUNICODE_STRING ExePath
;
1062 Status
= NtQueryInformationProcess(hProcess
,
1063 ProcessImageFileName
,
1065 /* Reserve a NULL terminator */
1066 sizeof(StaticBuffer
) - sizeof(WCHAR
),
1068 if (NT_SUCCESS(Status
))
1070 ExePath
= (PUNICODE_STRING
)StaticBuffer
;
1072 else if (Status
== STATUS_INFO_LENGTH_MISMATCH
)
1074 /* Allocate the buffer, reserving space for a NULL terminator */
1075 DynamicBuffer
= HeapAlloc(GetProcessHeap(), 0, SizeNeeded
+ sizeof(WCHAR
));
1079 Status
= NtQueryInformationProcess(hProcess
,
1080 ProcessImageFileName
,
1084 if (!NT_SUCCESS(Status
))
1087 ExePath
= DynamicBuffer
;
1094 /* Manually NULL-terminate */
1095 ExePath
->Buffer
[ExePath
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1097 /* HACK: Convert device path format into Win32 path format.
1098 * Use ProcessImageFileNameWin32 instead if the kernel supports it. */
1099 dwRet
= DevicePathToDosPath(ExePath
->Buffer
, lpExePath
, dwLength
);
1102 HeapFree(GetProcessHeap(), 0, DynamicBuffer
);
1109 * Retrieves the Win32 path of an executable image, by identifier.
1111 * @param[in] dwProcessId
1112 * Identifier of the running executable image.
1114 * @param[out] lpExePath
1115 * Receives the Win32 image path.
1117 * @param[in] dwLength
1118 * Size of the lpExePath buffer in characters.
1121 * The number of characters required (if lpExePath == NULL or dwLength == 0),
1122 * or actually written in the lpExePath buffer, including the NULL terminator.
1123 * Returns 0 in case of failure.
1126 GetProcessExecutablePathById(
1127 _In_ DWORD dwProcessId
,
1128 _Out_writes_to_opt_(dwLength
, return)
1130 _In_opt_ DWORD dwLength
)
1134 if (dwProcessId
== 0)
1137 /* PID = 4 ("System") */
1138 if (dwProcessId
== 4)
1140 static const WCHAR szKernelExe
[] = L
"\\ntoskrnl.exe";
1141 LPWSTR pszSystemDir
;
1144 uLength
= GetSystemDirectoryW(NULL
, 0);
1148 pszSystemDir
= HeapAlloc(GetProcessHeap(), 0, uLength
* sizeof(WCHAR
));
1152 if (GetSystemDirectoryW(pszSystemDir
, uLength
) != 0)
1154 /* Get the required length, including the NULL terminator */
1155 dwRet
= uLength
+ CONST_STR_LEN(szKernelExe
);
1157 if (lpExePath
&& (dwLength
>= dwRet
))
1159 StringCchPrintfW(lpExePath
, dwLength
, L
"%s%s",
1160 pszSystemDir
, szKernelExe
);
1164 HeapFree(GetProcessHeap(), 0, pszSystemDir
);
1170 hProcess
= OpenProcess(PROCESS_QUERY_INFORMATION
, FALSE
, dwProcessId
);
1173 dwRet
= GetProcessExecutablePath(hProcess
, lpExePath
, dwLength
);
1174 CloseHandle(hProcess
);
1181 void ProcessPage_OnProperties(void)
1186 SHELLEXECUTEINFOW info
= { 0 };
1188 dwProcessId
= GetSelectedProcessId();
1190 /* Retrieve the image path length */
1191 dwLength
= GetProcessExecutablePathById(dwProcessId
, NULL
, 0);
1195 /* Allocate and retrieve the image path */
1196 pszExePath
= HeapAlloc(GetProcessHeap(), 0, dwLength
* sizeof(WCHAR
));
1200 if (GetProcessExecutablePathById(dwProcessId
, pszExePath
, dwLength
) == 0)
1203 /* Call the shell to display the file properties */
1204 info
.cbSize
= sizeof(SHELLEXECUTEINFOW
);
1205 info
.fMask
= SEE_MASK_INVOKEIDLIST
;
1207 info
.lpVerb
= L
"properties";
1208 info
.lpFile
= pszExePath
;
1209 info
.lpParameters
= L
"";
1210 info
.lpDirectory
= NULL
;
1211 info
.nShow
= SW_SHOW
;
1212 info
.hInstApp
= NULL
;
1214 ShellExecuteExW(&info
);
1217 HeapFree(GetProcessHeap(), 0, pszExePath
);
1220 void ProcessPage_OnOpenFileLocation(void)
1225 LPWSTR pszCmdLine
= NULL
;
1227 dwProcessId
= GetSelectedProcessId();
1229 /* Retrieve the image path length */
1230 dwLength
= GetProcessExecutablePathById(dwProcessId
, NULL
, 0);
1234 /* Allocate and retrieve the image path */
1235 pszExePath
= HeapAlloc(GetProcessHeap(), 0, dwLength
* sizeof(WCHAR
));
1239 if (GetProcessExecutablePathById(dwProcessId
, pszExePath
, dwLength
) == 0)
1242 /* Build the shell command line */
1243 pszCmdLine
= HeapAlloc(GetProcessHeap(), 0, (dwLength
+ CONST_STR_LEN(L
"/select,\"\"")) * sizeof(WCHAR
));
1247 StringCchPrintfW(pszCmdLine
, dwLength
+ CONST_STR_LEN(L
"/select,\"\""), L
"/select,\"%s\"", pszExePath
);
1249 /* Call the shell to open the file location and select it */
1250 ShellExecuteW(NULL
, L
"open", L
"explorer.exe", pszCmdLine
, NULL
, SW_SHOWNORMAL
);
1253 HeapFree(GetProcessHeap(), 0, pszCmdLine
);
1254 HeapFree(GetProcessHeap(), 0, pszExePath
);