1 /* 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> 8 */ 9 10 #include "precomp.h" 11 12 #include "proclist.h" 13 14 #include <ndk/psfuncs.h> 15 16 #define CMP(x1, x2)\ 17 (x1 < x2 ? -1 : (x1 > x2 ? 1 : 0)) 18 19 #define CONST_STR_LEN(str) (_countof(str) - 1) 20 21 typedef struct 22 { 23 ULONG ProcessId; 24 } PROCESS_PAGE_LIST_ITEM, *LPPROCESS_PAGE_LIST_ITEM; 25 26 HWND hProcessPage; /* Process List Property Page */ 27 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 */ 33 34 static int nProcessPageWidth; 35 static int nProcessPageHeight; 36 #ifdef RUN_PROC_PAGE 37 static HANDLE hProcessThread = NULL; 38 static DWORD dwProcessThread; 39 #endif 40 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); 50 51 void Cleanup(void) 52 { 53 int i; 54 LV_ITEM item; 55 LPPROCESS_PAGE_LIST_ITEM pData; 56 for (i = 0; i < ListView_GetItemCount(hProcessPageListCtrl); i++) 57 { 58 memset(&item, 0, sizeof(LV_ITEM)); 59 item.mask = LVIF_PARAM; 60 item.iItem = i; 61 (void)ListView_GetItem(hProcessPageListCtrl, &item); 62 pData = (LPPROCESS_PAGE_LIST_ITEM)item.lParam; 63 HeapFree(GetProcessHeap(), 0, pData); 64 } 65 } 66 67 int ProcGetIndexByProcessId(DWORD dwProcessId) 68 { 69 int i; 70 LVITEM item; 71 LPPROCESS_PAGE_LIST_ITEM pData; 72 73 for (i=0; i<ListView_GetItemCount(hProcessPageListCtrl); i++) 74 { 75 memset(&item, 0, sizeof(LV_ITEM)); 76 item.mask = LVIF_PARAM; 77 item.iItem = i; 78 (void)ListView_GetItem(hProcessPageListCtrl, &item); 79 pData = (LPPROCESS_PAGE_LIST_ITEM)item.lParam; 80 if (pData->ProcessId == dwProcessId) 81 { 82 return i; 83 } 84 } 85 return 0; 86 } 87 88 DWORD GetSelectedProcessId(void) 89 { 90 int Index; 91 LVITEM lvitem; 92 93 if(ListView_GetSelectedCount(hProcessPageListCtrl) == 1) 94 { 95 Index = ListView_GetSelectionMark(hProcessPageListCtrl); 96 97 memset(&lvitem, 0, sizeof(LVITEM)); 98 99 lvitem.mask = LVIF_PARAM; 100 lvitem.iItem = Index; 101 102 (void)ListView_GetItem(hProcessPageListCtrl, &lvitem); 103 104 if (lvitem.lParam) 105 return ((LPPROCESS_PAGE_LIST_ITEM)lvitem.lParam)->ProcessId; 106 } 107 108 return 0; 109 } 110 111 void ProcessPageUpdate(void) 112 { 113 /* Enable or disable the "End Process" button */ 114 if (ListView_GetSelectedCount(hProcessPageListCtrl)) 115 EnableWindow(hProcessPageEndProcessButton, TRUE); 116 else 117 EnableWindow(hProcessPageEndProcessButton, FALSE); 118 } 119 120 INT_PTR CALLBACK 121 ProcessPageWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) 122 { 123 RECT rc; 124 int nXDifference; 125 int nYDifference; 126 int cx, cy; 127 128 switch (message) { 129 case WM_INITDIALOG: 130 /* 131 * Save the width and height 132 */ 133 GetClientRect(hDlg, &rc); 134 nProcessPageWidth = rc.right; 135 nProcessPageHeight = rc.bottom; 136 137 /* Update window position */ 138 SetWindowPos(hDlg, NULL, 15, 30, 0, 0, SWP_NOACTIVATE|SWP_NOOWNERZORDER|SWP_NOSIZE|SWP_NOZORDER); 139 140 /* 141 * Get handles to the controls 142 */ 143 hProcessPageListCtrl = GetDlgItem(hDlg, IDC_PROCESSLIST); 144 hProcessPageHeaderCtrl = ListView_GetHeader(hProcessPageListCtrl); 145 hProcessPageEndProcessButton = GetDlgItem(hDlg, IDC_ENDPROCESS); 146 hProcessPageShowAllProcessesButton = GetDlgItem(hDlg, IDC_SHOWALLPROCESSES); 147 148 /* 149 * Set the title, and extended window styles for the list control 150 */ 151 SetWindowTextW(hProcessPageListCtrl, L"Processes"); 152 (void)ListView_SetExtendedListViewStyle(hProcessPageListCtrl, ListView_GetExtendedListViewStyle(hProcessPageListCtrl) | LVS_EX_FULLROWSELECT | LVS_EX_HEADERDRAGDROP); 153 154 AddColumns(); 155 156 /* 157 * Subclass the process list control so we can intercept WM_ERASEBKGND 158 */ 159 OldProcessListWndProc = (WNDPROC)SetWindowLongPtrW(hProcessPageListCtrl, GWLP_WNDPROC, (LONG_PTR)ProcessListWndProc); 160 161 #ifdef RUN_PROC_PAGE 162 /* Start our refresh thread */ 163 hProcessThread = CreateThread(NULL, 0, ProcessPageRefreshThread, NULL, 0, &dwProcessThread); 164 #endif 165 166 /* Refresh page */ 167 ProcessPageUpdate(); 168 169 return TRUE; 170 171 case WM_DESTROY: 172 /* Close the event handle, this will make the */ 173 /* refresh thread exit when the wait fails */ 174 #ifdef RUN_PROC_PAGE 175 EndLocalThread(&hProcessThread, dwProcessThread); 176 #endif 177 SaveColumnSettings(); 178 Cleanup(); 179 break; 180 181 case WM_COMMAND: 182 /* Handle the button clicks */ 183 switch (LOWORD(wParam)) 184 { 185 case IDC_ENDPROCESS: 186 ProcessPage_OnEndProcess(); 187 } 188 break; 189 190 case WM_SIZE: 191 if (wParam == SIZE_MINIMIZED) 192 return 0; 193 194 cx = LOWORD(lParam); 195 cy = HIWORD(lParam); 196 nXDifference = cx - nProcessPageWidth; 197 nYDifference = cy - nProcessPageHeight; 198 nProcessPageWidth = cx; 199 nProcessPageHeight = cy; 200 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); 207 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); 214 215 GetClientRect(hProcessPageShowAllProcessesButton, &rc); 216 MapWindowPoints(hProcessPageShowAllProcessesButton, hDlg, (LPPOINT)(PRECT)(&rc), sizeof(RECT)/sizeof(POINT)); 217 cx = rc.left; 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); 221 break; 222 223 case WM_NOTIFY: 224 ProcessPageOnNotify(wParam, lParam); 225 break; 226 227 case WM_KEYDOWN: 228 if (wParam == VK_DELETE) 229 ProcessPage_OnEndProcess(); 230 break; 231 } 232 233 return 0; 234 } 235 236 void ProcessPageOnNotify(WPARAM wParam, LPARAM lParam) 237 { 238 LPNMHDR pnmh; 239 NMLVDISPINFO* pnmdi; 240 LPNMHEADER pnmhdr; 241 ULONG Index; 242 ULONG ColumnIndex; 243 LPPROCESS_PAGE_LIST_ITEM pData; 244 245 pnmh = (LPNMHDR) lParam; 246 pnmdi = (NMLVDISPINFO*) lParam; 247 pnmhdr = (LPNMHEADER) lParam; 248 249 if (pnmh->hwndFrom == hProcessPageListCtrl) 250 { 251 switch (pnmh->code) 252 { 253 case LVN_ITEMCHANGED: 254 ProcessPageUpdate(); 255 break; 256 257 case LVN_GETDISPINFO: 258 259 if (!(pnmdi->item.mask & LVIF_TEXT)) 260 break; 261 262 pData = (LPPROCESS_PAGE_LIST_ITEM)pnmdi->item.lParam; 263 Index = PerfDataGetProcessIndex(pData->ProcessId); 264 ColumnIndex = pnmdi->item.iSubItem; 265 266 PerfDataGetText(Index, ColumnIndex, pnmdi->item.pszText, (ULONG)pnmdi->item.cchTextMax); 267 268 break; 269 270 case NM_RCLICK: 271 272 ProcessPageShowContextMenu(GetSelectedProcessId()); 273 break; 274 275 case LVN_KEYDOWN: 276 277 if (((LPNMLVKEYDOWN)lParam)->wVKey == VK_DELETE) 278 ProcessPage_OnEndProcess(); 279 break; 280 281 } 282 } 283 else if (pnmh->hwndFrom == hProcessPageHeaderCtrl) 284 { 285 switch (pnmh->code) 286 { 287 case HDN_ITEMCLICK: 288 289 TaskManagerSettings.SortColumn = ColumnDataHints[pnmhdr->iItem]; 290 TaskManagerSettings.SortAscending = !TaskManagerSettings.SortAscending; 291 (void)ListView_SortItems(hProcessPageListCtrl, ProcessPageCompareFunc, NULL); 292 293 break; 294 295 case HDN_ITEMCHANGED: 296 297 UpdateColumnDataHints(); 298 299 break; 300 301 case HDN_ENDDRAG: 302 303 UpdateColumnDataHints(); 304 305 break; 306 307 } 308 } 309 } 310 311 /* 312 * Adapted from SH_FormatInteger in dll/win32/shell32/dialogs/filedefext.cpp. 313 */ 314 UINT 315 SH_FormatInteger( 316 _In_ LONGLONG Num, 317 _Out_writes_z_(cchResultMax) LPWSTR pwszResult, 318 _In_ UINT cchResultMax) 319 { 320 NUMBERFMTW nf; 321 INT i; 322 INT cchGrouping, cchResult; 323 WCHAR wszNumber[24]; 324 WCHAR wszDecimalSep[8], wszThousandSep[8]; 325 WCHAR wszGrouping[12]; 326 327 /* Print the number in uniform mode */ 328 StringCchPrintfW(wszNumber, _countof(wszNumber), L"%I64u", Num); 329 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)); 333 334 /* Initialize format for printing the number in bytes */ 335 ZeroMemory(&nf, sizeof(nf)); 336 nf.lpDecimalSep = wszDecimalSep; 337 nf.lpThousandSep = wszThousandSep; 338 339 /* Get system string for groups separator */ 340 cchGrouping = GetLocaleInfoW(LOCALE_USER_DEFAULT, 341 LOCALE_SGROUPING, 342 wszGrouping, 343 _countof(wszGrouping)); 344 345 /* Convert grouping specs from string to integer */ 346 for (i = 0; i < cchGrouping; i++) 347 { 348 WCHAR wch = wszGrouping[i]; 349 350 if (wch >= L'0' && wch <= L'9') 351 nf.Grouping = nf.Grouping * 10 + (wch - L'0'); 352 else if (wch != L';') 353 break; 354 } 355 356 if ((nf.Grouping % 10) == 0) 357 nf.Grouping /= 10; 358 else 359 nf.Grouping *= 10; 360 361 /* Format the number */ 362 cchResult = GetNumberFormatW(LOCALE_USER_DEFAULT, 363 0, 364 wszNumber, 365 &nf, 366 pwszResult, 367 cchResultMax); 368 if (!cchResult) 369 return 0; 370 371 /* GetNumberFormatW returns number of characters including UNICODE_NULL */ 372 return cchResult - 1; 373 } 374 375 void ProcessPageShowContextMenu(DWORD dwProcessId) 376 { 377 HMENU hMenu; 378 HMENU hSubMenu; 379 HMENU hPriorityMenu; 380 POINT pt; 381 SYSTEM_INFO si; 382 HANDLE hProcess; 383 DWORD dwProcessPriorityClass; 384 WCHAR strDebugger[260]; 385 DWORD dwDebuggerSize; 386 HKEY hKey; 387 388 if (dwProcessId == 0) 389 return; 390 391 memset(&si, 0, sizeof(SYSTEM_INFO)); 392 393 GetCursorPos(&pt); 394 GetSystemInfo(&si); 395 396 hMenu = LoadMenuW(hInst, MAKEINTRESOURCEW(IDR_PROCESS_PAGE_CONTEXT)); 397 hSubMenu = GetSubMenu(hMenu, 0); 398 hPriorityMenu = GetSubMenu(hSubMenu, 4); 399 400 hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, dwProcessId); 401 dwProcessPriorityClass = GetPriorityClass(hProcess); 402 CloseHandle(hProcess); 403 404 if (si.dwNumberOfProcessors < 2) 405 RemoveMenu(hSubMenu, ID_PROCESS_PAGE_SETAFFINITY, MF_BYCOMMAND); 406 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); 410 break; 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); 413 break; 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); 416 break; 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); 419 break; 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); 422 break; 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); 425 break; 426 } 427 428 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug", 0, KEY_READ, &hKey) == ERROR_SUCCESS) 429 { 430 dwDebuggerSize = sizeof(strDebugger); 431 if (RegQueryValueExW(hKey, L"Debugger", NULL, NULL, (LPBYTE)strDebugger, &dwDebuggerSize) == ERROR_SUCCESS) 432 { 433 CharUpper(strDebugger); 434 if (wcsstr(strDebugger, L"DRWTSN32")) 435 EnableMenuItem(hSubMenu, ID_PROCESS_PAGE_DEBUG, MF_BYCOMMAND|MF_DISABLED|MF_GRAYED); 436 } 437 else 438 EnableMenuItem(hSubMenu, ID_PROCESS_PAGE_DEBUG, MF_BYCOMMAND|MF_DISABLED|MF_GRAYED); 439 440 RegCloseKey(hKey); 441 } else { 442 EnableMenuItem(hSubMenu, ID_PROCESS_PAGE_DEBUG, MF_BYCOMMAND|MF_DISABLED|MF_GRAYED); 443 } 444 TrackPopupMenu(hSubMenu, TPM_LEFTALIGN|TPM_TOPALIGN|TPM_LEFTBUTTON, pt.x, pt.y, 0, hMainWnd, NULL); 445 DestroyMenu(hMenu); 446 } 447 448 void RefreshProcessPage(void) 449 { 450 #ifdef RUN_PROC_PAGE 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); 454 #endif 455 } 456 457 DWORD WINAPI ProcessPageRefreshThread(void *lpParameter) 458 { 459 MSG msg; 460 461 while (1) { 462 /* Wait for an the event or application close */ 463 if (GetMessage(&msg, NULL, 0, 0) <= 0) 464 return 0; 465 466 if (msg.message == WM_TIMER) { 467 468 UpdateProcesses(); 469 470 if (IsWindowVisible(hProcessPage)) 471 InvalidateRect(hProcessPageListCtrl, NULL, FALSE); 472 473 ProcessPageUpdate(); 474 } 475 } 476 return 0; 477 } 478 479 void UpdateProcesses() 480 { 481 int i; 482 ULONG l; 483 LV_ITEM item; 484 LPPROCESS_PAGE_LIST_ITEM pData; 485 486 SendMessage(hProcessPageListCtrl, WM_SETREDRAW, FALSE, 0); 487 488 /* Remove old processes */ 489 for (i = 0; i < ListView_GetItemCount(hProcessPageListCtrl); i++) 490 { 491 memset(&item, 0, sizeof (LV_ITEM)); 492 item.mask = LVIF_PARAM; 493 item.iItem = i; 494 (void)ListView_GetItem(hProcessPageListCtrl, &item); 495 pData = (LPPROCESS_PAGE_LIST_ITEM)item.lParam; 496 if (!ProcessRunning(pData->ProcessId)) 497 { 498 (void)ListView_DeleteItem(hProcessPageListCtrl, i); 499 HeapFree(GetProcessHeap(), 0, pData); 500 } 501 } 502 503 /* Check for difference in listview process and performance process counts */ 504 if (ListView_GetItemCount(hProcessPageListCtrl) != PerfDataGetProcessCount()) 505 { 506 /* Add new processes by checking against the current items */ 507 for (l = 0; l < PerfDataGetProcessCount(); l++) 508 { 509 AddProcess(l); 510 } 511 } 512 513 if (TaskManagerSettings.SortColumn != -1) 514 { 515 (void)ListView_SortItems(hProcessPageListCtrl, ProcessPageCompareFunc, NULL); 516 } 517 518 SendMessage(hProcessPageListCtrl, WM_SETREDRAW, TRUE, 0); 519 520 /* Select first item if any */ 521 if ((ListView_GetNextItem(hProcessPageListCtrl, -1, LVNI_FOCUSED | LVNI_SELECTED) == -1) && 522 (ListView_GetItemCount(hProcessPageListCtrl) > 0) && !bProcessPageSelectionMade) 523 { 524 ListView_SetItemState(hProcessPageListCtrl, 0, LVIS_FOCUSED | LVIS_SELECTED, LVIS_FOCUSED | LVIS_SELECTED); 525 bProcessPageSelectionMade = TRUE; 526 } 527 /* 528 else 529 { 530 bProcessPageSelectionMade = FALSE; 531 } 532 */ 533 } 534 535 BOOL ProcessRunning(ULONG ProcessId) 536 { 537 HANDLE hProcess; 538 DWORD exitCode; 539 540 if (ProcessId == 0) { 541 return TRUE; 542 } 543 544 hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, ProcessId); 545 if (hProcess == NULL) { 546 return FALSE; 547 } 548 549 if (GetExitCodeProcess(hProcess, &exitCode)) { 550 CloseHandle(hProcess); 551 return (exitCode == STILL_ACTIVE); 552 } 553 554 CloseHandle(hProcess); 555 return FALSE; 556 } 557 558 void AddProcess(ULONG Index) 559 { 560 LPPROCESS_PAGE_LIST_ITEM pData; 561 int i; 562 LV_ITEM item; 563 BOOL bAlreadyInList = FALSE; 564 ULONG pid; 565 566 pid = PerfDataGetProcessId(Index); 567 568 /* Check to see if it's already in our list */ 569 for (i=0; i<ListView_GetItemCount(hProcessPageListCtrl); i++) 570 { 571 memset(&item, 0, sizeof(LV_ITEM)); 572 item.mask = LVIF_PARAM; 573 item.iItem = i; 574 (void)ListView_GetItem(hProcessPageListCtrl, &item); 575 pData = (LPPROCESS_PAGE_LIST_ITEM)item.lParam; 576 if (pData->ProcessId == pid) 577 { 578 bAlreadyInList = TRUE; 579 break; 580 } 581 } 582 if (!bAlreadyInList) /* Add */ 583 { 584 pData = (LPPROCESS_PAGE_LIST_ITEM)HeapAlloc(GetProcessHeap(), 0, sizeof(PROCESS_PAGE_LIST_ITEM)); 585 pData->ProcessId = pid; 586 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); 594 } 595 } 596 597 BOOL PerfDataGetText(ULONG Index, ULONG ColumnIndex, LPTSTR lpText, ULONG nMaxCount) 598 { 599 IO_COUNTERS iocounters; 600 601 switch (ColumnDataHints[ColumnIndex]) 602 { 603 case COLUMN_IMAGENAME: 604 PerfDataGetImageName(Index, lpText, nMaxCount); 605 return TRUE; 606 607 case COLUMN_PID: 608 StringCchPrintfW(lpText, nMaxCount, L"%lu", PerfDataGetProcessId(Index)); 609 return TRUE; 610 611 case COLUMN_USERNAME: 612 PerfDataGetUserName(Index, lpText, nMaxCount); 613 return TRUE; 614 615 case COLUMN_COMMANDLINE: 616 PerfDataGetCommandLine(Index, lpText, nMaxCount); 617 return TRUE; 618 619 case COLUMN_SESSIONID: 620 StringCchPrintfW(lpText, nMaxCount, L"%lu", PerfDataGetSessionId(Index)); 621 return TRUE; 622 623 case COLUMN_CPUUSAGE: 624 StringCchPrintfW(lpText, nMaxCount, L"%02lu", PerfDataGetCPUUsage(Index)); 625 return TRUE; 626 627 case COLUMN_CPUTIME: 628 { 629 LARGE_INTEGER time; 630 DWORD dwHours; 631 DWORD dwMinutes; 632 DWORD dwSeconds; 633 634 time = PerfDataGetCPUTime(Index); 635 gethmsfromlargeint(time, &dwHours, &dwMinutes, &dwSeconds); 636 StringCchPrintfW(lpText, nMaxCount, L"%lu:%02lu:%02lu", dwHours, dwMinutes, dwSeconds); 637 return TRUE; 638 } 639 640 case COLUMN_MEMORYUSAGE: 641 SH_FormatInteger(PerfDataGetWorkingSetSizeBytes(Index) / 1024, lpText, nMaxCount); 642 StringCchCatW(lpText, nMaxCount, L" K"); 643 return TRUE; 644 645 case COLUMN_PEAKMEMORYUSAGE: 646 SH_FormatInteger(PerfDataGetPeakWorkingSetSizeBytes(Index) / 1024, lpText, nMaxCount); 647 StringCchCatW(lpText, nMaxCount, L" K"); 648 return TRUE; 649 650 case COLUMN_MEMORYUSAGEDELTA: 651 SH_FormatInteger(PerfDataGetWorkingSetSizeDelta(Index) / 1024, lpText, nMaxCount); 652 StringCchCatW(lpText, nMaxCount, L" K"); 653 return TRUE; 654 655 case COLUMN_PAGEFAULTS: 656 SH_FormatInteger(PerfDataGetPageFaultCount(Index), lpText, nMaxCount); 657 return TRUE; 658 659 case COLUMN_PAGEFAULTSDELTA: 660 SH_FormatInteger(PerfDataGetPageFaultCountDelta(Index), lpText, nMaxCount); 661 return TRUE; 662 663 case COLUMN_VIRTUALMEMORYSIZE: 664 SH_FormatInteger(PerfDataGetVirtualMemorySizeBytes(Index) / 1024, lpText, nMaxCount); 665 StringCchCatW(lpText, nMaxCount, L" K"); 666 return TRUE; 667 668 case COLUMN_PAGEDPOOL: 669 SH_FormatInteger(PerfDataGetPagedPoolUsagePages(Index) / 1024, lpText, nMaxCount); 670 StringCchCatW(lpText, nMaxCount, L" K"); 671 return TRUE; 672 673 case COLUMN_NONPAGEDPOOL: 674 SH_FormatInteger(PerfDataGetNonPagedPoolUsagePages(Index) / 1024, lpText, nMaxCount); 675 StringCchCatW(lpText, nMaxCount, L" K"); 676 return TRUE; 677 678 case COLUMN_BASEPRIORITY: 679 StringCchPrintfW(lpText, nMaxCount, L"%lu", PerfDataGetBasePriority(Index)); 680 return TRUE; 681 682 case COLUMN_HANDLECOUNT: 683 SH_FormatInteger(PerfDataGetHandleCount(Index), lpText, nMaxCount); 684 return TRUE; 685 686 case COLUMN_THREADCOUNT: 687 SH_FormatInteger(PerfDataGetThreadCount(Index), lpText, nMaxCount); 688 return TRUE; 689 690 case COLUMN_USEROBJECTS: 691 SH_FormatInteger(PerfDataGetUSERObjectCount(Index), lpText, nMaxCount); 692 return TRUE; 693 694 case COLUMN_GDIOBJECTS: 695 SH_FormatInteger(PerfDataGetGDIObjectCount(Index), lpText, nMaxCount); 696 return TRUE; 697 698 case COLUMN_IOREADS: 699 PerfDataGetIOCounters(Index, &iocounters); 700 SH_FormatInteger(iocounters.ReadOperationCount, lpText, nMaxCount); 701 return TRUE; 702 703 case COLUMN_IOWRITES: 704 PerfDataGetIOCounters(Index, &iocounters); 705 SH_FormatInteger(iocounters.WriteOperationCount, lpText, nMaxCount); 706 return TRUE; 707 708 case COLUMN_IOOTHER: 709 PerfDataGetIOCounters(Index, &iocounters); 710 SH_FormatInteger(iocounters.OtherOperationCount, lpText, nMaxCount); 711 return TRUE; 712 713 case COLUMN_IOREADBYTES: 714 PerfDataGetIOCounters(Index, &iocounters); 715 SH_FormatInteger(iocounters.ReadTransferCount, lpText, nMaxCount); 716 return TRUE; 717 718 case COLUMN_IOWRITEBYTES: 719 PerfDataGetIOCounters(Index, &iocounters); 720 SH_FormatInteger(iocounters.WriteTransferCount, lpText, nMaxCount); 721 return TRUE; 722 723 case COLUMN_IOOTHERBYTES: 724 PerfDataGetIOCounters(Index, &iocounters); 725 SH_FormatInteger(iocounters.OtherTransferCount, lpText, nMaxCount); 726 return TRUE; 727 } 728 729 return FALSE; 730 } 731 732 733 void gethmsfromlargeint(LARGE_INTEGER largeint, DWORD *dwHours, DWORD *dwMinutes, DWORD *dwSeconds) 734 { 735 #ifdef _MSC_VER 736 *dwHours = (DWORD)(largeint.QuadPart / 36000000000L); 737 *dwMinutes = (DWORD)((largeint.QuadPart % 36000000000L) / 600000000L); 738 *dwSeconds = (DWORD)(((largeint.QuadPart % 36000000000L) % 600000000L) / 10000000L); 739 #else 740 *dwHours = (DWORD)(largeint.QuadPart / 36000000000LL); 741 *dwMinutes = (DWORD)((largeint.QuadPart % 36000000000LL) / 600000000LL); 742 *dwSeconds = (DWORD)(((largeint.QuadPart % 36000000000LL) % 600000000LL) / 10000000LL); 743 #endif 744 } 745 746 int largeintcmp(LARGE_INTEGER l1, LARGE_INTEGER l2) 747 { 748 int ret = 0; 749 DWORD dwHours1; 750 DWORD dwMinutes1; 751 DWORD dwSeconds1; 752 DWORD dwHours2; 753 DWORD dwMinutes2; 754 DWORD dwSeconds2; 755 756 gethmsfromlargeint(l1, &dwHours1, &dwMinutes1, &dwSeconds1); 757 gethmsfromlargeint(l2, &dwHours2, &dwMinutes2, &dwSeconds2); 758 ret = CMP(dwHours1, dwHours2); 759 if (ret == 0) 760 { 761 ret = CMP(dwMinutes1, dwMinutes2); 762 if (ret == 0) 763 { 764 ret = CMP(dwSeconds1, dwSeconds2); 765 } 766 } 767 return ret; 768 } 769 770 int CALLBACK ProcessPageCompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) 771 { 772 int ret = 0; 773 LPPROCESS_PAGE_LIST_ITEM Param1; 774 LPPROCESS_PAGE_LIST_ITEM Param2; 775 ULONG IndexParam1; 776 ULONG IndexParam2; 777 WCHAR text1[260]; 778 WCHAR text2[260]; 779 ULONG l1; 780 ULONG l2; 781 LARGE_INTEGER time1; 782 LARGE_INTEGER time2; 783 IO_COUNTERS iocounters1; 784 IO_COUNTERS iocounters2; 785 ULONGLONG ull1; 786 ULONGLONG ull2; 787 788 if (TaskManagerSettings.SortAscending) { 789 Param1 = (LPPROCESS_PAGE_LIST_ITEM)lParam1; 790 Param2 = (LPPROCESS_PAGE_LIST_ITEM)lParam2; 791 } else { 792 Param1 = (LPPROCESS_PAGE_LIST_ITEM)lParam2; 793 Param2 = (LPPROCESS_PAGE_LIST_ITEM)lParam1; 794 } 795 IndexParam1 = PerfDataGetProcessIndex(Param1->ProcessId); 796 IndexParam2 = PerfDataGetProcessIndex(Param2->ProcessId); 797 798 if (TaskManagerSettings.SortColumn == COLUMN_IMAGENAME) 799 { 800 PerfDataGetImageName(IndexParam1, text1, _countof(text1)); 801 PerfDataGetImageName(IndexParam2, text2, _countof(text2)); 802 ret = _wcsicmp(text1, text2); 803 } 804 else if (TaskManagerSettings.SortColumn == COLUMN_PID) 805 { 806 l1 = Param1->ProcessId; 807 l2 = Param2->ProcessId; 808 ret = CMP(l1, l2); 809 } 810 else if (TaskManagerSettings.SortColumn == COLUMN_USERNAME) 811 { 812 PerfDataGetUserName(IndexParam1, text1, _countof(text1)); 813 PerfDataGetUserName(IndexParam2, text2, _countof(text2)); 814 ret = _wcsicmp(text1, text2); 815 } 816 else if (TaskManagerSettings.SortColumn == COLUMN_COMMANDLINE) 817 { 818 PerfDataGetCommandLine(IndexParam1, text1, _countof(text1)); 819 PerfDataGetCommandLine(IndexParam2, text2, _countof(text2)); 820 ret = _wcsicmp(text1, text2); 821 } 822 else if (TaskManagerSettings.SortColumn == COLUMN_SESSIONID) 823 { 824 l1 = PerfDataGetSessionId(IndexParam1); 825 l2 = PerfDataGetSessionId(IndexParam2); 826 ret = CMP(l1, l2); 827 } 828 else if (TaskManagerSettings.SortColumn == COLUMN_CPUUSAGE) 829 { 830 l1 = PerfDataGetCPUUsage(IndexParam1); 831 l2 = PerfDataGetCPUUsage(IndexParam2); 832 ret = CMP(l1, l2); 833 } 834 else if (TaskManagerSettings.SortColumn == COLUMN_CPUTIME) 835 { 836 time1 = PerfDataGetCPUTime(IndexParam1); 837 time2 = PerfDataGetCPUTime(IndexParam2); 838 ret = largeintcmp(time1, time2); 839 } 840 else if (TaskManagerSettings.SortColumn == COLUMN_MEMORYUSAGE) 841 { 842 l1 = PerfDataGetWorkingSetSizeBytes(IndexParam1); 843 l2 = PerfDataGetWorkingSetSizeBytes(IndexParam2); 844 ret = CMP(l1, l2); 845 } 846 else if (TaskManagerSettings.SortColumn == COLUMN_PEAKMEMORYUSAGE) 847 { 848 l1 = PerfDataGetPeakWorkingSetSizeBytes(IndexParam1); 849 l2 = PerfDataGetPeakWorkingSetSizeBytes(IndexParam2); 850 ret = CMP(l1, l2); 851 } 852 else if (TaskManagerSettings.SortColumn == COLUMN_MEMORYUSAGEDELTA) 853 { 854 l1 = PerfDataGetWorkingSetSizeDelta(IndexParam1); 855 l2 = PerfDataGetWorkingSetSizeDelta(IndexParam2); 856 ret = CMP(l1, l2); 857 } 858 else if (TaskManagerSettings.SortColumn == COLUMN_PAGEFAULTS) 859 { 860 l1 = PerfDataGetPageFaultCount(IndexParam1); 861 l2 = PerfDataGetPageFaultCount(IndexParam2); 862 ret = CMP(l1, l2); 863 } 864 else if (TaskManagerSettings.SortColumn == COLUMN_PAGEFAULTSDELTA) 865 { 866 l1 = PerfDataGetPageFaultCountDelta(IndexParam1); 867 l2 = PerfDataGetPageFaultCountDelta(IndexParam2); 868 ret = CMP(l1, l2); 869 } 870 else if (TaskManagerSettings.SortColumn == COLUMN_VIRTUALMEMORYSIZE) 871 { 872 l1 = PerfDataGetVirtualMemorySizeBytes(IndexParam1); 873 l2 = PerfDataGetVirtualMemorySizeBytes(IndexParam2); 874 ret = CMP(l1, l2); 875 } 876 else if (TaskManagerSettings.SortColumn == COLUMN_PAGEDPOOL) 877 { 878 l1 = PerfDataGetPagedPoolUsagePages(IndexParam1); 879 l2 = PerfDataGetPagedPoolUsagePages(IndexParam2); 880 ret = CMP(l1, l2); 881 } 882 else if (TaskManagerSettings.SortColumn == COLUMN_NONPAGEDPOOL) 883 { 884 l1 = PerfDataGetNonPagedPoolUsagePages(IndexParam1); 885 l2 = PerfDataGetNonPagedPoolUsagePages(IndexParam2); 886 ret = CMP(l1, l2); 887 } 888 else if (TaskManagerSettings.SortColumn == COLUMN_BASEPRIORITY) 889 { 890 l1 = PerfDataGetBasePriority(IndexParam1); 891 l2 = PerfDataGetBasePriority(IndexParam2); 892 ret = CMP(l1, l2); 893 } 894 else if (TaskManagerSettings.SortColumn == COLUMN_HANDLECOUNT) 895 { 896 l1 = PerfDataGetHandleCount(IndexParam1); 897 l2 = PerfDataGetHandleCount(IndexParam2); 898 ret = CMP(l1, l2); 899 } 900 else if (TaskManagerSettings.SortColumn == COLUMN_THREADCOUNT) 901 { 902 l1 = PerfDataGetThreadCount(IndexParam1); 903 l2 = PerfDataGetThreadCount(IndexParam2); 904 ret = CMP(l1, l2); 905 } 906 else if (TaskManagerSettings.SortColumn == COLUMN_USEROBJECTS) 907 { 908 l1 = PerfDataGetUSERObjectCount(IndexParam1); 909 l2 = PerfDataGetUSERObjectCount(IndexParam2); 910 ret = CMP(l1, l2); 911 } 912 else if (TaskManagerSettings.SortColumn == COLUMN_GDIOBJECTS) 913 { 914 l1 = PerfDataGetGDIObjectCount(IndexParam1); 915 l2 = PerfDataGetGDIObjectCount(IndexParam2); 916 ret = CMP(l1, l2); 917 } 918 else if (TaskManagerSettings.SortColumn == COLUMN_IOREADS) 919 { 920 PerfDataGetIOCounters(IndexParam1, &iocounters1); 921 PerfDataGetIOCounters(IndexParam2, &iocounters2); 922 ull1 = iocounters1.ReadOperationCount; 923 ull2 = iocounters2.ReadOperationCount; 924 ret = CMP(ull1, ull2); 925 } 926 else if (TaskManagerSettings.SortColumn == COLUMN_IOWRITES) 927 { 928 PerfDataGetIOCounters(IndexParam1, &iocounters1); 929 PerfDataGetIOCounters(IndexParam2, &iocounters2); 930 ull1 = iocounters1.WriteOperationCount; 931 ull2 = iocounters2.WriteOperationCount; 932 ret = CMP(ull1, ull2); 933 } 934 else if (TaskManagerSettings.SortColumn == COLUMN_IOOTHER) 935 { 936 PerfDataGetIOCounters(IndexParam1, &iocounters1); 937 PerfDataGetIOCounters(IndexParam2, &iocounters2); 938 ull1 = iocounters1.OtherOperationCount; 939 ull2 = iocounters2.OtherOperationCount; 940 ret = CMP(ull1, ull2); 941 } 942 else if (TaskManagerSettings.SortColumn == COLUMN_IOREADBYTES) 943 { 944 PerfDataGetIOCounters(IndexParam1, &iocounters1); 945 PerfDataGetIOCounters(IndexParam2, &iocounters2); 946 ull1 = iocounters1.ReadTransferCount; 947 ull2 = iocounters2.ReadTransferCount; 948 ret = CMP(ull1, ull2); 949 } 950 else if (TaskManagerSettings.SortColumn == COLUMN_IOWRITEBYTES) 951 { 952 PerfDataGetIOCounters(IndexParam1, &iocounters1); 953 PerfDataGetIOCounters(IndexParam2, &iocounters2); 954 ull1 = iocounters1.WriteTransferCount; 955 ull2 = iocounters2.WriteTransferCount; 956 ret = CMP(ull1, ull2); 957 } 958 else if (TaskManagerSettings.SortColumn == COLUMN_IOOTHERBYTES) 959 { 960 PerfDataGetIOCounters(IndexParam1, &iocounters1); 961 PerfDataGetIOCounters(IndexParam2, &iocounters2); 962 ull1 = iocounters1.OtherTransferCount; 963 ull2 = iocounters2.OtherTransferCount; 964 ret = CMP(ull1, ull2); 965 } 966 return ret; 967 } 968 969 /** 970 * @brief 971 * Maps an NT "\Device\..." path to its Win32 "DOS" equivalent. 972 * 973 * @param[in] lpDevicePath 974 * The NT device path to convert. 975 * 976 * @param[out] lpDosPath 977 * Receives the converted Win32 path. 978 * 979 * @param[in] dwLength 980 * Size of the lpDosPath buffer in characters. 981 * 982 * @return 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. 986 **/ 987 static DWORD 988 DevicePathToDosPath( 989 _In_ LPCWSTR lpDevicePath, 990 _Out_writes_to_opt_(dwLength, return) 991 LPWSTR lpDosPath, 992 _In_opt_ DWORD dwLength) 993 { 994 DWORD dwRet = 0; 995 WCHAR szDrive[3] = L"?:"; 996 WCHAR szDeviceName[MAX_PATH]; 997 998 /* Check if lpDevicePath is a device path */ 999 if (_wcsnicmp(lpDevicePath, L"\\Device\\", CONST_STR_LEN(L"\\Device\\")) != 0) 1000 { 1001 return 0; 1002 } 1003 1004 for (szDrive[0] = L'A'; szDrive[0] <= L'`'; szDrive[0]++) 1005 { 1006 if (QueryDosDeviceW(szDrive, szDeviceName, _countof(szDeviceName)) != 0) 1007 { 1008 size_t len = wcslen(szDeviceName); 1009 1010 if (_wcsnicmp(lpDevicePath, szDeviceName, len) == 0) 1011 { 1012 /* Get the required length, including the NULL terminator */ 1013 dwRet = _countof(szDrive) + wcslen(lpDevicePath + len); 1014 1015 if (lpDosPath && (dwLength >= dwRet)) 1016 { 1017 StringCchPrintfW(lpDosPath, dwLength, L"%s%s", 1018 szDrive, lpDevicePath + len); 1019 } 1020 1021 break; 1022 } 1023 } 1024 } 1025 1026 return dwRet; 1027 } 1028 1029 /** 1030 * @brief 1031 * Retrieves the Win32 path of an executable image, by handle. 1032 * 1033 * @param[in] hProcess 1034 * Handle to the executable image; it should be opened with 1035 * PROCESS_QUERY_INFORMATION access rights. 1036 * 1037 * @param[out] lpExePath 1038 * Receives the Win32 image path. 1039 * 1040 * @param[in] dwLength 1041 * Size of the lpExePath buffer in characters. 1042 * 1043 * @return 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. 1047 **/ 1048 static DWORD 1049 GetProcessExecutablePath( 1050 _In_ HANDLE hProcess, 1051 _Out_writes_to_opt_(dwLength, return) 1052 LPWSTR lpExePath, 1053 _In_opt_ DWORD dwLength) 1054 { 1055 DWORD dwRet = 0; 1056 NTSTATUS Status; 1057 BYTE StaticBuffer[sizeof(UNICODE_STRING) + (MAX_PATH * sizeof(WCHAR))]; 1058 PVOID DynamicBuffer = NULL; 1059 PUNICODE_STRING ExePath; 1060 ULONG SizeNeeded; 1061 1062 Status = NtQueryInformationProcess(hProcess, 1063 ProcessImageFileName, 1064 StaticBuffer, 1065 /* Reserve a NULL terminator */ 1066 sizeof(StaticBuffer) - sizeof(WCHAR), 1067 &SizeNeeded); 1068 if (NT_SUCCESS(Status)) 1069 { 1070 ExePath = (PUNICODE_STRING)StaticBuffer; 1071 } 1072 else if (Status == STATUS_INFO_LENGTH_MISMATCH) 1073 { 1074 /* Allocate the buffer, reserving space for a NULL terminator */ 1075 DynamicBuffer = HeapAlloc(GetProcessHeap(), 0, SizeNeeded + sizeof(WCHAR)); 1076 if (!DynamicBuffer) 1077 return 0; 1078 1079 Status = NtQueryInformationProcess(hProcess, 1080 ProcessImageFileName, 1081 DynamicBuffer, 1082 SizeNeeded, 1083 &SizeNeeded); 1084 if (!NT_SUCCESS(Status)) 1085 goto Cleanup; 1086 1087 ExePath = DynamicBuffer; 1088 } 1089 else 1090 { 1091 return 0; 1092 } 1093 1094 /* Manually NULL-terminate */ 1095 ExePath->Buffer[ExePath->Length / sizeof(WCHAR)] = UNICODE_NULL; 1096 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); 1100 1101 Cleanup: 1102 HeapFree(GetProcessHeap(), 0, DynamicBuffer); 1103 1104 return dwRet; 1105 } 1106 1107 /** 1108 * @brief 1109 * Retrieves the Win32 path of an executable image, by identifier. 1110 * 1111 * @param[in] dwProcessId 1112 * Identifier of the running executable image. 1113 * 1114 * @param[out] lpExePath 1115 * Receives the Win32 image path. 1116 * 1117 * @param[in] dwLength 1118 * Size of the lpExePath buffer in characters. 1119 * 1120 * @return 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. 1124 **/ 1125 static DWORD 1126 GetProcessExecutablePathById( 1127 _In_ DWORD dwProcessId, 1128 _Out_writes_to_opt_(dwLength, return) 1129 LPWSTR lpExePath, 1130 _In_opt_ DWORD dwLength) 1131 { 1132 DWORD dwRet = 0; 1133 1134 if (dwProcessId == 0) 1135 return 0; 1136 1137 /* PID = 4 ("System") */ 1138 if (dwProcessId == 4) 1139 { 1140 static const WCHAR szKernelExe[] = L"\\ntoskrnl.exe"; 1141 LPWSTR pszSystemDir; 1142 UINT uLength; 1143 1144 uLength = GetSystemDirectoryW(NULL, 0); 1145 if (uLength == 0) 1146 return 0; 1147 1148 pszSystemDir = HeapAlloc(GetProcessHeap(), 0, uLength * sizeof(WCHAR)); 1149 if (!pszSystemDir) 1150 return 0; 1151 1152 if (GetSystemDirectoryW(pszSystemDir, uLength) != 0) 1153 { 1154 /* Get the required length, including the NULL terminator */ 1155 dwRet = uLength + CONST_STR_LEN(szKernelExe); 1156 1157 if (lpExePath && (dwLength >= dwRet)) 1158 { 1159 StringCchPrintfW(lpExePath, dwLength, L"%s%s", 1160 pszSystemDir, szKernelExe); 1161 } 1162 } 1163 1164 HeapFree(GetProcessHeap(), 0, pszSystemDir); 1165 } 1166 else 1167 { 1168 HANDLE hProcess; 1169 1170 hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, dwProcessId); 1171 if (hProcess) 1172 { 1173 dwRet = GetProcessExecutablePath(hProcess, lpExePath, dwLength); 1174 CloseHandle(hProcess); 1175 } 1176 } 1177 1178 return dwRet; 1179 } 1180 1181 void ProcessPage_OnProperties(void) 1182 { 1183 DWORD dwProcessId; 1184 DWORD dwLength; 1185 LPWSTR pszExePath; 1186 SHELLEXECUTEINFOW info = { 0 }; 1187 1188 dwProcessId = GetSelectedProcessId(); 1189 1190 /* Retrieve the image path length */ 1191 dwLength = GetProcessExecutablePathById(dwProcessId, NULL, 0); 1192 if (dwLength == 0) 1193 return; 1194 1195 /* Allocate and retrieve the image path */ 1196 pszExePath = HeapAlloc(GetProcessHeap(), 0, dwLength * sizeof(WCHAR)); 1197 if (!pszExePath) 1198 return; 1199 1200 if (GetProcessExecutablePathById(dwProcessId, pszExePath, dwLength) == 0) 1201 goto Cleanup; 1202 1203 /* Call the shell to display the file properties */ 1204 info.cbSize = sizeof(SHELLEXECUTEINFOW); 1205 info.fMask = SEE_MASK_INVOKEIDLIST; 1206 info.hwnd = NULL; 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; 1213 1214 ShellExecuteExW(&info); 1215 1216 Cleanup: 1217 HeapFree(GetProcessHeap(), 0, pszExePath); 1218 } 1219 1220 void ProcessPage_OnOpenFileLocation(void) 1221 { 1222 DWORD dwProcessId; 1223 DWORD dwLength; 1224 LPWSTR pszExePath; 1225 static const WCHAR szCmdFormat[] = L"/select,\"%s\""; 1226 LPWSTR pszCmdLine = NULL; 1227 1228 dwProcessId = GetSelectedProcessId(); 1229 1230 /* Retrieve the image path length */ 1231 dwLength = GetProcessExecutablePathById(dwProcessId, NULL, 0); 1232 if (dwLength == 0) 1233 return; 1234 1235 /* Allocate and retrieve the image path */ 1236 pszExePath = HeapAlloc(GetProcessHeap(), 0, dwLength * sizeof(WCHAR)); 1237 if (!pszExePath) 1238 return; 1239 1240 if (GetProcessExecutablePathById(dwProcessId, pszExePath, dwLength) == 0) 1241 goto Cleanup; 1242 1243 /* Build the shell command line */ 1244 dwLength += CONST_STR_LEN(szCmdFormat) - CONST_STR_LEN(L"%s"); 1245 pszCmdLine = HeapAlloc(GetProcessHeap(), 0, dwLength * sizeof(WCHAR)); 1246 if (!pszCmdLine) 1247 goto Cleanup; 1248 1249 StringCchPrintfW(pszCmdLine, dwLength, szCmdFormat, pszExePath); 1250 1251 /* Call the shell to open the file location and select it. If Explorer shell 1252 * is not available, use ReactOS's alternative file browser instead. */ 1253 ShellExecuteW(NULL, L"open", 1254 GetShellWindow() ? L"explorer.exe" : L"filebrowser.exe", 1255 pszCmdLine, NULL, SW_SHOWNORMAL); 1256 1257 Cleanup: 1258 HeapFree(GetProcessHeap(), 0, pszCmdLine); 1259 HeapFree(GetProcessHeap(), 0, pszExePath); 1260 } 1261