[CMAKE]
[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 }
400
401 return 0;
402 }
403
404 void FillSolidRect(HDC hDC, LPCRECT lpRect, COLORREF clr)
405 {
406 SetBkColor(hDC, clr);
407 ExtTextOutW(hDC, 0, 0, ETO_OPAQUE, lpRect, NULL, 0, NULL);
408 }
409
410 void FillSolidRect2(HDC hDC, int x, int y, int cx, int cy, COLORREF clr)
411 {
412 RECT rect;
413
414 SetBkColor(hDC, clr);
415 rect.left = x;
416 rect.top = y;
417 rect.right = x + cx;
418 rect.bottom = y + cy;
419 ExtTextOutW(hDC, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);
420 }
421
422 void Draw3dRect(HDC hDC, int x, int y, int cx, int cy, COLORREF clrTopLeft, COLORREF clrBottomRight)
423 {
424 FillSolidRect2(hDC, x, y, cx - 1, 1, clrTopLeft);
425 FillSolidRect2(hDC, x, y, 1, cy - 1, clrTopLeft);
426 FillSolidRect2(hDC, x + cx, y, -1, cy, clrBottomRight);
427 FillSolidRect2(hDC, x, y + cy, cx, -1, clrBottomRight);
428 }
429
430 void Draw3dRect2(HDC hDC, LPRECT lpRect, COLORREF clrTopLeft, COLORREF clrBottomRight)
431 {
432 Draw3dRect(hDC, lpRect->left, lpRect->top, lpRect->right - lpRect->left,
433 lpRect->bottom - lpRect->top, clrTopLeft, clrBottomRight);
434 }
435
436 static void SetUpdateSpeed(HWND hWnd)
437 {
438 /* Setup update speed (pause=fall down) */
439 switch (TaskManagerSettings.UpdateSpeed) {
440 case ID_VIEW_UPDATESPEED_HIGH:
441 SetTimer(hWnd, 1, 1000, NULL);
442 break;
443 case ID_VIEW_UPDATESPEED_NORMAL:
444 SetTimer(hWnd, 1, 2000, NULL);
445 break;
446 case ID_VIEW_UPDATESPEED_LOW:
447 SetTimer(hWnd, 1, 4000, NULL);
448 break;
449 }
450 }
451
452 BOOL OnCreate(HWND hWnd)
453 {
454 HMENU hMenu;
455 HMENU hEditMenu;
456 HMENU hViewMenu;
457 HMENU hUpdateSpeedMenu;
458 HMENU hCPUHistoryMenu;
459 int nActivePage;
460 int nParts[3];
461 RECT rc;
462 WCHAR szTemp[256];
463 TCITEM item;
464
465 SendMessageW(hMainWnd, WM_SETICON, ICON_BIG, (LPARAM)LoadIconW(hInst, MAKEINTRESOURCEW(IDI_TASKMANAGER)));
466
467 /* Initialize the Windows Common Controls DLL */
468 InitCommonControls();
469
470 /* Get the minimum window sizes */
471 GetWindowRect(hWnd, &rc);
472 nMinimumWidth = (rc.right - rc.left);
473 nMinimumHeight = (rc.bottom - rc.top);
474
475 /* Create the status bar */
476 hStatusWnd = CreateStatusWindow(WS_VISIBLE|WS_CHILD|WS_CLIPSIBLINGS|SBT_NOBORDERS, L"", hWnd, STATUS_WINDOW);
477 if(!hStatusWnd)
478 return FALSE;
479
480 /* Create the status bar panes */
481 nParts[0] = STATUS_SIZE1;
482 nParts[1] = STATUS_SIZE2;
483 nParts[2] = STATUS_SIZE3;
484 SendMessageW(hStatusWnd, SB_SETPARTS, 3, (LPARAM) (LPINT) nParts);
485
486 /* Create tab pages */
487 hTabWnd = GetDlgItem(hWnd, IDC_TAB);
488 #if 1
489 hApplicationPage = CreateDialogW(hInst, MAKEINTRESOURCEW(IDD_APPLICATION_PAGE), hWnd, ApplicationPageWndProc);
490 hProcessPage = CreateDialogW(hInst, MAKEINTRESOURCEW(IDD_PROCESS_PAGE), hWnd, ProcessPageWndProc);
491 hPerformancePage = CreateDialogW(hInst, MAKEINTRESOURCEW(IDD_PERFORMANCE_PAGE), hWnd, PerformancePageWndProc);
492 #else
493 hApplicationPage = CreateDialogW(hInst, MAKEINTRESOURCEW(IDD_APPLICATION_PAGE), hTabWnd, ApplicationPageWndProc);
494 hProcessPage = CreateDialogW(hInst, MAKEINTRESOURCEW(IDD_PROCESS_PAGE), hTabWnd, ProcessPageWndProc);
495 hPerformancePage = CreateDialogW(hInst, MAKEINTRESOURCEW(IDD_PERFORMANCE_PAGE), hTabWnd, PerformancePageWndProc);
496 #endif
497
498 /* Insert tabs */
499 LoadStringW(hInst, IDS_TAB_APPS, szTemp, 256);
500 memset(&item, 0, sizeof(TCITEM));
501 item.mask = TCIF_TEXT;
502 item.pszText = szTemp;
503 (void)TabCtrl_InsertItem(hTabWnd, 0, &item);
504 LoadStringW(hInst, IDS_TAB_PROCESSES, szTemp, 256);
505 memset(&item, 0, sizeof(TCITEM));
506 item.mask = TCIF_TEXT;
507 item.pszText = szTemp;
508 (void)TabCtrl_InsertItem(hTabWnd, 1, &item);
509 LoadStringW(hInst, IDS_TAB_PERFORMANCE, szTemp, 256);
510 memset(&item, 0, sizeof(TCITEM));
511 item.mask = TCIF_TEXT;
512 item.pszText = szTemp;
513 (void)TabCtrl_InsertItem(hTabWnd, 2, &item);
514
515 /* Size everything correctly */
516 GetClientRect(hWnd, &rc);
517 nOldWidth = rc.right;
518 nOldHeight = rc.bottom;
519 /* nOldStartX = rc.left; */
520 /*nOldStartY = rc.top; */
521
522 #define PAGE_OFFSET_LEFT 17
523 #define PAGE_OFFSET_TOP 72
524 #define PAGE_OFFSET_WIDTH (PAGE_OFFSET_LEFT*2)
525 #define PAGE_OFFSET_HEIGHT (PAGE_OFFSET_TOP+32)
526
527 if ((TaskManagerSettings.Left != 0) ||
528 (TaskManagerSettings.Top != 0) ||
529 (TaskManagerSettings.Right != 0) ||
530 (TaskManagerSettings.Bottom != 0))
531 {
532 MoveWindow(hWnd, TaskManagerSettings.Left, TaskManagerSettings.Top, TaskManagerSettings.Right - TaskManagerSettings.Left, TaskManagerSettings.Bottom - TaskManagerSettings.Top, TRUE);
533 #ifdef __GNUC__TEST__
534 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);
535 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);
536 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);
537 #endif
538 }
539 if (TaskManagerSettings.Maximized)
540 ShowWindow(hWnd, SW_MAXIMIZE);
541
542 /* Set the always on top style */
543 hMenu = GetMenu(hWnd);
544 hEditMenu = GetSubMenu(hMenu, 1);
545 hViewMenu = GetSubMenu(hMenu, 2);
546 hUpdateSpeedMenu = GetSubMenu(hViewMenu, 1);
547 hCPUHistoryMenu = GetSubMenu(hViewMenu, 7);
548
549 /* Check or uncheck the always on top menu item */
550 if (TaskManagerSettings.AlwaysOnTop) {
551 CheckMenuItem(hEditMenu, ID_OPTIONS_ALWAYSONTOP, MF_BYCOMMAND|MF_CHECKED);
552 SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
553 } else {
554 CheckMenuItem(hEditMenu, ID_OPTIONS_ALWAYSONTOP, MF_BYCOMMAND|MF_UNCHECKED);
555 SetWindowPos(hWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
556 }
557
558 /* Check or uncheck the minimize on use menu item */
559 if (TaskManagerSettings.MinimizeOnUse)
560 CheckMenuItem(hEditMenu, ID_OPTIONS_MINIMIZEONUSE, MF_BYCOMMAND|MF_CHECKED);
561 else
562 CheckMenuItem(hEditMenu, ID_OPTIONS_MINIMIZEONUSE, MF_BYCOMMAND|MF_UNCHECKED);
563
564 /* Check or uncheck the hide when minimized menu item */
565 if (TaskManagerSettings.HideWhenMinimized)
566 CheckMenuItem(hEditMenu, ID_OPTIONS_HIDEWHENMINIMIZED, MF_BYCOMMAND|MF_CHECKED);
567 else
568 CheckMenuItem(hEditMenu, ID_OPTIONS_HIDEWHENMINIMIZED, MF_BYCOMMAND|MF_UNCHECKED);
569
570 /* Check or uncheck the show 16-bit tasks menu item */
571 if (TaskManagerSettings.Show16BitTasks)
572 CheckMenuItem(hEditMenu, ID_OPTIONS_SHOW16BITTASKS, MF_BYCOMMAND|MF_CHECKED);
573 else
574 CheckMenuItem(hEditMenu, ID_OPTIONS_SHOW16BITTASKS, MF_BYCOMMAND|MF_UNCHECKED);
575
576 /* Set the view mode */
577 CheckMenuRadioItem(hViewMenu, ID_VIEW_LARGE, ID_VIEW_DETAILS, TaskManagerSettings.ViewMode, MF_BYCOMMAND);
578
579 if (TaskManagerSettings.ShowKernelTimes)
580 CheckMenuItem(hViewMenu, ID_VIEW_SHOWKERNELTIMES, MF_BYCOMMAND|MF_CHECKED);
581 else
582 CheckMenuItem(hViewMenu, ID_VIEW_SHOWKERNELTIMES, MF_BYCOMMAND|MF_UNCHECKED);
583
584 CheckMenuRadioItem(hUpdateSpeedMenu, ID_VIEW_UPDATESPEED_HIGH, ID_VIEW_UPDATESPEED_PAUSED, TaskManagerSettings.UpdateSpeed, MF_BYCOMMAND);
585
586 if (TaskManagerSettings.CPUHistory_OneGraphPerCPU)
587 CheckMenuRadioItem(hCPUHistoryMenu, ID_VIEW_CPUHISTORY_ONEGRAPHALL, ID_VIEW_CPUHISTORY_ONEGRAPHPERCPU, ID_VIEW_CPUHISTORY_ONEGRAPHPERCPU, MF_BYCOMMAND);
588 else
589 CheckMenuRadioItem(hCPUHistoryMenu, ID_VIEW_CPUHISTORY_ONEGRAPHALL, ID_VIEW_CPUHISTORY_ONEGRAPHPERCPU, ID_VIEW_CPUHISTORY_ONEGRAPHALL, MF_BYCOMMAND);
590
591 nActivePage = TaskManagerSettings.ActiveTabPage;
592 TabCtrl_SetCurFocus/*Sel*/(hTabWnd, 0);
593 TabCtrl_SetCurFocus/*Sel*/(hTabWnd, 1);
594 TabCtrl_SetCurFocus/*Sel*/(hTabWnd, 2);
595 TabCtrl_SetCurFocus/*Sel*/(hTabWnd, nActivePage);
596
597 /* Setup update speed */
598 SetUpdateSpeed(hWnd);
599
600 /*
601 * Refresh the performance data
602 * Sample it twice so we can establish
603 * the delta values & cpu usage
604 */
605 PerfDataRefresh();
606 PerfDataRefresh();
607
608 RefreshApplicationPage();
609 RefreshProcessPage();
610 RefreshPerformancePage();
611
612 TrayIcon_ShellAddTrayIcon();
613
614 return TRUE;
615 }
616
617 /* OnMove()
618 * This function handles all the moving events for the application
619 * It moves every child window that needs moving
620 */
621 void OnMove( WPARAM nType, int cx, int cy )
622 {
623 #ifdef __GNUC__TEST__
624 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);
625 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);
626 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);
627 #endif
628 }
629
630 /* OnSize()
631 * This function handles all the sizing events for the application
632 * It re-sizes every window, and child window that needs re-sizing
633 */
634 void OnSize( WPARAM nType, int cx, int cy )
635 {
636 int nParts[3];
637 int nXDifference;
638 int nYDifference;
639 RECT rc;
640
641 if (nType == SIZE_MINIMIZED)
642 {
643 if(TaskManagerSettings.HideWhenMinimized)
644 {
645 ShowWindow(hMainWnd, SW_HIDE);
646 }
647 return;
648 }
649
650 nXDifference = cx - nOldWidth;
651 nYDifference = cy - nOldHeight;
652 nOldWidth = cx;
653 nOldHeight = cy;
654
655 /* Update the status bar size */
656 GetWindowRect(hStatusWnd, &rc);
657 SendMessageW(hStatusWnd, WM_SIZE, nType, MAKELPARAM(cx,rc.bottom - rc.top));
658
659 /* Update the status bar pane sizes */
660 nParts[0] = bInMenuLoop ? -1 : STATUS_SIZE1;
661 nParts[1] = STATUS_SIZE2;
662 nParts[2] = cx;
663 SendMessageW(hStatusWnd, SB_SETPARTS, bInMenuLoop ? 1 : 3, (LPARAM) (LPINT) nParts);
664
665 /* Resize the tab control */
666 GetWindowRect(hTabWnd, &rc);
667 cx = (rc.right - rc.left) + nXDifference;
668 cy = (rc.bottom - rc.top) + nYDifference;
669 SetWindowPos(hTabWnd, NULL, 0, 0, cx, cy, SWP_NOACTIVATE|SWP_NOOWNERZORDER|SWP_NOMOVE|SWP_NOZORDER);
670
671 /* Resize the application page */
672 GetWindowRect(hApplicationPage, &rc);
673 cx = (rc.right - rc.left) + nXDifference;
674 cy = (rc.bottom - rc.top) + nYDifference;
675 SetWindowPos(hApplicationPage, NULL, 0, 0, cx, cy, SWP_NOACTIVATE|SWP_NOOWNERZORDER|SWP_NOMOVE|SWP_NOZORDER);
676
677 /* Resize the process page */
678 GetWindowRect(hProcessPage, &rc);
679 cx = (rc.right - rc.left) + nXDifference;
680 cy = (rc.bottom - rc.top) + nYDifference;
681 SetWindowPos(hProcessPage, NULL, 0, 0, cx, cy, SWP_NOACTIVATE|SWP_NOOWNERZORDER|SWP_NOMOVE|SWP_NOZORDER);
682
683 /* Resize the performance page */
684 GetWindowRect(hPerformancePage, &rc);
685 cx = (rc.right - rc.left) + nXDifference;
686 cy = (rc.bottom - rc.top) + nYDifference;
687 SetWindowPos(hPerformancePage, NULL, 0, 0, cx, cy, SWP_NOACTIVATE|SWP_NOOWNERZORDER|SWP_NOMOVE|SWP_NOZORDER);
688 }
689
690 void LoadSettings(void)
691 {
692 HKEY hKey;
693 WCHAR szSubKey[] = L"Software\\ReactOS\\TaskManager";
694 int i;
695 DWORD dwSize;
696
697 /* Window size & position settings */
698 TaskManagerSettings.Maximized = FALSE;
699 TaskManagerSettings.Left = 0;
700 TaskManagerSettings.Top = 0;
701 TaskManagerSettings.Right = 0;
702 TaskManagerSettings.Bottom = 0;
703
704 /* Tab settings */
705 TaskManagerSettings.ActiveTabPage = 0;
706
707 /* Options menu settings */
708 TaskManagerSettings.AlwaysOnTop = FALSE;
709 TaskManagerSettings.MinimizeOnUse = TRUE;
710 TaskManagerSettings.HideWhenMinimized = TRUE;
711 TaskManagerSettings.Show16BitTasks = TRUE;
712
713 /* Update speed settings */
714 TaskManagerSettings.UpdateSpeed = ID_VIEW_UPDATESPEED_NORMAL;
715
716 /* Applications page settings */
717 TaskManagerSettings.ViewMode = ID_VIEW_DETAILS;
718
719 /* Processes page settings */
720 TaskManagerSettings.ShowProcessesFromAllUsers = FALSE; /* Server-only? */
721
722 for (i = 0; i < COLUMN_NMAX; i++) {
723 TaskManagerSettings.Columns[i] = ColumnPresets[i].bDefaults;
724 TaskManagerSettings.ColumnOrderArray[i] = i;
725 TaskManagerSettings.ColumnSizeArray[i] = ColumnPresets[i].size;
726 }
727
728 TaskManagerSettings.SortColumn = COLUMN_IMAGENAME;
729 TaskManagerSettings.SortAscending = TRUE;
730
731 /* Performance page settings */
732 TaskManagerSettings.CPUHistory_OneGraphPerCPU = TRUE;
733 TaskManagerSettings.ShowKernelTimes = FALSE;
734
735 /* Open the key */
736 if (RegOpenKeyExW(HKEY_CURRENT_USER, szSubKey, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
737 return;
738 /* Read the settings */
739 dwSize = sizeof(TASKMANAGER_SETTINGS);
740 RegQueryValueExW(hKey, L"Preferences", NULL, NULL, (LPBYTE)&TaskManagerSettings, &dwSize);
741
742 /*
743 * ATM, the 'ImageName' column is always visible
744 * (and grayed in configuration dialog)
745 * This will avoid troubles if the registry gets corrupted.
746 */
747 TaskManagerSettings.Column_ImageName = TRUE;
748
749 /* Close the key */
750 RegCloseKey(hKey);
751 }
752
753 void SaveSettings(void)
754 {
755 HKEY hKey;
756 WCHAR szSubKey1[] = L"Software";
757 WCHAR szSubKey2[] = L"Software\\ReactOS";
758 WCHAR szSubKey3[] = L"Software\\ReactOS\\TaskManager";
759
760 /* Open (or create) the key */
761 hKey = NULL;
762 RegCreateKeyExW(HKEY_CURRENT_USER, szSubKey1, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, NULL);
763 RegCloseKey(hKey);
764 hKey = NULL;
765 RegCreateKeyExW(HKEY_CURRENT_USER, szSubKey2, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, NULL);
766 RegCloseKey(hKey);
767 hKey = NULL;
768 if (RegCreateKeyExW(HKEY_CURRENT_USER, szSubKey3, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, NULL) != ERROR_SUCCESS)
769 return;
770 /* Save the settings */
771 RegSetValueExW(hKey, L"Preferences", 0, REG_BINARY, (LPBYTE)&TaskManagerSettings, sizeof(TASKMANAGER_SETTINGS));
772 /* Close the key */
773 RegCloseKey(hKey);
774 }
775
776 void TaskManager_OnRestoreMainWindow(void)
777 {
778 HMENU hMenu, hOptionsMenu;
779 BOOL OnTop;
780
781 hMenu = GetMenu(hMainWnd);
782 hOptionsMenu = GetSubMenu(hMenu, OPTIONS_MENU_INDEX);
783 OnTop = ((GetWindowLongPtrW(hMainWnd, GWL_EXSTYLE) & WS_EX_TOPMOST) != 0);
784
785 OpenIcon(hMainWnd);
786 SetForegroundWindow(hMainWnd);
787 SetWindowPos(hMainWnd, (OnTop ? HWND_TOPMOST : HWND_TOP), 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW);
788 }
789
790 void TaskManager_OnEnterMenuLoop(HWND hWnd)
791 {
792 int nParts;
793
794 /* Update the status bar pane sizes */
795 nParts = -1;
796 SendMessageW(hStatusWnd, SB_SETPARTS, 1, (LPARAM) (LPINT)&nParts);
797 bInMenuLoop = TRUE;
798 SendMessageW(hStatusWnd, SB_SETTEXT, (WPARAM)0, (LPARAM)L"");
799 }
800
801 void TaskManager_OnExitMenuLoop(HWND hWnd)
802 {
803 RECT rc;
804 int nParts[3];
805 WCHAR text[260];
806 WCHAR szCpuUsage[256], szProcesses[256];
807
808 LoadStringW(hInst, IDS_STATUS_CPUUSAGE, szCpuUsage, 256);
809 LoadStringW(hInst, IDS_STATUS_PROCESSES, szProcesses, 256);
810
811 bInMenuLoop = FALSE;
812 /* Update the status bar pane sizes */
813 GetClientRect(hWnd, &rc);
814 nParts[0] = STATUS_SIZE1;
815 nParts[1] = STATUS_SIZE2;
816 nParts[2] = rc.right;
817 SendMessageW(hStatusWnd, SB_SETPARTS, 3, (LPARAM) (LPINT) nParts);
818 SendMessageW(hStatusWnd, SB_SETTEXT, 0, (LPARAM)L"");
819 wsprintfW(text, szCpuUsage, PerfDataGetProcessorUsage());
820 SendMessageW(hStatusWnd, SB_SETTEXT, 1, (LPARAM)text);
821 wsprintfW(text, szProcesses, PerfDataGetProcessCount());
822 SendMessageW(hStatusWnd, SB_SETTEXT, 0, (LPARAM)text);
823 }
824
825 void TaskManager_OnMenuSelect(HWND hWnd, UINT nItemID, UINT nFlags, HMENU hSysMenu)
826 {
827 WCHAR str[100];
828
829 wcscpy(str, L"");
830 if (LoadStringW(hInst, nItemID, str, 100)) {
831 /* load appropriate string */
832 LPWSTR lpsz = str;
833 /* first newline terminates actual string */
834 lpsz = wcschr(lpsz, '\n');
835 if (lpsz != NULL)
836 *lpsz = '\0';
837 }
838 SendMessageW(hStatusWnd, SB_SETTEXT, 0, (LPARAM)str);
839 }
840
841 void TaskManager_OnViewUpdateSpeed(DWORD dwSpeed)
842 {
843 HMENU hMenu;
844 HMENU hViewMenu;
845 HMENU hUpdateSpeedMenu;
846
847 hMenu = GetMenu(hMainWnd);
848 hViewMenu = GetSubMenu(hMenu, 2);
849 hUpdateSpeedMenu = GetSubMenu(hViewMenu, 1);
850
851 TaskManagerSettings.UpdateSpeed = dwSpeed;
852 CheckMenuRadioItem(hUpdateSpeedMenu, ID_VIEW_UPDATESPEED_HIGH, ID_VIEW_UPDATESPEED_PAUSED, dwSpeed, MF_BYCOMMAND);
853
854 KillTimer(hMainWnd, 1);
855
856 SetUpdateSpeed(hMainWnd);
857 }
858
859 void TaskManager_OnTabWndSelChange(void)
860 {
861 int i;
862 HMENU hMenu;
863 HMENU hOptionsMenu;
864 HMENU hViewMenu;
865 HMENU hSubMenu;
866 WCHAR szTemp[256];
867 SYSTEM_INFO sysInfo;
868
869 hMenu = GetMenu(hMainWnd);
870 hViewMenu = GetSubMenu(hMenu, 2);
871 hOptionsMenu = GetSubMenu(hMenu, 1);
872 TaskManagerSettings.ActiveTabPage = TabCtrl_GetCurSel(hTabWnd);
873 for (i = GetMenuItemCount(hViewMenu) - 1; i > 2; i--) {
874 hSubMenu = GetSubMenu(hViewMenu, i);
875 if (hSubMenu)
876 DestroyMenu(hSubMenu);
877 RemoveMenu(hViewMenu, i, MF_BYPOSITION);
878 }
879 RemoveMenu(hOptionsMenu, 3, MF_BYPOSITION);
880 switch (TaskManagerSettings.ActiveTabPage) {
881 case 0:
882 ShowWindow(hApplicationPage, SW_SHOW);
883 ShowWindow(hProcessPage, SW_HIDE);
884 ShowWindow(hPerformancePage, SW_HIDE);
885 BringWindowToTop(hApplicationPage);
886
887 LoadStringW(hInst, IDS_MENU_LARGEICONS, szTemp, 256);
888 AppendMenuW(hViewMenu, MF_STRING, ID_VIEW_LARGE, szTemp);
889
890 LoadStringW(hInst, IDS_MENU_SMALLICONS, szTemp, 256);
891 AppendMenuW(hViewMenu, MF_STRING, ID_VIEW_SMALL, szTemp);
892
893 LoadStringW(hInst, IDS_MENU_DETAILS, szTemp, 256);
894 AppendMenuW(hViewMenu, MF_STRING, ID_VIEW_DETAILS, szTemp);
895
896 if (GetMenuItemCount(hMenu) <= 4) {
897 hSubMenu = LoadMenuW(hInst, MAKEINTRESOURCEW(IDR_WINDOWSMENU));
898
899 LoadStringW(hInst, IDS_MENU_WINDOWS, szTemp, 256);
900 InsertMenuW(hMenu, 3, MF_BYPOSITION|MF_POPUP, (UINT_PTR) hSubMenu, szTemp);
901
902 DrawMenuBar(hMainWnd);
903 }
904 CheckMenuRadioItem(hViewMenu, ID_VIEW_LARGE, ID_VIEW_DETAILS, TaskManagerSettings.ViewMode, MF_BYCOMMAND);
905
906 /*
907 * Give the application list control focus
908 */
909 SetFocus(hApplicationPageListCtrl);
910 break;
911
912 case 1:
913 ShowWindow(hApplicationPage, SW_HIDE);
914 ShowWindow(hProcessPage, SW_SHOW);
915 ShowWindow(hPerformancePage, SW_HIDE);
916 BringWindowToTop(hProcessPage);
917
918 LoadStringW(hInst, IDS_MENU_SELECTCOLUMNS, szTemp, 256);
919 AppendMenuW(hViewMenu, MF_STRING, ID_VIEW_SELECTCOLUMNS, szTemp);
920
921 LoadStringW(hInst, IDS_MENU_16BITTASK, szTemp, 256);
922 AppendMenuW(hOptionsMenu, MF_STRING, ID_OPTIONS_SHOW16BITTASKS, szTemp);
923
924 if (TaskManagerSettings.Show16BitTasks)
925 CheckMenuItem(hOptionsMenu, ID_OPTIONS_SHOW16BITTASKS, MF_BYCOMMAND|MF_CHECKED);
926 if (GetMenuItemCount(hMenu) > 4)
927 {
928 DeleteMenu(hMenu, 3, MF_BYPOSITION);
929 DrawMenuBar(hMainWnd);
930 }
931 /*
932 * Give the process list control focus
933 */
934 SetFocus(hProcessPageListCtrl);
935 break;
936
937 case 2:
938 ShowWindow(hApplicationPage, SW_HIDE);
939 ShowWindow(hProcessPage, SW_HIDE);
940 ShowWindow(hPerformancePage, SW_SHOW);
941 BringWindowToTop(hPerformancePage);
942 if (GetMenuItemCount(hMenu) > 4) {
943 DeleteMenu(hMenu, 3, MF_BYPOSITION);
944 DrawMenuBar(hMainWnd);
945 }
946
947 GetSystemInfo(&sysInfo);
948
949 /* Hide CPU graph options on single CPU systems */
950 if (sysInfo.dwNumberOfProcessors > 1)
951 {
952 hSubMenu = CreatePopupMenu();
953
954 LoadStringW(hInst, IDS_MENU_ONEGRAPHALLCPUS, szTemp, 256);
955 AppendMenuW(hSubMenu, MF_STRING, ID_VIEW_CPUHISTORY_ONEGRAPHALL, szTemp);
956
957 LoadStringW(hInst, IDS_MENU_ONEGRAPHPERCPU, szTemp, 256);
958 AppendMenuW(hSubMenu, MF_STRING, ID_VIEW_CPUHISTORY_ONEGRAPHPERCPU, szTemp);
959
960 LoadStringW(hInst, IDS_MENU_CPUHISTORY, szTemp, 256);
961 AppendMenuW(hViewMenu, MF_STRING|MF_POPUP, (UINT_PTR) hSubMenu, szTemp);
962
963 if (TaskManagerSettings.CPUHistory_OneGraphPerCPU)
964 CheckMenuRadioItem(hSubMenu, ID_VIEW_CPUHISTORY_ONEGRAPHALL, ID_VIEW_CPUHISTORY_ONEGRAPHPERCPU, ID_VIEW_CPUHISTORY_ONEGRAPHPERCPU, MF_BYCOMMAND);
965 else
966 CheckMenuRadioItem(hSubMenu, ID_VIEW_CPUHISTORY_ONEGRAPHALL, ID_VIEW_CPUHISTORY_ONEGRAPHPERCPU, ID_VIEW_CPUHISTORY_ONEGRAPHALL, MF_BYCOMMAND);
967 }
968
969 LoadStringW(hInst, IDS_MENU_SHOWKERNELTIMES, szTemp, 256);
970 AppendMenuW(hViewMenu, MF_STRING, ID_VIEW_SHOWKERNELTIMES, szTemp);
971
972 if (TaskManagerSettings.ShowKernelTimes)
973 CheckMenuItem(hViewMenu, ID_VIEW_SHOWKERNELTIMES, MF_BYCOMMAND|MF_CHECKED);
974 else
975 CheckMenuItem(hViewMenu, ID_VIEW_SHOWKERNELTIMES, MF_BYCOMMAND|MF_UNCHECKED);
976
977 /*
978 * Give the tab control focus
979 */
980 SetFocus(hTabWnd);
981 break;
982 }
983 }
984
985 LPWSTR GetLastErrorText(LPWSTR lpszBuf, DWORD dwSize)
986 {
987 DWORD dwRet;
988 LPWSTR lpszTemp = NULL;
989
990 dwRet = FormatMessageW( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |FORMAT_MESSAGE_ARGUMENT_ARRAY,
991 NULL,
992 GetLastError(),
993 LANG_NEUTRAL,
994 (LPWSTR)&lpszTemp,
995 0,
996 NULL );
997
998 /* supplied buffer is not long enough */
999 if (!dwRet || ( (long)dwSize < (long)dwRet+14)) {
1000 lpszBuf[0] = L'\0';
1001 } else {
1002 lpszTemp[lstrlenW(lpszTemp)-2] = L'\0'; /*remove cr and newline character */
1003 wsprintfW(lpszBuf, L"%s (0x%x)", lpszTemp, (int)GetLastError());
1004 }
1005 if (lpszTemp) {
1006 LocalFree((HLOCAL)lpszTemp);
1007 }
1008 return lpszBuf;
1009 }
1010
1011 DWORD EndLocalThread(HANDLE *hThread, DWORD dwThread)
1012 {
1013 DWORD dwExitCodeThread = 0;
1014
1015 if (*hThread != NULL) {
1016 PostThreadMessage(dwThread,WM_QUIT,0,0);
1017 for (;;) {
1018 MSG msg;
1019
1020 if (WAIT_OBJECT_0 == WaitForSingleObject(*hThread, 500))
1021 break;
1022 while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
1023 TranslateMessage(&msg);
1024 DispatchMessage(&msg);
1025 }
1026 }
1027 GetExitCodeThread(*hThread, &dwExitCodeThread);
1028 CloseHandle(*hThread);
1029 *hThread = NULL;
1030 }
1031 return dwExitCodeThread;
1032 }
1033