* Sync the recent cmake branch changes.
[reactos.git] / base / applications / taskmgr / taskmgr.c
1 /*
2 * ReactOS Task Manager
3 *
4 * taskmgr.c : Defines the entry point for the application.
5 *
6 * Copyright (C) 1999 - 2001 Brian Palmer <brianp@reactos.org>
7 * 2005 Klemens Friedl <frik85@reactos.at>
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * This library 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 GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24 #include <precomp.h>
25
26 #define STATUS_WINDOW 2001
27
28 /* Global Variables: */
29 HINSTANCE hInst; /* current instance */
30
31 HWND hMainWnd; /* Main Window */
32 HWND hStatusWnd; /* Status Bar Window */
33 HWND hTabWnd; /* Tab Control Window */
34
35 int nMinimumWidth; /* Minimum width of the dialog (OnSize()'s cx) */
36 int nMinimumHeight; /* Minimum height of the dialog (OnSize()'s cy) */
37
38 int nOldWidth; /* Holds the previous client area width */
39 int nOldHeight; /* Holds the previous client area height */
40
41 BOOL bInMenuLoop = FALSE; /* Tells us if we are in the menu loop */
42
43 TASKMANAGER_SETTINGS TaskManagerSettings;
44
45
46 int APIENTRY wWinMain(HINSTANCE hInstance,
47 HINSTANCE hPrevInstance,
48 LPWSTR lpCmdLine,
49 int nCmdShow)
50 {
51 HANDLE hProcess;
52 HANDLE hToken;
53 TOKEN_PRIVILEGES tkp;
54 HANDLE hMutex;
55
56 /* check wether we're already running or not */
57 hMutex = CreateMutexW(NULL, TRUE, L"taskmgrros");
58 if (hMutex && GetLastError() == ERROR_ALREADY_EXISTS)
59 {
60 /* Restore existing taskmanager and bring window to front */
61 /* Relies on the fact that the application title string and window title are the same */
62 HWND hTaskMgr;
63 TCHAR szTaskmgr[128];
64
65 LoadString(hInst, IDS_APP_TITLE, szTaskmgr, sizeof(szTaskmgr)/sizeof(TCHAR));
66 hTaskMgr = FindWindow(NULL, szTaskmgr);
67
68 if (hTaskMgr != NULL)
69 {
70 SendMessage(hTaskMgr, WM_SYSCOMMAND, SC_RESTORE, 0);
71 SetForegroundWindow(hTaskMgr);
72 }
73 return 0;
74 }
75 else if (!hMutex)
76 {
77 return 1;
78 }
79
80 /* Initialize global variables */
81 hInst = hInstance;
82
83 /* Change our priority class to HIGH */
84 hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId());
85 SetPriorityClass(hProcess, HIGH_PRIORITY_CLASS);
86 CloseHandle(hProcess);
87
88 /* Now lets get the SE_DEBUG_NAME privilege
89 * so that we can debug processes
90 */
91
92 /* Get a token for this process. */
93 if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
94 /* Get the LUID for the debug privilege. */
95 LookupPrivilegeValueW(NULL, SE_DEBUG_NAME, &tkp.Privileges[0].Luid);
96
97 tkp.PrivilegeCount = 1; /* one privilege to set */
98 tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
99
100 /* Get the debug privilege for this process. */
101 AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES)NULL, 0);
102 CloseHandle(hToken);
103 }
104
105 /* Load our settings from the registry */
106 LoadSettings();
107
108 /* Initialize perf data */
109 if (!PerfDataInitialize()) {
110 return -1;
111 }
112
113 DialogBoxW(hInst, (LPCWSTR)IDD_TASKMGR_DIALOG, NULL, TaskManagerWndProc);
114
115 /* Save our settings to the registry */
116 SaveSettings();
117 PerfDataUninitialize();
118 return 0;
119 }
120
121 /* Message handler for dialog box. */
122 INT_PTR CALLBACK
123 TaskManagerWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
124 {
125 #if 0
126 HDC hdc;
127 PAINTSTRUCT ps;
128 RECT rc;
129 #endif
130 LPRECT pRC;
131 int idctrl;
132 LPNMHDR pnmh;
133 WINDOWPLACEMENT wp;
134
135 switch (message) {
136 case WM_INITDIALOG:
137 hMainWnd = hDlg;
138 return OnCreate(hDlg);
139
140 case WM_COMMAND:
141 if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) {
142 EndDialog(hDlg, LOWORD(wParam));
143 return TRUE;
144 }
145 /* Process menu commands */
146 switch (LOWORD(wParam))
147 {
148 case ID_FILE_NEW:
149 TaskManager_OnFileNew();
150 break;
151 case ID_OPTIONS_ALWAYSONTOP:
152 TaskManager_OnOptionsAlwaysOnTop();
153 break;
154 case ID_OPTIONS_MINIMIZEONUSE:
155 TaskManager_OnOptionsMinimizeOnUse();
156 break;
157 case ID_OPTIONS_HIDEWHENMINIMIZED:
158 TaskManager_OnOptionsHideWhenMinimized();
159 break;
160 case ID_OPTIONS_SHOW16BITTASKS:
161 TaskManager_OnOptionsShow16BitTasks();
162 break;
163 case ID_RESTORE:
164 TaskManager_OnRestoreMainWindow();
165 break;
166 case ID_VIEW_LARGE:
167 case ID_VIEW_SMALL:
168 case ID_VIEW_DETAILS:
169 ApplicationPage_OnView(LOWORD(wParam));
170 break;
171 case ID_VIEW_SHOWKERNELTIMES:
172 PerformancePage_OnViewShowKernelTimes();
173 break;
174 case ID_VIEW_CPUHISTORY_ONEGRAPHALL:
175 PerformancePage_OnViewCPUHistoryOneGraphAll();
176 break;
177 case ID_VIEW_CPUHISTORY_ONEGRAPHPERCPU:
178 PerformancePage_OnViewCPUHistoryOneGraphPerCPU();
179 break;
180 case ID_VIEW_UPDATESPEED_HIGH:
181 case ID_VIEW_UPDATESPEED_NORMAL:
182 case ID_VIEW_UPDATESPEED_LOW:
183 case ID_VIEW_UPDATESPEED_PAUSED:
184 TaskManager_OnViewUpdateSpeed(LOWORD(wParam));
185 break;
186 case ID_VIEW_SELECTCOLUMNS:
187 ProcessPage_OnViewSelectColumns();
188 break;
189 case ID_VIEW_REFRESH:
190 PostMessageW(hDlg, WM_TIMER, 0, 0);
191 break;
192 case ID_WINDOWS_TILEHORIZONTALLY:
193 ApplicationPage_OnWindowsTile(MDITILE_HORIZONTAL);
194 break;
195 case ID_WINDOWS_TILEVERTICALLY:
196 ApplicationPage_OnWindowsTile(MDITILE_VERTICAL);
197 break;
198 case ID_WINDOWS_MINIMIZE:
199 ApplicationPage_OnWindowsMinimize();
200 break;
201 case ID_WINDOWS_MAXIMIZE:
202 ApplicationPage_OnWindowsMaximize();
203 break;
204 case ID_WINDOWS_CASCADE:
205 ApplicationPage_OnWindowsCascade();
206 break;
207 case ID_WINDOWS_BRINGTOFRONT:
208 ApplicationPage_OnWindowsBringToFront();
209 break;
210 case ID_APPLICATION_PAGE_SWITCHTO:
211 ApplicationPage_OnSwitchTo();
212 break;
213 case ID_APPLICATION_PAGE_ENDTASK:
214 ApplicationPage_OnEndTask();
215 break;
216 case ID_APPLICATION_PAGE_GOTOPROCESS:
217 ApplicationPage_OnGotoProcess();
218 break;
219 case ID_PROCESS_PAGE_ENDPROCESS:
220 ProcessPage_OnEndProcess();
221 break;
222 case ID_PROCESS_PAGE_ENDPROCESSTREE:
223 ProcessPage_OnEndProcessTree();
224 break;
225 case ID_PROCESS_PAGE_DEBUG:
226 ProcessPage_OnDebug();
227 break;
228 case ID_PROCESS_PAGE_SETAFFINITY:
229 ProcessPage_OnSetAffinity();
230 break;
231 case ID_PROCESS_PAGE_SETPRIORITY_REALTIME:
232 DoSetPriority(REALTIME_PRIORITY_CLASS);
233 break;
234 case ID_PROCESS_PAGE_SETPRIORITY_HIGH:
235 DoSetPriority(HIGH_PRIORITY_CLASS);
236 break;
237 case ID_PROCESS_PAGE_SETPRIORITY_ABOVENORMAL:
238 DoSetPriority(ABOVE_NORMAL_PRIORITY_CLASS);
239 break;
240 case ID_PROCESS_PAGE_SETPRIORITY_NORMAL:
241 DoSetPriority(NORMAL_PRIORITY_CLASS);
242 break;
243 case ID_PROCESS_PAGE_SETPRIORITY_BELOWNORMAL:
244 DoSetPriority(BELOW_NORMAL_PRIORITY_CLASS);
245 break;
246 case ID_PROCESS_PAGE_SETPRIORITY_LOW:
247 DoSetPriority(IDLE_PRIORITY_CLASS);
248 break;
249 case ID_PROCESS_PAGE_DEBUGCHANNELS:
250 ProcessPage_OnDebugChannels();
251 break;
252 case ID_HELP_ABOUT:
253 OnAbout();
254 break;
255 case ID_FILE_EXIT:
256 EndDialog(hDlg, IDOK);
257 break;
258 }
259 break;
260
261 case WM_ONTRAYICON:
262 switch(lParam)
263 {
264 case WM_RBUTTONDOWN:
265 {
266 POINT pt;
267 BOOL OnTop;
268 HMENU hMenu, hPopupMenu;
269
270 GetCursorPos(&pt);
271
272 OnTop = ((GetWindowLongPtrW(hMainWnd, GWL_EXSTYLE) & WS_EX_TOPMOST) != 0);
273
274 hMenu = LoadMenuW(hInst, MAKEINTRESOURCEW(IDR_TRAY_POPUP));
275 hPopupMenu = GetSubMenu(hMenu, 0);
276
277 if(IsWindowVisible(hMainWnd))
278 {
279 DeleteMenu(hPopupMenu, ID_RESTORE, MF_BYCOMMAND);
280 }
281 else
282 {
283 SetMenuDefaultItem(hPopupMenu, ID_RESTORE, FALSE);
284 }
285
286 if(OnTop)
287 {
288 CheckMenuItem(hPopupMenu, ID_OPTIONS_ALWAYSONTOP, MF_BYCOMMAND | MF_CHECKED);
289 } else
290 {
291 CheckMenuItem(hPopupMenu, ID_OPTIONS_ALWAYSONTOP, MF_BYCOMMAND | MF_UNCHECKED);
292 }
293
294 SetForegroundWindow(hMainWnd);
295 TrackPopupMenuEx(hPopupMenu, 0, pt.x, pt.y, hMainWnd, NULL);
296
297 DestroyMenu(hMenu);
298 break;
299 }
300 case WM_LBUTTONDBLCLK:
301 TaskManager_OnRestoreMainWindow();
302 break;
303 }
304 break;
305
306 case WM_NOTIFY:
307 idctrl = (int)wParam;
308 pnmh = (LPNMHDR)lParam;
309 if ((pnmh->hwndFrom == hTabWnd) &&
310 (pnmh->idFrom == IDC_TAB) &&
311 (pnmh->code == TCN_SELCHANGE))
312 {
313 TaskManager_OnTabWndSelChange();
314 }
315 break;
316 #if 0
317 case WM_NCPAINT:
318 hdc = GetDC(hDlg);
319 GetClientRect(hDlg, &rc);
320 Draw3dRect(hdc, rc.left, rc.top, rc.right, rc.top + 2, GetSysColor(COLOR_3DSHADOW), GetSysColor(COLOR_3DHILIGHT));
321 ReleaseDC(hDlg, hdc);
322 break;
323
324 case WM_PAINT:
325 hdc = BeginPaint(hDlg, &ps);
326 GetClientRect(hDlg, &rc);
327 Draw3dRect(hdc, rc.left, rc.top, rc.right, rc.top + 2, GetSysColor(COLOR_3DSHADOW), GetSysColor(COLOR_3DHILIGHT));
328 EndPaint(hDlg, &ps);
329 break;
330 #endif
331 case WM_SIZING:
332 /* Make sure the user is sizing the dialog */
333 /* in an acceptable range */
334 pRC = (LPRECT)lParam;
335 if ((wParam == WMSZ_LEFT) || (wParam == WMSZ_TOPLEFT) || (wParam == WMSZ_BOTTOMLEFT)) {
336 /* If the width is too small enlarge it to the minimum */
337 if (nMinimumWidth > (pRC->right - pRC->left))
338 pRC->left = pRC->right - nMinimumWidth;
339 } else {
340 /* If the width is too small enlarge it to the minimum */
341 if (nMinimumWidth > (pRC->right - pRC->left))
342 pRC->right = pRC->left + nMinimumWidth;
343 }
344 if ((wParam == WMSZ_TOP) || (wParam == WMSZ_TOPLEFT) || (wParam == WMSZ_TOPRIGHT)) {
345 /* If the height is too small enlarge it to the minimum */
346 if (nMinimumHeight > (pRC->bottom - pRC->top))
347 pRC->top = pRC->bottom - nMinimumHeight;
348 } else {
349 /* If the height is too small enlarge it to the minimum */
350 if (nMinimumHeight > (pRC->bottom - pRC->top))
351 pRC->bottom = pRC->top + nMinimumHeight;
352 }
353 return TRUE;
354 break;
355
356 case WM_SIZE:
357 /* Handle the window sizing in it's own function */
358 OnSize(wParam, LOWORD(lParam), HIWORD(lParam));
359 break;
360
361 case WM_MOVE:
362 /* Handle the window moving in it's own function */
363 OnMove(wParam, LOWORD(lParam), HIWORD(lParam));
364 break;
365
366 case WM_DESTROY:
367 ShowWindow(hDlg, SW_HIDE);
368 TrayIcon_ShellRemoveTrayIcon();
369 wp.length = sizeof(WINDOWPLACEMENT);
370 GetWindowPlacement(hDlg, &wp);
371 TaskManagerSettings.Left = wp.rcNormalPosition.left;
372 TaskManagerSettings.Top = wp.rcNormalPosition.top;
373 TaskManagerSettings.Right = wp.rcNormalPosition.right;
374 TaskManagerSettings.Bottom = wp.rcNormalPosition.bottom;
375 if (IsZoomed(hDlg) || (wp.flags & WPF_RESTORETOMAXIMIZED))
376 TaskManagerSettings.Maximized = TRUE;
377 else
378 TaskManagerSettings.Maximized = FALSE;
379 return DefWindowProcW(hDlg, message, wParam, lParam);
380
381 case WM_TIMER:
382 /* Refresh the performance data */
383 PerfDataRefresh();
384 RefreshApplicationPage();
385 RefreshProcessPage();
386 RefreshPerformancePage();
387 TrayIcon_ShellUpdateTrayIcon();
388 break;
389
390 case WM_ENTERMENULOOP:
391 TaskManager_OnEnterMenuLoop(hDlg);
392 break;
393 case WM_EXITMENULOOP:
394 TaskManager_OnExitMenuLoop(hDlg);
395 break;
396 case WM_MENUSELECT:
397 TaskManager_OnMenuSelect(hDlg, LOWORD(wParam), HIWORD(wParam), (HMENU)lParam);
398 break;
399 case WM_SYSCOLORCHANGE:
400 /* Forward WM_SYSCOLORCHANGE to common controls */
401 SendMessage(hApplicationPageListCtrl, WM_SYSCOLORCHANGE, 0, 0);
402 SendMessage(hProcessPageListCtrl, WM_SYSCOLORCHANGE, 0, 0);
403 SendMessage(hProcessPageHeaderCtrl, WM_SYSCOLORCHANGE, 0, 0);
404 break;
405 }
406
407 return 0;
408 }
409
410 void FillSolidRect(HDC hDC, LPCRECT lpRect, COLORREF clr)
411 {
412 SetBkColor(hDC, clr);
413 ExtTextOutW(hDC, 0, 0, ETO_OPAQUE, lpRect, NULL, 0, NULL);
414 }
415
416 void FillSolidRect2(HDC hDC, int x, int y, int cx, int cy, COLORREF clr)
417 {
418 RECT rect;
419
420 SetBkColor(hDC, clr);
421 rect.left = x;
422 rect.top = y;
423 rect.right = x + cx;
424 rect.bottom = y + cy;
425 ExtTextOutW(hDC, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);
426 }
427
428 void Draw3dRect(HDC hDC, int x, int y, int cx, int cy, COLORREF clrTopLeft, COLORREF clrBottomRight)
429 {
430 FillSolidRect2(hDC, x, y, cx - 1, 1, clrTopLeft);
431 FillSolidRect2(hDC, x, y, 1, cy - 1, clrTopLeft);
432 FillSolidRect2(hDC, x + cx, y, -1, cy, clrBottomRight);
433 FillSolidRect2(hDC, x, y + cy, cx, -1, clrBottomRight);
434 }
435
436 void Draw3dRect2(HDC hDC, LPRECT lpRect, COLORREF clrTopLeft, COLORREF clrBottomRight)
437 {
438 Draw3dRect(hDC, lpRect->left, lpRect->top, lpRect->right - lpRect->left,
439 lpRect->bottom - lpRect->top, clrTopLeft, clrBottomRight);
440 }
441
442 static void SetUpdateSpeed(HWND hWnd)
443 {
444 /* Setup update speed (pause=fall down) */
445 switch (TaskManagerSettings.UpdateSpeed) {
446 case ID_VIEW_UPDATESPEED_HIGH:
447 SetTimer(hWnd, 1, 1000, NULL);
448 break;
449 case ID_VIEW_UPDATESPEED_NORMAL:
450 SetTimer(hWnd, 1, 2000, NULL);
451 break;
452 case ID_VIEW_UPDATESPEED_LOW:
453 SetTimer(hWnd, 1, 4000, NULL);
454 break;
455 }
456 }
457
458 BOOL OnCreate(HWND hWnd)
459 {
460 HMENU hMenu;
461 HMENU hEditMenu;
462 HMENU hViewMenu;
463 HMENU hUpdateSpeedMenu;
464 HMENU hCPUHistoryMenu;
465 int nActivePage;
466 int nParts[3];
467 RECT rc;
468 WCHAR szTemp[256];
469 TCITEM item;
470
471 SendMessageW(hMainWnd, WM_SETICON, ICON_BIG, (LPARAM)LoadIconW(hInst, MAKEINTRESOURCEW(IDI_TASKMANAGER)));
472
473 /* Initialize the Windows Common Controls DLL */
474 InitCommonControls();
475
476 /* Get the minimum window sizes */
477 GetWindowRect(hWnd, &rc);
478 nMinimumWidth = (rc.right - rc.left);
479 nMinimumHeight = (rc.bottom - rc.top);
480
481 /* Create the status bar */
482 hStatusWnd = CreateStatusWindow(WS_VISIBLE|WS_CHILD|WS_CLIPSIBLINGS|SBT_NOBORDERS, L"", hWnd, STATUS_WINDOW);
483 if(!hStatusWnd)
484 return FALSE;
485
486 /* Create the status bar panes */
487 nParts[0] = STATUS_SIZE1;
488 nParts[1] = STATUS_SIZE2;
489 nParts[2] = STATUS_SIZE3;
490 SendMessageW(hStatusWnd, SB_SETPARTS, 3, (LPARAM) (LPINT) nParts);
491
492 /* Create tab pages */
493 hTabWnd = GetDlgItem(hWnd, IDC_TAB);
494 #if 1
495 hApplicationPage = CreateDialogW(hInst, MAKEINTRESOURCEW(IDD_APPLICATION_PAGE), hWnd, ApplicationPageWndProc);
496 hProcessPage = CreateDialogW(hInst, MAKEINTRESOURCEW(IDD_PROCESS_PAGE), hWnd, ProcessPageWndProc);
497 hPerformancePage = CreateDialogW(hInst, MAKEINTRESOURCEW(IDD_PERFORMANCE_PAGE), hWnd, PerformancePageWndProc);
498 #else
499 hApplicationPage = CreateDialogW(hInst, MAKEINTRESOURCEW(IDD_APPLICATION_PAGE), hTabWnd, ApplicationPageWndProc);
500 hProcessPage = CreateDialogW(hInst, MAKEINTRESOURCEW(IDD_PROCESS_PAGE), hTabWnd, ProcessPageWndProc);
501 hPerformancePage = CreateDialogW(hInst, MAKEINTRESOURCEW(IDD_PERFORMANCE_PAGE), hTabWnd, PerformancePageWndProc);
502 #endif
503
504 /* Insert tabs */
505 LoadStringW(hInst, IDS_TAB_APPS, szTemp, 256);
506 memset(&item, 0, sizeof(TCITEM));
507 item.mask = TCIF_TEXT;
508 item.pszText = szTemp;
509 (void)TabCtrl_InsertItem(hTabWnd, 0, &item);
510 LoadStringW(hInst, IDS_TAB_PROCESSES, szTemp, 256);
511 memset(&item, 0, sizeof(TCITEM));
512 item.mask = TCIF_TEXT;
513 item.pszText = szTemp;
514 (void)TabCtrl_InsertItem(hTabWnd, 1, &item);
515 LoadStringW(hInst, IDS_TAB_PERFORMANCE, szTemp, 256);
516 memset(&item, 0, sizeof(TCITEM));
517 item.mask = TCIF_TEXT;
518 item.pszText = szTemp;
519 (void)TabCtrl_InsertItem(hTabWnd, 2, &item);
520
521 /* Size everything correctly */
522 GetClientRect(hWnd, &rc);
523 nOldWidth = rc.right;
524 nOldHeight = rc.bottom;
525 /* nOldStartX = rc.left; */
526 /*nOldStartY = rc.top; */
527
528 #define PAGE_OFFSET_LEFT 17
529 #define PAGE_OFFSET_TOP 72
530 #define PAGE_OFFSET_WIDTH (PAGE_OFFSET_LEFT*2)
531 #define PAGE_OFFSET_HEIGHT (PAGE_OFFSET_TOP+32)
532
533 if ((TaskManagerSettings.Left != 0) ||
534 (TaskManagerSettings.Top != 0) ||
535 (TaskManagerSettings.Right != 0) ||
536 (TaskManagerSettings.Bottom != 0))
537 {
538 MoveWindow(hWnd, TaskManagerSettings.Left, TaskManagerSettings.Top, TaskManagerSettings.Right - TaskManagerSettings.Left, TaskManagerSettings.Bottom - TaskManagerSettings.Top, TRUE);
539 #ifdef __GNUC__TEST__
540 MoveWindow(hApplicationPage, TaskManagerSettings.Left + PAGE_OFFSET_LEFT, TaskManagerSettings.Top + PAGE_OFFSET_TOP, TaskManagerSettings.Right - TaskManagerSettings.Left - PAGE_OFFSET_WIDTH, TaskManagerSettings.Bottom - TaskManagerSettings.Top - PAGE_OFFSET_HEIGHT, FALSE);
541 MoveWindow(hProcessPage, TaskManagerSettings.Left + PAGE_OFFSET_LEFT, TaskManagerSettings.Top + PAGE_OFFSET_TOP, TaskManagerSettings.Right - TaskManagerSettings.Left - PAGE_OFFSET_WIDTH, TaskManagerSettings.Bottom - TaskManagerSettings.Top - PAGE_OFFSET_HEIGHT, FALSE);
542 MoveWindow(hPerformancePage, TaskManagerSettings.Left + PAGE_OFFSET_LEFT, TaskManagerSettings.Top + PAGE_OFFSET_TOP, TaskManagerSettings.Right - TaskManagerSettings.Left - PAGE_OFFSET_WIDTH, TaskManagerSettings.Bottom - TaskManagerSettings.Top - PAGE_OFFSET_HEIGHT, FALSE);
543 #endif
544 }
545 if (TaskManagerSettings.Maximized)
546 ShowWindow(hWnd, SW_MAXIMIZE);
547
548 /* Set the always on top style */
549 hMenu = GetMenu(hWnd);
550 hEditMenu = GetSubMenu(hMenu, 1);
551 hViewMenu = GetSubMenu(hMenu, 2);
552 hUpdateSpeedMenu = GetSubMenu(hViewMenu, 1);
553 hCPUHistoryMenu = GetSubMenu(hViewMenu, 7);
554
555 /* Check or uncheck the always on top menu item */
556 if (TaskManagerSettings.AlwaysOnTop) {
557 CheckMenuItem(hEditMenu, ID_OPTIONS_ALWAYSONTOP, MF_BYCOMMAND|MF_CHECKED);
558 SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
559 } else {
560 CheckMenuItem(hEditMenu, ID_OPTIONS_ALWAYSONTOP, MF_BYCOMMAND|MF_UNCHECKED);
561 SetWindowPos(hWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
562 }
563
564 /* Check or uncheck the minimize on use menu item */
565 if (TaskManagerSettings.MinimizeOnUse)
566 CheckMenuItem(hEditMenu, ID_OPTIONS_MINIMIZEONUSE, MF_BYCOMMAND|MF_CHECKED);
567 else
568 CheckMenuItem(hEditMenu, ID_OPTIONS_MINIMIZEONUSE, MF_BYCOMMAND|MF_UNCHECKED);
569
570 /* Check or uncheck the hide when minimized menu item */
571 if (TaskManagerSettings.HideWhenMinimized)
572 CheckMenuItem(hEditMenu, ID_OPTIONS_HIDEWHENMINIMIZED, MF_BYCOMMAND|MF_CHECKED);
573 else
574 CheckMenuItem(hEditMenu, ID_OPTIONS_HIDEWHENMINIMIZED, MF_BYCOMMAND|MF_UNCHECKED);
575
576 /* Check or uncheck the show 16-bit tasks menu item */
577 if (TaskManagerSettings.Show16BitTasks)
578 CheckMenuItem(hEditMenu, ID_OPTIONS_SHOW16BITTASKS, MF_BYCOMMAND|MF_CHECKED);
579 else
580 CheckMenuItem(hEditMenu, ID_OPTIONS_SHOW16BITTASKS, MF_BYCOMMAND|MF_UNCHECKED);
581
582 /* Set the view mode */
583 CheckMenuRadioItem(hViewMenu, ID_VIEW_LARGE, ID_VIEW_DETAILS, TaskManagerSettings.ViewMode, MF_BYCOMMAND);
584
585 if (TaskManagerSettings.ShowKernelTimes)
586 CheckMenuItem(hViewMenu, ID_VIEW_SHOWKERNELTIMES, MF_BYCOMMAND|MF_CHECKED);
587 else
588 CheckMenuItem(hViewMenu, ID_VIEW_SHOWKERNELTIMES, MF_BYCOMMAND|MF_UNCHECKED);
589
590 CheckMenuRadioItem(hUpdateSpeedMenu, ID_VIEW_UPDATESPEED_HIGH, ID_VIEW_UPDATESPEED_PAUSED, TaskManagerSettings.UpdateSpeed, MF_BYCOMMAND);
591
592 if (TaskManagerSettings.CPUHistory_OneGraphPerCPU)
593 CheckMenuRadioItem(hCPUHistoryMenu, ID_VIEW_CPUHISTORY_ONEGRAPHALL, ID_VIEW_CPUHISTORY_ONEGRAPHPERCPU, ID_VIEW_CPUHISTORY_ONEGRAPHPERCPU, MF_BYCOMMAND);
594 else
595 CheckMenuRadioItem(hCPUHistoryMenu, ID_VIEW_CPUHISTORY_ONEGRAPHALL, ID_VIEW_CPUHISTORY_ONEGRAPHPERCPU, ID_VIEW_CPUHISTORY_ONEGRAPHALL, MF_BYCOMMAND);
596
597 nActivePage = TaskManagerSettings.ActiveTabPage;
598 TabCtrl_SetCurFocus/*Sel*/(hTabWnd, 0);
599 TabCtrl_SetCurFocus/*Sel*/(hTabWnd, 1);
600 TabCtrl_SetCurFocus/*Sel*/(hTabWnd, 2);
601 TabCtrl_SetCurFocus/*Sel*/(hTabWnd, nActivePage);
602
603 /* Setup update speed */
604 SetUpdateSpeed(hWnd);
605
606 /*
607 * Refresh the performance data
608 * Sample it twice so we can establish
609 * the delta values & cpu usage
610 */
611 PerfDataRefresh();
612 PerfDataRefresh();
613
614 RefreshApplicationPage();
615 RefreshProcessPage();
616 RefreshPerformancePage();
617
618 TrayIcon_ShellAddTrayIcon();
619
620 return TRUE;
621 }
622
623 /* OnMove()
624 * This function handles all the moving events for the application
625 * It moves every child window that needs moving
626 */
627 void OnMove( WPARAM nType, int cx, int cy )
628 {
629 #ifdef __GNUC__TEST__
630 MoveWindow(hApplicationPage, TaskManagerSettings.Left + PAGE_OFFSET_LEFT, TaskManagerSettings.Top + PAGE_OFFSET_TOP, TaskManagerSettings.Right - TaskManagerSettings.Left - PAGE_OFFSET_WIDTH, TaskManagerSettings.Bottom - TaskManagerSettings.Top - PAGE_OFFSET_HEIGHT, FALSE);
631 MoveWindow(hProcessPage, TaskManagerSettings.Left + PAGE_OFFSET_LEFT, TaskManagerSettings.Top + PAGE_OFFSET_TOP, TaskManagerSettings.Right - TaskManagerSettings.Left - PAGE_OFFSET_WIDTH, TaskManagerSettings.Bottom - TaskManagerSettings.Top - PAGE_OFFSET_HEIGHT, FALSE);
632 MoveWindow(hPerformancePage, TaskManagerSettings.Left + PAGE_OFFSET_LEFT, TaskManagerSettings.Top + PAGE_OFFSET_TOP, TaskManagerSettings.Right - TaskManagerSettings.Left - PAGE_OFFSET_WIDTH, TaskManagerSettings.Bottom - TaskManagerSettings.Top - PAGE_OFFSET_HEIGHT, FALSE);
633 #endif
634 }
635
636 /* OnSize()
637 * This function handles all the sizing events for the application
638 * It re-sizes every window, and child window that needs re-sizing
639 */
640 void OnSize( WPARAM nType, int cx, int cy )
641 {
642 int nParts[3];
643 int nXDifference;
644 int nYDifference;
645 RECT rc;
646
647 if (nType == SIZE_MINIMIZED)
648 {
649 if(TaskManagerSettings.HideWhenMinimized)
650 {
651 ShowWindow(hMainWnd, SW_HIDE);
652 }
653 return;
654 }
655
656 nXDifference = cx - nOldWidth;
657 nYDifference = cy - nOldHeight;
658 nOldWidth = cx;
659 nOldHeight = cy;
660
661 /* Update the status bar size */
662 GetWindowRect(hStatusWnd, &rc);
663 SendMessageW(hStatusWnd, WM_SIZE, nType, MAKELPARAM(cx,rc.bottom - rc.top));
664
665 /* Update the status bar pane sizes */
666 nParts[0] = bInMenuLoop ? -1 : STATUS_SIZE1;
667 nParts[1] = STATUS_SIZE2;
668 nParts[2] = cx;
669 SendMessageW(hStatusWnd, SB_SETPARTS, bInMenuLoop ? 1 : 3, (LPARAM) (LPINT) nParts);
670
671 /* Resize the tab control */
672 GetWindowRect(hTabWnd, &rc);
673 cx = (rc.right - rc.left) + nXDifference;
674 cy = (rc.bottom - rc.top) + nYDifference;
675 SetWindowPos(hTabWnd, NULL, 0, 0, cx, cy, SWP_NOACTIVATE|SWP_NOOWNERZORDER|SWP_NOMOVE|SWP_NOZORDER);
676
677 /* Resize the application page */
678 GetWindowRect(hApplicationPage, &rc);
679 cx = (rc.right - rc.left) + nXDifference;
680 cy = (rc.bottom - rc.top) + nYDifference;
681 SetWindowPos(hApplicationPage, NULL, 0, 0, cx, cy, SWP_NOACTIVATE|SWP_NOOWNERZORDER|SWP_NOMOVE|SWP_NOZORDER);
682
683 /* Resize the process page */
684 GetWindowRect(hProcessPage, &rc);
685 cx = (rc.right - rc.left) + nXDifference;
686 cy = (rc.bottom - rc.top) + nYDifference;
687 SetWindowPos(hProcessPage, NULL, 0, 0, cx, cy, SWP_NOACTIVATE|SWP_NOOWNERZORDER|SWP_NOMOVE|SWP_NOZORDER);
688
689 /* Resize the performance page */
690 GetWindowRect(hPerformancePage, &rc);
691 cx = (rc.right - rc.left) + nXDifference;
692 cy = (rc.bottom - rc.top) + nYDifference;
693 SetWindowPos(hPerformancePage, NULL, 0, 0, cx, cy, SWP_NOACTIVATE|SWP_NOOWNERZORDER|SWP_NOMOVE|SWP_NOZORDER);
694 }
695
696 void LoadSettings(void)
697 {
698 HKEY hKey;
699 WCHAR szSubKey[] = L"Software\\ReactOS\\TaskManager";
700 int i;
701 DWORD dwSize;
702
703 /* Window size & position settings */
704 TaskManagerSettings.Maximized = FALSE;
705 TaskManagerSettings.Left = 0;
706 TaskManagerSettings.Top = 0;
707 TaskManagerSettings.Right = 0;
708 TaskManagerSettings.Bottom = 0;
709
710 /* Tab settings */
711 TaskManagerSettings.ActiveTabPage = 0;
712
713 /* Options menu settings */
714 TaskManagerSettings.AlwaysOnTop = FALSE;
715 TaskManagerSettings.MinimizeOnUse = TRUE;
716 TaskManagerSettings.HideWhenMinimized = TRUE;
717 TaskManagerSettings.Show16BitTasks = TRUE;
718
719 /* Update speed settings */
720 TaskManagerSettings.UpdateSpeed = ID_VIEW_UPDATESPEED_NORMAL;
721
722 /* Applications page settings */
723 TaskManagerSettings.ViewMode = ID_VIEW_DETAILS;
724
725 /* Processes page settings */
726 TaskManagerSettings.ShowProcessesFromAllUsers = FALSE; /* Server-only? */
727
728 for (i = 0; i < COLUMN_NMAX; i++) {
729 TaskManagerSettings.Columns[i] = ColumnPresets[i].bDefaults;
730 TaskManagerSettings.ColumnOrderArray[i] = i;
731 TaskManagerSettings.ColumnSizeArray[i] = ColumnPresets[i].size;
732 }
733
734 TaskManagerSettings.SortColumn = COLUMN_IMAGENAME;
735 TaskManagerSettings.SortAscending = TRUE;
736
737 /* Performance page settings */
738 TaskManagerSettings.CPUHistory_OneGraphPerCPU = TRUE;
739 TaskManagerSettings.ShowKernelTimes = FALSE;
740
741 /* Open the key */
742 if (RegOpenKeyExW(HKEY_CURRENT_USER, szSubKey, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
743 return;
744 /* Read the settings */
745 dwSize = sizeof(TASKMANAGER_SETTINGS);
746 RegQueryValueExW(hKey, L"Preferences", NULL, NULL, (LPBYTE)&TaskManagerSettings, &dwSize);
747
748 /*
749 * ATM, the 'ImageName' column is always visible
750 * (and grayed in configuration dialog)
751 * This will avoid troubles if the registry gets corrupted.
752 */
753 TaskManagerSettings.Column_ImageName = TRUE;
754
755 /* Close the key */
756 RegCloseKey(hKey);
757 }
758
759 void SaveSettings(void)
760 {
761 HKEY hKey;
762 WCHAR szSubKey1[] = L"Software";
763 WCHAR szSubKey2[] = L"Software\\ReactOS";
764 WCHAR szSubKey3[] = L"Software\\ReactOS\\TaskManager";
765
766 /* Open (or create) the key */
767 hKey = NULL;
768 RegCreateKeyExW(HKEY_CURRENT_USER, szSubKey1, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, NULL);
769 RegCloseKey(hKey);
770 hKey = NULL;
771 RegCreateKeyExW(HKEY_CURRENT_USER, szSubKey2, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, NULL);
772 RegCloseKey(hKey);
773 hKey = NULL;
774 if (RegCreateKeyExW(HKEY_CURRENT_USER, szSubKey3, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, NULL) != ERROR_SUCCESS)
775 return;
776 /* Save the settings */
777 RegSetValueExW(hKey, L"Preferences", 0, REG_BINARY, (LPBYTE)&TaskManagerSettings, sizeof(TASKMANAGER_SETTINGS));
778 /* Close the key */
779 RegCloseKey(hKey);
780 }
781
782 void TaskManager_OnRestoreMainWindow(void)
783 {
784 HMENU hMenu, hOptionsMenu;
785 BOOL OnTop;
786
787 hMenu = GetMenu(hMainWnd);
788 hOptionsMenu = GetSubMenu(hMenu, OPTIONS_MENU_INDEX);
789 OnTop = ((GetWindowLongPtrW(hMainWnd, GWL_EXSTYLE) & WS_EX_TOPMOST) != 0);
790
791 OpenIcon(hMainWnd);
792 SetForegroundWindow(hMainWnd);
793 SetWindowPos(hMainWnd, (OnTop ? HWND_TOPMOST : HWND_TOP), 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW);
794 }
795
796 void TaskManager_OnEnterMenuLoop(HWND hWnd)
797 {
798 int nParts;
799
800 /* Update the status bar pane sizes */
801 nParts = -1;
802 SendMessageW(hStatusWnd, SB_SETPARTS, 1, (LPARAM) (LPINT)&nParts);
803 bInMenuLoop = TRUE;
804 SendMessageW(hStatusWnd, SB_SETTEXT, (WPARAM)0, (LPARAM)L"");
805 }
806
807 void TaskManager_OnExitMenuLoop(HWND hWnd)
808 {
809 RECT rc;
810 int nParts[3];
811 WCHAR text[260];
812 WCHAR szCpuUsage[256], szProcesses[256];
813
814 LoadStringW(hInst, IDS_STATUS_CPUUSAGE, szCpuUsage, 256);
815 LoadStringW(hInst, IDS_STATUS_PROCESSES, szProcesses, 256);
816
817 bInMenuLoop = FALSE;
818 /* Update the status bar pane sizes */
819 GetClientRect(hWnd, &rc);
820 nParts[0] = STATUS_SIZE1;
821 nParts[1] = STATUS_SIZE2;
822 nParts[2] = rc.right;
823 SendMessageW(hStatusWnd, SB_SETPARTS, 3, (LPARAM) (LPINT) nParts);
824 SendMessageW(hStatusWnd, SB_SETTEXT, 0, (LPARAM)L"");
825 wsprintfW(text, szCpuUsage, PerfDataGetProcessorUsage());
826 SendMessageW(hStatusWnd, SB_SETTEXT, 1, (LPARAM)text);
827 wsprintfW(text, szProcesses, PerfDataGetProcessCount());
828 SendMessageW(hStatusWnd, SB_SETTEXT, 0, (LPARAM)text);
829 }
830
831 void TaskManager_OnMenuSelect(HWND hWnd, UINT nItemID, UINT nFlags, HMENU hSysMenu)
832 {
833 WCHAR str[100];
834
835 wcscpy(str, L"");
836 if (LoadStringW(hInst, nItemID, str, 100)) {
837 /* load appropriate string */
838 LPWSTR lpsz = str;
839 /* first newline terminates actual string */
840 lpsz = wcschr(lpsz, '\n');
841 if (lpsz != NULL)
842 *lpsz = '\0';
843 }
844 SendMessageW(hStatusWnd, SB_SETTEXT, 0, (LPARAM)str);
845 }
846
847 void TaskManager_OnViewUpdateSpeed(DWORD dwSpeed)
848 {
849 HMENU hMenu;
850 HMENU hViewMenu;
851 HMENU hUpdateSpeedMenu;
852
853 hMenu = GetMenu(hMainWnd);
854 hViewMenu = GetSubMenu(hMenu, 2);
855 hUpdateSpeedMenu = GetSubMenu(hViewMenu, 1);
856
857 TaskManagerSettings.UpdateSpeed = dwSpeed;
858 CheckMenuRadioItem(hUpdateSpeedMenu, ID_VIEW_UPDATESPEED_HIGH, ID_VIEW_UPDATESPEED_PAUSED, dwSpeed, MF_BYCOMMAND);
859
860 KillTimer(hMainWnd, 1);
861
862 SetUpdateSpeed(hMainWnd);
863 }
864
865 void TaskManager_OnTabWndSelChange(void)
866 {
867 int i;
868 HMENU hMenu;
869 HMENU hOptionsMenu;
870 HMENU hViewMenu;
871 HMENU hSubMenu;
872 WCHAR szTemp[256];
873 SYSTEM_INFO sysInfo;
874
875 hMenu = GetMenu(hMainWnd);
876 hViewMenu = GetSubMenu(hMenu, 2);
877 hOptionsMenu = GetSubMenu(hMenu, 1);
878 TaskManagerSettings.ActiveTabPage = TabCtrl_GetCurSel(hTabWnd);
879 for (i = GetMenuItemCount(hViewMenu) - 1; i > 2; i--) {
880 hSubMenu = GetSubMenu(hViewMenu, i);
881 if (hSubMenu)
882 DestroyMenu(hSubMenu);
883 RemoveMenu(hViewMenu, i, MF_BYPOSITION);
884 }
885 RemoveMenu(hOptionsMenu, 3, MF_BYPOSITION);
886 switch (TaskManagerSettings.ActiveTabPage) {
887 case 0:
888 ShowWindow(hApplicationPage, SW_SHOW);
889 ShowWindow(hProcessPage, SW_HIDE);
890 ShowWindow(hPerformancePage, SW_HIDE);
891 BringWindowToTop(hApplicationPage);
892
893 LoadStringW(hInst, IDS_MENU_LARGEICONS, szTemp, 256);
894 AppendMenuW(hViewMenu, MF_STRING, ID_VIEW_LARGE, szTemp);
895
896 LoadStringW(hInst, IDS_MENU_SMALLICONS, szTemp, 256);
897 AppendMenuW(hViewMenu, MF_STRING, ID_VIEW_SMALL, szTemp);
898
899 LoadStringW(hInst, IDS_MENU_DETAILS, szTemp, 256);
900 AppendMenuW(hViewMenu, MF_STRING, ID_VIEW_DETAILS, szTemp);
901
902 if (GetMenuItemCount(hMenu) <= 4) {
903 hSubMenu = LoadMenuW(hInst, MAKEINTRESOURCEW(IDR_WINDOWSMENU));
904
905 LoadStringW(hInst, IDS_MENU_WINDOWS, szTemp, 256);
906 InsertMenuW(hMenu, 3, MF_BYPOSITION|MF_POPUP, (UINT_PTR) hSubMenu, szTemp);
907
908 DrawMenuBar(hMainWnd);
909 }
910 CheckMenuRadioItem(hViewMenu, ID_VIEW_LARGE, ID_VIEW_DETAILS, TaskManagerSettings.ViewMode, MF_BYCOMMAND);
911
912 /*
913 * Give the application list control focus
914 */
915 SetFocus(hApplicationPageListCtrl);
916 break;
917
918 case 1:
919 ShowWindow(hApplicationPage, SW_HIDE);
920 ShowWindow(hProcessPage, SW_SHOW);
921 ShowWindow(hPerformancePage, SW_HIDE);
922 BringWindowToTop(hProcessPage);
923
924 LoadStringW(hInst, IDS_MENU_SELECTCOLUMNS, szTemp, 256);
925 AppendMenuW(hViewMenu, MF_STRING, ID_VIEW_SELECTCOLUMNS, szTemp);
926
927 LoadStringW(hInst, IDS_MENU_16BITTASK, szTemp, 256);
928 AppendMenuW(hOptionsMenu, MF_STRING, ID_OPTIONS_SHOW16BITTASKS, szTemp);
929
930 if (TaskManagerSettings.Show16BitTasks)
931 CheckMenuItem(hOptionsMenu, ID_OPTIONS_SHOW16BITTASKS, MF_BYCOMMAND|MF_CHECKED);
932 if (GetMenuItemCount(hMenu) > 4)
933 {
934 DeleteMenu(hMenu, 3, MF_BYPOSITION);
935 DrawMenuBar(hMainWnd);
936 }
937 /*
938 * Give the process list control focus
939 */
940 SetFocus(hProcessPageListCtrl);
941 break;
942
943 case 2:
944 ShowWindow(hApplicationPage, SW_HIDE);
945 ShowWindow(hProcessPage, SW_HIDE);
946 ShowWindow(hPerformancePage, SW_SHOW);
947 BringWindowToTop(hPerformancePage);
948 if (GetMenuItemCount(hMenu) > 4) {
949 DeleteMenu(hMenu, 3, MF_BYPOSITION);
950 DrawMenuBar(hMainWnd);
951 }
952
953 GetSystemInfo(&sysInfo);
954
955 /* Hide CPU graph options on single CPU systems */
956 if (sysInfo.dwNumberOfProcessors > 1)
957 {
958 hSubMenu = CreatePopupMenu();
959
960 LoadStringW(hInst, IDS_MENU_ONEGRAPHALLCPUS, szTemp, 256);
961 AppendMenuW(hSubMenu, MF_STRING, ID_VIEW_CPUHISTORY_ONEGRAPHALL, szTemp);
962
963 LoadStringW(hInst, IDS_MENU_ONEGRAPHPERCPU, szTemp, 256);
964 AppendMenuW(hSubMenu, MF_STRING, ID_VIEW_CPUHISTORY_ONEGRAPHPERCPU, szTemp);
965
966 LoadStringW(hInst, IDS_MENU_CPUHISTORY, szTemp, 256);
967 AppendMenuW(hViewMenu, MF_STRING|MF_POPUP, (UINT_PTR) hSubMenu, szTemp);
968
969 if (TaskManagerSettings.CPUHistory_OneGraphPerCPU)
970 CheckMenuRadioItem(hSubMenu, ID_VIEW_CPUHISTORY_ONEGRAPHALL, ID_VIEW_CPUHISTORY_ONEGRAPHPERCPU, ID_VIEW_CPUHISTORY_ONEGRAPHPERCPU, MF_BYCOMMAND);
971 else
972 CheckMenuRadioItem(hSubMenu, ID_VIEW_CPUHISTORY_ONEGRAPHALL, ID_VIEW_CPUHISTORY_ONEGRAPHPERCPU, ID_VIEW_CPUHISTORY_ONEGRAPHALL, MF_BYCOMMAND);
973 }
974
975 LoadStringW(hInst, IDS_MENU_SHOWKERNELTIMES, szTemp, 256);
976 AppendMenuW(hViewMenu, MF_STRING, ID_VIEW_SHOWKERNELTIMES, szTemp);
977
978 if (TaskManagerSettings.ShowKernelTimes)
979 CheckMenuItem(hViewMenu, ID_VIEW_SHOWKERNELTIMES, MF_BYCOMMAND|MF_CHECKED);
980 else
981 CheckMenuItem(hViewMenu, ID_VIEW_SHOWKERNELTIMES, MF_BYCOMMAND|MF_UNCHECKED);
982
983 /*
984 * Give the tab control focus
985 */
986 SetFocus(hTabWnd);
987 break;
988 }
989 }
990
991 LPWSTR GetLastErrorText(LPWSTR lpszBuf, DWORD dwSize)
992 {
993 DWORD dwRet;
994 LPWSTR lpszTemp = NULL;
995
996 dwRet = FormatMessageW( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |FORMAT_MESSAGE_ARGUMENT_ARRAY,
997 NULL,
998 GetLastError(),
999 LANG_NEUTRAL,
1000 (LPWSTR)&lpszTemp,
1001 0,
1002 NULL );
1003
1004 /* supplied buffer is not long enough */
1005 if (!dwRet || ( (long)dwSize < (long)dwRet+14)) {
1006 lpszBuf[0] = L'\0';
1007 } else {
1008 lpszTemp[lstrlenW(lpszTemp)-2] = L'\0'; /*remove cr and newline character */
1009 wsprintfW(lpszBuf, L"%s (0x%x)", lpszTemp, (int)GetLastError());
1010 }
1011 if (lpszTemp) {
1012 LocalFree((HLOCAL)lpszTemp);
1013 }
1014 return lpszBuf;
1015 }
1016
1017 DWORD EndLocalThread(HANDLE *hThread, DWORD dwThread)
1018 {
1019 DWORD dwExitCodeThread = 0;
1020
1021 if (*hThread != NULL) {
1022 PostThreadMessage(dwThread,WM_QUIT,0,0);
1023 for (;;) {
1024 MSG msg;
1025
1026 if (WAIT_OBJECT_0 == WaitForSingleObject(*hThread, 500))
1027 break;
1028 while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
1029 TranslateMessage(&msg);
1030 DispatchMessage(&msg);
1031 }
1032 }
1033 GetExitCodeThread(*hThread, &dwExitCodeThread);
1034 CloseHandle(*hThread);
1035 *hThread = NULL;
1036 }
1037 return dwExitCodeThread;
1038 }
1039