Process Hacker
jobprp.c
Go to the documentation of this file.
1 /*
2  * Process Hacker -
3  * job properties
4  *
5  * Copyright (C) 2010 wj32
6  *
7  * This file is part of Process Hacker.
8  *
9  * Process Hacker is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation, either version 3 of the License, or
12  * (at your option) any later version.
13  *
14  * Process Hacker is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
21  */
22 
23 #include <phapp.h>
24 #include <secedit.h>
25 #include <settings.h>
26 
27 typedef struct _JOB_PAGE_CONTEXT
28 {
29  PPH_OPEN_OBJECT OpenObject;
30  PVOID Context;
31  DLGPROC HookProc;
33 
34 INT CALLBACK PhpJobPropPageProc(
35  _In_ HWND hwnd,
36  _In_ UINT uMsg,
37  _In_ LPPROPSHEETPAGE ppsp
38  );
39 
40 INT_PTR CALLBACK PhpJobPageProc(
41  _In_ HWND hwndDlg,
42  _In_ UINT uMsg,
43  _In_ WPARAM wParam,
44  _In_ LPARAM lParam
45  );
46 
48  _In_ HWND ParentWindowHandle,
49  _In_ PJOB_PAGE_CONTEXT Context
50  );
51 
52 INT_PTR CALLBACK PhpJobStatisticsPageProc(
53  _In_ HWND hwndDlg,
54  _In_ UINT uMsg,
55  _In_ WPARAM wParam,
56  _In_ LPARAM lParam
57  );
58 
60  _In_ HWND ParentWindowHandle,
61  _In_ PPH_OPEN_OBJECT OpenObject,
62  _In_opt_ PVOID Context,
63  _In_opt_ PWSTR Title
64  )
65 {
66  PROPSHEETHEADER propSheetHeader = { sizeof(propSheetHeader) };
67  HPROPSHEETPAGE pages[1];
68 
69  propSheetHeader.dwFlags =
70  PSH_NOAPPLYNOW |
71  PSH_NOCONTEXTHELP |
72  PSH_PROPTITLE;
73  propSheetHeader.hwndParent = ParentWindowHandle;
74  propSheetHeader.pszCaption = Title ? Title : L"Job";
75  propSheetHeader.nPages = 1;
76  propSheetHeader.nStartPage = 0;
77  propSheetHeader.phpage = pages;
78 
79  pages[0] = PhCreateJobPage(OpenObject, Context, NULL);
80 
81  PropertySheet(&propSheetHeader);
82 }
83 
84 HPROPSHEETPAGE PhCreateJobPage(
85  _In_ PPH_OPEN_OBJECT OpenObject,
86  _In_opt_ PVOID Context,
87  _In_opt_ DLGPROC HookProc
88  )
89 {
90  HPROPSHEETPAGE propSheetPageHandle;
91  PROPSHEETPAGE propSheetPage;
92  PJOB_PAGE_CONTEXT jobPageContext;
93 
94  jobPageContext = PhCreateAlloc(sizeof(JOB_PAGE_CONTEXT));
95  memset(jobPageContext, 0, sizeof(JOB_PAGE_CONTEXT));
96  jobPageContext->OpenObject = OpenObject;
97  jobPageContext->Context = Context;
98  jobPageContext->HookProc = HookProc;
99 
100  memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE));
101  propSheetPage.dwSize = sizeof(PROPSHEETPAGE);
102  propSheetPage.dwFlags = PSP_USECALLBACK;
103  propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_OBJJOB);
104  propSheetPage.pfnDlgProc = PhpJobPageProc;
105  propSheetPage.lParam = (LPARAM)jobPageContext;
106  propSheetPage.pfnCallback = PhpJobPropPageProc;
107 
108  propSheetPageHandle = CreatePropertySheetPage(&propSheetPage);
109  // CreatePropertySheetPage would have sent PSPCB_ADDREF (below),
110  // which would have added a reference.
111  PhDereferenceObject(jobPageContext);
112 
113  return propSheetPageHandle;
114 }
115 
116 INT CALLBACK PhpJobPropPageProc(
117  _In_ HWND hwnd,
118  _In_ UINT uMsg,
119  _In_ LPPROPSHEETPAGE ppsp
120  )
121 {
122  PJOB_PAGE_CONTEXT jobPageContext;
123 
124  jobPageContext = (PJOB_PAGE_CONTEXT)ppsp->lParam;
125 
126  if (uMsg == PSPCB_ADDREF)
127  {
128  PhReferenceObject(jobPageContext);
129  }
130  else if (uMsg == PSPCB_RELEASE)
131  {
132  PhDereferenceObject(jobPageContext);
133  }
134 
135  return 1;
136 }
137 
139  _In_ HWND hwndDlg,
140  _In_ UINT uMsg,
141  _In_ WPARAM wParam,
142  _In_ LPARAM lParam
143  )
144 {
146  hwndDlg, uMsg, wParam, lParam, L"JobPageContext");
147 }
148 
149 static VOID PhpAddLimit(
150  _In_ HWND Handle,
151  _In_ PWSTR Name,
152  _In_ PWSTR Value
153  )
154 {
155  INT lvItemIndex;
156 
157  lvItemIndex = PhAddListViewItem(Handle, MAXINT, Name, NULL);
158  PhSetListViewSubItem(Handle, lvItemIndex, 1, Value);
159 }
160 
161 static VOID PhpAddJobProcesses(
162  _In_ HWND hwndDlg,
163  _In_ HANDLE JobHandle
164  )
165 {
166  PJOBOBJECT_BASIC_PROCESS_ID_LIST processIdList;
167  HWND processesLv;
168 
169  processesLv = GetDlgItem(hwndDlg, IDC_PROCESSES);
170 
171  if (NT_SUCCESS(PhGetJobProcessIdList(JobHandle, &processIdList)))
172  {
173  ULONG i;
174  CLIENT_ID clientId;
175  PPH_STRING name;
176 
177  clientId.UniqueThread = NULL;
178 
179  for (i = 0; i < processIdList->NumberOfProcessIdsInList; i++)
180  {
181  clientId.UniqueProcess = (HANDLE)processIdList->ProcessIdList[i];
182  name = PhAutoDereferenceObject(PhGetClientIdName(&clientId));
183 
184  PhAddListViewItem(processesLv, MAXINT, PhGetString(name), NULL);
185  }
186 
187  PhFree(processIdList);
188  }
189 }
190 
191 INT_PTR CALLBACK PhpJobPageProc(
192  _In_ HWND hwndDlg,
193  _In_ UINT uMsg,
194  _In_ WPARAM wParam,
195  _In_ LPARAM lParam
196  )
197 {
198  PJOB_PAGE_CONTEXT jobPageContext;
199 
200  jobPageContext = PhpJobPageHeader(hwndDlg, uMsg, wParam, lParam);
201 
202  if (!jobPageContext)
203  return FALSE;
204 
205  if (jobPageContext->HookProc)
206  {
207  if (jobPageContext->HookProc(hwndDlg, uMsg, wParam, lParam))
208  return TRUE;
209  }
210 
211  switch (uMsg)
212  {
213  case WM_INITDIALOG:
214  {
215  HANDLE jobHandle;
216  HWND processesLv;
217  HWND limitsLv;
218 
219  processesLv = GetDlgItem(hwndDlg, IDC_PROCESSES);
220  limitsLv = GetDlgItem(hwndDlg, IDC_LIMITS);
221  PhSetListViewStyle(processesLv, FALSE, TRUE);
222  PhSetListViewStyle(limitsLv, FALSE, TRUE);
223  PhSetControlTheme(processesLv, L"explorer");
224  PhSetControlTheme(limitsLv, L"explorer");
225 
226  PhAddListViewColumn(processesLv, 0, 0, 0, LVCFMT_LEFT, 240, L"Name");
227 
228  PhAddListViewColumn(limitsLv, 0, 0, 0, LVCFMT_LEFT, 120, L"Name");
229  PhAddListViewColumn(limitsLv, 1, 1, 1, LVCFMT_LEFT, 160, L"Value");
230 
231  SetDlgItemText(hwndDlg, IDC_NAME, L"Unknown");
232 
233  if (NT_SUCCESS(jobPageContext->OpenObject(
234  &jobHandle,
236  jobPageContext->Context
237  )))
238  {
239  PPH_STRING jobObjectName = NULL;
240  JOBOBJECT_EXTENDED_LIMIT_INFORMATION extendedLimits;
241  JOBOBJECT_BASIC_UI_RESTRICTIONS basicUiRestrictions;
242 
243  // Name
244 
246  NtCurrentProcess(),
247  jobHandle,
248  -1,
249  NULL,
250  NULL,
251  NULL,
252  &jobObjectName
253  );
254  PhAutoDereferenceObject(jobObjectName);
255 
256  if (jobObjectName && jobObjectName->Length == 0)
257  jobObjectName = NULL;
258 
259  SetDlgItemText(hwndDlg, IDC_NAME, PhGetStringOrDefault(jobObjectName, L"(unnamed job)"));
260 
261  // Processes
262  PhpAddJobProcesses(hwndDlg, jobHandle);
263 
264  // Limits
265 
266  if (NT_SUCCESS(PhGetJobExtendedLimits(jobHandle, &extendedLimits)))
267  {
268  ULONG flags = extendedLimits.BasicLimitInformation.LimitFlags;
269 
270  if (flags & JOB_OBJECT_LIMIT_ACTIVE_PROCESS)
271  {
272  WCHAR value[PH_INT32_STR_LEN_1];
273  PhPrintUInt32(value, extendedLimits.BasicLimitInformation.ActiveProcessLimit);
274  PhpAddLimit(limitsLv, L"Active Processes", value);
275  }
276 
277  if (flags & JOB_OBJECT_LIMIT_AFFINITY)
278  {
279  WCHAR value[PH_PTR_STR_LEN_1];
280  PhPrintPointer(value, (PVOID)extendedLimits.BasicLimitInformation.Affinity);
281  PhpAddLimit(limitsLv, L"Affinity", value);
282  }
283 
284  if (flags & JOB_OBJECT_LIMIT_BREAKAWAY_OK)
285  {
286  PhpAddLimit(limitsLv, L"Breakaway OK", L"Enabled");
287  }
288 
289  if (flags & JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION)
290  {
291  PhpAddLimit(limitsLv, L"Die on Unhandled Exception", L"Enabled");
292  }
293 
294  if (flags & JOB_OBJECT_LIMIT_JOB_MEMORY)
295  {
296  PPH_STRING value = PhFormatSize(extendedLimits.JobMemoryLimit, -1);
297  PhpAddLimit(limitsLv, L"Job Memory", value->Buffer);
298  PhDereferenceObject(value);
299  }
300 
301  if (flags & JOB_OBJECT_LIMIT_JOB_TIME)
302  {
303  WCHAR value[PH_TIMESPAN_STR_LEN_1];
304  PhPrintTimeSpan(value, extendedLimits.BasicLimitInformation.PerJobUserTimeLimit.QuadPart,
306  PhpAddLimit(limitsLv, L"Job Time", value);
307  }
308 
309  if (flags & JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE)
310  {
311  PhpAddLimit(limitsLv, L"Kill on Job Close", L"Enabled");
312  }
313 
314  if (flags & JOB_OBJECT_LIMIT_PRIORITY_CLASS)
315  {
316  PhpAddLimit(limitsLv, L"Priority Class",
317  PhGetProcessPriorityClassString(extendedLimits.BasicLimitInformation.PriorityClass));
318  }
319 
320  if (flags & JOB_OBJECT_LIMIT_PROCESS_MEMORY)
321  {
322  PPH_STRING value = PhFormatSize(extendedLimits.ProcessMemoryLimit, -1);
323  PhpAddLimit(limitsLv, L"Process Memory", value->Buffer);
324  PhDereferenceObject(value);
325  }
326 
327  if (flags & JOB_OBJECT_LIMIT_PROCESS_TIME)
328  {
329  WCHAR value[PH_TIMESPAN_STR_LEN_1];
330  PhPrintTimeSpan(value, extendedLimits.BasicLimitInformation.PerProcessUserTimeLimit.QuadPart,
332  PhpAddLimit(limitsLv, L"Process Time", value);
333  }
334 
335  if (flags & JOB_OBJECT_LIMIT_SCHEDULING_CLASS)
336  {
337  WCHAR value[PH_INT32_STR_LEN_1];
338  PhPrintUInt32(value, extendedLimits.BasicLimitInformation.SchedulingClass);
339  PhpAddLimit(limitsLv, L"Scheduling Class", value);
340  }
341 
342  if (flags & JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK)
343  {
344  PhpAddLimit(limitsLv, L"Silent Breakaway OK", L"Enabled");
345  }
346 
347  if (flags & JOB_OBJECT_LIMIT_WORKINGSET)
348  {
349  PPH_STRING value;
350 
351  value = PhFormatSize(extendedLimits.BasicLimitInformation.MinimumWorkingSetSize, -1);
352  PhpAddLimit(limitsLv, L"Working Set Minimum", value->Buffer);
353  PhDereferenceObject(value);
354 
355  value = PhFormatSize(extendedLimits.BasicLimitInformation.MaximumWorkingSetSize, -1);
356  PhpAddLimit(limitsLv, L"Working Set Maximum", value->Buffer);
357  PhDereferenceObject(value);
358  }
359  }
360 
361  if (NT_SUCCESS(PhGetJobBasicUiRestrictions(jobHandle, &basicUiRestrictions)))
362  {
363  ULONG flags = basicUiRestrictions.UIRestrictionsClass;
364 
365  if (flags & JOB_OBJECT_UILIMIT_DESKTOP)
366  PhpAddLimit(limitsLv, L"Desktop", L"Limited");
367  if (flags & JOB_OBJECT_UILIMIT_DISPLAYSETTINGS)
368  PhpAddLimit(limitsLv, L"Display Settings", L"Limited");
369  if (flags & JOB_OBJECT_UILIMIT_EXITWINDOWS)
370  PhpAddLimit(limitsLv, L"Exit Windows", L"Limited");
371  if (flags & JOB_OBJECT_UILIMIT_GLOBALATOMS)
372  PhpAddLimit(limitsLv, L"Global Atoms", L"Limited");
373  if (flags & JOB_OBJECT_UILIMIT_HANDLES)
374  PhpAddLimit(limitsLv, L"Handles", L"Limited");
375  if (flags & JOB_OBJECT_UILIMIT_READCLIPBOARD)
376  PhpAddLimit(limitsLv, L"Read Clipboard", L"Limited");
377  if (flags & JOB_OBJECT_UILIMIT_SYSTEMPARAMETERS)
378  PhpAddLimit(limitsLv, L"System Parameters", L"Limited");
379  if (flags & JOB_OBJECT_UILIMIT_WRITECLIPBOARD)
380  PhpAddLimit(limitsLv, L"Write Clipboard", L"Limited");
381  }
382 
383  NtClose(jobHandle);
384  }
385  }
386  break;
387  case WM_COMMAND:
388  {
389  switch (LOWORD(wParam))
390  {
391  case IDC_TERMINATE:
392  {
394  hwndDlg,
395  L"terminate",
396  L"the job",
397  L"Terminating a job will terminate all processes assigned to it.",
398  TRUE
399  ))
400  {
401  NTSTATUS status;
402  HANDLE jobHandle;
403 
404  if (NT_SUCCESS(status = jobPageContext->OpenObject(
405  &jobHandle,
407  jobPageContext->Context
408  )))
409  {
410  status = NtTerminateJobObject(jobHandle, STATUS_SUCCESS);
411  NtClose(jobHandle);
412  }
413 
414  if (!NT_SUCCESS(status))
415  PhShowStatus(hwndDlg, L"Unable to terminate the job", status, 0);
416  }
417  }
418  break;
419  case IDC_ADD:
420  {
421  NTSTATUS status;
422  HANDLE processId;
423  HANDLE processHandle;
424  HANDLE jobHandle;
425 
427  hwndDlg,
428  L"Select a process to add to the job permanently.",
429  &processId
430  ))
431  {
432  if (NT_SUCCESS(status = PhOpenProcess(
433  &processHandle,
435  processId
436  )))
437  {
438  if (NT_SUCCESS(status = jobPageContext->OpenObject(
439  &jobHandle,
441  jobPageContext->Context
442  )))
443  {
444  status = NtAssignProcessToJobObject(jobHandle, processHandle);
445 
446  if (NT_SUCCESS(status))
447  {
448  ListView_DeleteAllItems(GetDlgItem(hwndDlg, IDC_PROCESSES));
449  PhpAddJobProcesses(hwndDlg, jobHandle);
450  }
451 
452  NtClose(jobHandle);
453  }
454 
455  NtClose(processHandle);
456  }
457 
458  if (NT_SUCCESS(status))
459  break;
460  else
461  PhShowStatus(hwndDlg, L"Unable to add the process to the job", status, 0);
462  }
463  }
464  break;
465  case IDC_ADVANCED:
466  {
467  PhpShowJobAdvancedProperties(hwndDlg, jobPageContext);
468  }
469  break;
470  }
471  }
472  break;
473  case WM_NOTIFY:
474  {
477  }
478  break;
479  }
480 
481  return FALSE;
482 }
483 
485  _In_ HWND ParentWindowHandle,
486  _In_ PJOB_PAGE_CONTEXT Context
487  )
488 {
489  PROPSHEETHEADER propSheetHeader = { sizeof(propSheetHeader) };
490  HPROPSHEETPAGE pages[2];
491  PROPSHEETPAGE statisticsPage;
492  PH_STD_OBJECT_SECURITY stdObjectSecurity;
493  PPH_ACCESS_ENTRY accessEntries;
494  ULONG numberOfAccessEntries;
495 
496  propSheetHeader.dwFlags =
497  PSH_NOAPPLYNOW |
498  PSH_NOCONTEXTHELP |
499  PSH_PROPTITLE;
500  propSheetHeader.hwndParent = ParentWindowHandle;
501  propSheetHeader.pszCaption = L"Job";
502  propSheetHeader.nPages = 2;
503  propSheetHeader.nStartPage = 0;
504  propSheetHeader.phpage = pages;
505 
506  // General
507 
508  memset(&statisticsPage, 0, sizeof(PROPSHEETPAGE));
509  statisticsPage.dwSize = sizeof(PROPSHEETPAGE);
510  statisticsPage.pszTemplate = MAKEINTRESOURCE(IDD_JOBSTATISTICS);
511  statisticsPage.pfnDlgProc = PhpJobStatisticsPageProc;
512  statisticsPage.lParam = (LPARAM)Context;
513  pages[0] = CreatePropertySheetPage(&statisticsPage);
514 
515  // Security
516 
517  stdObjectSecurity.OpenObject = Context->OpenObject;
518  stdObjectSecurity.ObjectType = L"Job";
519  stdObjectSecurity.Context = Context->Context;
520 
521  if (PhGetAccessEntries(L"Job", &accessEntries, &numberOfAccessEntries))
522  {
523  pages[1] = PhCreateSecurityPage(
524  L"Job",
527  &stdObjectSecurity,
528  accessEntries,
529  numberOfAccessEntries
530  );
531  PhFree(accessEntries);
532  }
533 
534  PropertySheet(&propSheetHeader);
535 }
536 
537 static VOID PhpRefreshJobStatisticsInfo(
538  _In_ HWND hwndDlg,
539  _In_ PJOB_PAGE_CONTEXT Context
540  )
541 {
542  HANDLE jobHandle = NULL;
543  JOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION basicAndIo;
544  JOBOBJECT_EXTENDED_LIMIT_INFORMATION extendedLimitInfo;
545 
546  Context->OpenObject(
547  &jobHandle,
549  Context->Context
550  );
551 
552  if (jobHandle && NT_SUCCESS(PhGetJobBasicAndIoAccounting(
553  jobHandle,
554  &basicAndIo
555  )))
556  {
557  WCHAR timeSpan[PH_TIMESPAN_STR_LEN_1];
558 
559  SetDlgItemInt(hwndDlg, IDC_ZACTIVEPROCESSES_V, basicAndIo.BasicInfo.ActiveProcesses, FALSE);
560  SetDlgItemInt(hwndDlg, IDC_ZTOTALPROCESSES_V, basicAndIo.BasicInfo.TotalProcesses, FALSE);
561  SetDlgItemInt(hwndDlg, IDC_ZTERMINATEDPROCESSES_V, basicAndIo.BasicInfo.TotalTerminatedProcesses, FALSE);
562 
563  PhPrintTimeSpan(timeSpan, basicAndIo.BasicInfo.TotalUserTime.QuadPart, PH_TIMESPAN_HMSM);
564  SetDlgItemText(hwndDlg, IDC_ZUSERTIME_V, timeSpan);
565  PhPrintTimeSpan(timeSpan, basicAndIo.BasicInfo.TotalKernelTime.QuadPart, PH_TIMESPAN_HMSM);
566  SetDlgItemText(hwndDlg, IDC_ZKERNELTIME_V, timeSpan);
567  PhPrintTimeSpan(timeSpan, basicAndIo.BasicInfo.ThisPeriodTotalUserTime.QuadPart, PH_TIMESPAN_HMSM);
568  SetDlgItemText(hwndDlg, IDC_ZUSERTIMEPERIOD_V, timeSpan);
569  PhPrintTimeSpan(timeSpan, basicAndIo.BasicInfo.ThisPeriodTotalKernelTime.QuadPart, PH_TIMESPAN_HMSM);
570  SetDlgItemText(hwndDlg, IDC_ZKERNELTIMEPERIOD_V, timeSpan);
571 
572  SetDlgItemText(hwndDlg, IDC_ZPAGEFAULTS_V, PhaFormatUInt64(basicAndIo.BasicInfo.TotalPageFaultCount, TRUE)->Buffer);
573 
574  SetDlgItemText(hwndDlg, IDC_ZIOREADS_V, PhaFormatUInt64(basicAndIo.IoInfo.ReadOperationCount, TRUE)->Buffer);
575  SetDlgItemText(hwndDlg, IDC_ZIOREADBYTES_V, PhaFormatSize(basicAndIo.IoInfo.ReadTransferCount, -1)->Buffer);
576  SetDlgItemText(hwndDlg, IDC_ZIOWRITES_V, PhaFormatUInt64(basicAndIo.IoInfo.WriteOperationCount, TRUE)->Buffer);
577  SetDlgItemText(hwndDlg, IDC_ZIOWRITEBYTES_V, PhaFormatSize(basicAndIo.IoInfo.WriteTransferCount, -1)->Buffer);
578  SetDlgItemText(hwndDlg, IDC_ZIOOTHER_V, PhaFormatUInt64(basicAndIo.IoInfo.OtherOperationCount, TRUE)->Buffer);
579  SetDlgItemText(hwndDlg, IDC_ZIOOTHERBYTES_V, PhaFormatSize(basicAndIo.IoInfo.OtherTransferCount, -1)->Buffer);
580  }
581  else
582  {
583  SetDlgItemText(hwndDlg, IDC_ZACTIVEPROCESSES_V, L"Unknown");
584  SetDlgItemText(hwndDlg, IDC_ZTOTALPROCESSES_V, L"Unknown");
585  SetDlgItemText(hwndDlg, IDC_ZTERMINATEDPROCESSES_V, L"Unknown");
586 
587  SetDlgItemText(hwndDlg, IDC_ZUSERTIME_V, L"Unknown");
588  SetDlgItemText(hwndDlg, IDC_ZKERNELTIME_V, L"Unknown");
589  SetDlgItemText(hwndDlg, IDC_ZUSERTIMEPERIOD_V, L"Unknown");
590  SetDlgItemText(hwndDlg, IDC_ZKERNELTIMEPERIOD_V, L"Unknown");
591 
592  SetDlgItemText(hwndDlg, IDC_ZPAGEFAULTS_V, L"Unknown");
593 
594  SetDlgItemText(hwndDlg, IDC_ZIOREADS_V, L"Unknown");
595  SetDlgItemText(hwndDlg, IDC_ZIOREADBYTES_V, L"Unknown");
596  SetDlgItemText(hwndDlg, IDC_ZIOWRITES_V, L"Unknown");
597  SetDlgItemText(hwndDlg, IDC_ZIOWRITEBYTES_V, L"Unknown");
598  SetDlgItemText(hwndDlg, IDC_ZIOOTHER_V, L"Unknown");
599  SetDlgItemText(hwndDlg, IDC_ZIOOTHERBYTES_V, L"Unknown");
600  }
601 
602  if (jobHandle && NT_SUCCESS(PhGetJobExtendedLimits(
603  jobHandle,
604  &extendedLimitInfo
605  )))
606  {
607  SetDlgItemText(hwndDlg, IDC_ZPEAKPROCESSUSAGE_V, PhaFormatSize(extendedLimitInfo.PeakProcessMemoryUsed, -1)->Buffer);
608  SetDlgItemText(hwndDlg, IDC_ZPEAKJOBUSAGE_V, PhaFormatSize(extendedLimitInfo.PeakJobMemoryUsed, -1)->Buffer);
609  }
610  else
611  {
612  SetDlgItemText(hwndDlg, IDC_ZPEAKPROCESSUSAGE_V, L"Unknown");
613  SetDlgItemText(hwndDlg, IDC_ZPEAKJOBUSAGE_V, L"Unknown");
614  }
615 
616  if (jobHandle)
617  NtClose(jobHandle);
618 }
619 
620 INT_PTR CALLBACK PhpJobStatisticsPageProc(
621  _In_ HWND hwndDlg,
622  _In_ UINT uMsg,
623  _In_ WPARAM wParam,
624  _In_ LPARAM lParam
625  )
626 {
627  PJOB_PAGE_CONTEXT jobPageContext;
628 
629  jobPageContext = PhpJobPageHeader(hwndDlg, uMsg, wParam, lParam);
630 
631  if (!jobPageContext)
632  return FALSE;
633 
634  switch (uMsg)
635  {
636  case WM_INITDIALOG:
637  {
638  PhpRefreshJobStatisticsInfo(hwndDlg, jobPageContext);
639  SetTimer(hwndDlg, 1, PhGetIntegerSetting(L"UpdateInterval"), NULL);
640  }
641  break;
642  case WM_TIMER:
643  {
644  if (wParam == 1)
645  {
646  PhpRefreshJobStatisticsInfo(hwndDlg, jobPageContext);
647  }
648  }
649  break;
650  }
651 
652  return FALSE;
653 }