[SYSDM] Make MHz and GHz strings translatable
[reactos.git] / dll / cpl / sysdm / general.c
1 /*
2 * PROJECT: ReactOS System Control Panel Applet
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: dll/cpl/sysdm/general.c
5 * PURPOSE: General System Information
6 * COPYRIGHT: Copyright Thomas Weidenmueller <w3seek@reactos.org>
7 * Copyright 2006 Ged Murphy <gedmurphy@gmail.com>
8 * Copyright 2006-2007 Colin Finck <mail@colinfinck.de>
9 *
10 */
11
12 #include "precomp.h"
13
14 #include <winnls.h>
15 #include <powrprof.h>
16 #include <buildno.h>
17 #include <strsafe.h>
18
19 #define ANIM_STEP 2
20 #define ANIM_TIME 50
21
22 typedef struct _IMGINFO
23 {
24 HBITMAP hBitmap;
25 INT cxSource;
26 INT cySource;
27 INT iPLanes;
28 INT iBits;
29 } IMGINFO, *PIMGINFO;
30
31 PIMGINFO pImgInfo = NULL;
32 BLENDFUNCTION BlendFunc = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA};
33
34 VOID ShowLastWin32Error(HWND hWndOwner)
35 {
36 LPTSTR lpMsg;
37 DWORD LastError;
38
39 LastError = GetLastError();
40 if (LastError == ERROR_SUCCESS)
41 return;
42
43 if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
44 FORMAT_MESSAGE_FROM_SYSTEM |
45 FORMAT_MESSAGE_IGNORE_INSERTS,
46 NULL,
47 LastError,
48 LANG_USER_DEFAULT,
49 (LPTSTR)&lpMsg,
50 0, NULL))
51 {
52 return;
53 }
54
55 MessageBox(hWndOwner, lpMsg, NULL, MB_OK | MB_ICONERROR);
56 LocalFree(lpMsg);
57 }
58
59
60 static VOID InitLogo(HWND hwndDlg)
61 {
62 BITMAP logoBitmap;
63 BITMAP maskBitmap;
64 BITMAPINFO bmpi;
65 HDC hDC = GetDC(hwndDlg);
66 HDC hDCLogo = CreateCompatibleDC(NULL);
67 HDC hDCMask = CreateCompatibleDC(NULL);
68 HBITMAP hMask, hLogo, hAlphaLogo = NULL;
69 COLORREF *pBits;
70 INT line, column;
71
72 ZeroMemory(pImgInfo, sizeof(*pImgInfo));
73 ZeroMemory(&bmpi, sizeof(bmpi));
74
75 hLogo = (HBITMAP)LoadImage(hApplet, MAKEINTRESOURCE(IDB_ROSBMP), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR);
76 hMask = (HBITMAP)LoadImage(hApplet, MAKEINTRESOURCE(IDB_ROSMASK), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR);
77
78 if (hLogo != NULL && hMask != NULL)
79 {
80 GetObject(hLogo, sizeof(BITMAP), &logoBitmap);
81 GetObject(hMask, sizeof(BITMAP), &maskBitmap);
82
83 if(logoBitmap.bmHeight != maskBitmap.bmHeight || logoBitmap.bmWidth != maskBitmap.bmWidth)
84 return;
85
86 pImgInfo->cxSource = logoBitmap.bmWidth;
87 pImgInfo->cySource = logoBitmap.bmHeight;
88
89 bmpi.bmiHeader.biSize = sizeof(BITMAPINFO);
90 bmpi.bmiHeader.biWidth = logoBitmap.bmWidth;
91 bmpi.bmiHeader.biHeight = logoBitmap.bmHeight;
92 bmpi.bmiHeader.biPlanes = 1;
93 bmpi.bmiHeader.biBitCount = 32;
94 bmpi.bmiHeader.biCompression = BI_RGB;
95 bmpi.bmiHeader.biSizeImage = 4 * logoBitmap.bmWidth * logoBitmap.bmHeight;
96
97 hAlphaLogo = CreateDIBSection(hDC, &bmpi, DIB_RGB_COLORS, (PVOID*)&pBits, 0, 0);
98
99 if(!hAlphaLogo)
100 return;
101
102 SelectObject(hDCLogo, hLogo);
103 SelectObject(hDCMask, hMask);
104
105 for(line = logoBitmap.bmHeight - 1; line >= 0; line--)
106 {
107 for(column = 0; column < logoBitmap.bmWidth; column++)
108 {
109 COLORREF alpha = GetPixel(hDCMask, column, line) & 0xFF;
110 COLORREF Color = GetPixel(hDCLogo, column, line);
111 DWORD r, g, b;
112
113 r = GetRValue(Color) * alpha / 255;
114 g = GetGValue(Color) * alpha / 255;
115 b = GetBValue(Color) * alpha / 255;
116
117 *pBits++ = b | g << 8 | r << 16 | alpha << 24;
118 }
119 }
120 }
121
122 pImgInfo->hBitmap = hAlphaLogo;
123 pImgInfo->cxSource = logoBitmap.bmWidth;
124 pImgInfo->cySource = logoBitmap.bmHeight;
125 pImgInfo->iBits = logoBitmap.bmBitsPixel;
126 pImgInfo->iPLanes = logoBitmap.bmPlanes;
127
128 DeleteObject(hLogo);
129 DeleteObject(hMask);
130 DeleteDC(hDCLogo);
131 DeleteDC(hDCMask);
132
133 }
134
135 LRESULT CALLBACK RosImageProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
136 {
137 static UINT timerid = 0, top = 0, offset;
138 static HBITMAP hCreditsBitmap;
139
140 switch (uMsg)
141 {
142 case WM_LBUTTONDBLCLK:
143 if (wParam & (MK_CONTROL | MK_SHIFT))
144 {
145 if (timerid == 0)
146 {
147 HDC hCreditsDC, hLogoDC;
148 HFONT hFont;
149 NONCLIENTMETRICS ncm;
150 RECT rcCredits;
151 TCHAR szCredits[2048];
152 INT iDevsHeight;
153
154 top = 0;
155 offset = 0;
156 hCreditsDC = CreateCompatibleDC(GetDC(NULL));
157 hLogoDC = CreateCompatibleDC(hCreditsDC);
158
159 if (hCreditsDC == NULL || hLogoDC == NULL)
160 break;
161
162 SetRect(&rcCredits, 0, 0, 0, 0);
163
164 ncm.cbSize = sizeof(NONCLIENTMETRICS);
165 SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, 0);
166
167 hFont = CreateFontIndirect(&ncm.lfMessageFont);
168 SelectObject(hCreditsDC, hFont);
169
170 LoadString(hApplet, IDS_DEVS, szCredits, sizeof(szCredits) / sizeof(TCHAR));
171 DrawText(hCreditsDC, szCredits, -1, &rcCredits, DT_CALCRECT);
172
173 iDevsHeight = rcCredits.bottom - rcCredits.top;
174
175 hCreditsBitmap = CreateBitmap(pImgInfo->cxSource, (2 * pImgInfo->cySource) + iDevsHeight + 1, pImgInfo->iPLanes, pImgInfo->iBits, NULL);
176
177 if(!hCreditsBitmap)
178 break;
179
180 SelectObject(hLogoDC, pImgInfo->hBitmap);
181 SelectObject(hCreditsDC, hCreditsBitmap);
182
183 offset += pImgInfo->cySource;
184
185 SetRect(&rcCredits, 0, 0, pImgInfo->cxSource, (2 * pImgInfo->cySource) + iDevsHeight + 1);
186 FillRect(hCreditsDC, &rcCredits, GetSysColorBrush(COLOR_3DFACE));
187
188 SetRect(&rcCredits, 0, offset, pImgInfo->cxSource, offset + iDevsHeight + 1);
189 SetBkMode(hCreditsDC, TRANSPARENT);
190
191 OffsetRect(&rcCredits, 1, 1);
192 SetTextColor(hCreditsDC, GetSysColor(COLOR_BTNSHADOW));
193 DrawText(hCreditsDC, szCredits, -1, &rcCredits, DT_CENTER);
194
195 OffsetRect(&rcCredits, -1, -1);
196 SetTextColor(hCreditsDC, GetSysColor(COLOR_WINDOWTEXT));
197 DrawText(hCreditsDC, szCredits, -1, &rcCredits, DT_CENTER);
198
199 offset += iDevsHeight;
200
201 AlphaBlend(hCreditsDC, 0, 0, pImgInfo->cxSource, pImgInfo->cySource, hLogoDC, 0, 0, pImgInfo->cxSource, pImgInfo->cySource, BlendFunc);
202 AlphaBlend(hCreditsDC, 0, offset, pImgInfo->cxSource, pImgInfo->cySource, hLogoDC, 0, 0, pImgInfo->cxSource, pImgInfo->cySource, BlendFunc);
203
204 DeleteDC(hLogoDC);
205 DeleteDC(hCreditsDC);
206
207 timerid = SetTimer(hwnd, 1, ANIM_TIME, NULL);
208 }
209 }
210 break;
211 case WM_LBUTTONDOWN:
212 if (timerid)
213 {
214 RECT rcCredits;
215 HDC hDC = GetDC(hwnd);
216
217 GetClientRect(hwnd, &rcCredits);
218 SetRect(&rcCredits, 0, 0, rcCredits.right, pImgInfo->cySource);
219 FillRect(hDC, &rcCredits, GetSysColorBrush(COLOR_3DFACE));
220
221 KillTimer(hwnd, timerid);
222 DeleteObject(hCreditsBitmap);
223 InvalidateRect(hwnd, NULL, FALSE);
224
225 top = 0;
226 timerid = 0;
227 }
228 break;
229 case WM_TIMER:
230 top += ANIM_STEP;
231
232 if (top > offset)
233 {
234 RECT rcCredits;
235 HDC hDC = GetDC(hwnd);
236
237 GetClientRect(hwnd, &rcCredits);
238 SetRect(&rcCredits, 0, 0, rcCredits.right, pImgInfo->cySource);
239 FillRect(hDC, &rcCredits, GetSysColorBrush(COLOR_3DFACE));
240
241 KillTimer(hwnd, timerid);
242 DeleteObject(hCreditsBitmap);
243
244 top = 0;
245 timerid = 0;
246 }
247
248 InvalidateRect(hwnd, NULL, FALSE);
249 break;
250 case WM_PAINT:
251 {
252 PAINTSTRUCT PS;
253 HDC hdcMem, hdc;
254 LONG left;
255
256 hdc = wParam != 0 ? (HDC)wParam : BeginPaint(hwnd, &PS);
257
258 GetClientRect(hwnd, &PS.rcPaint);
259
260 /* Position image in center of dialog */
261 left = (PS.rcPaint.right - pImgInfo->cxSource) / 2;
262 hdcMem = CreateCompatibleDC(hdc);
263
264 if (hdcMem != NULL)
265 {
266 if(timerid != 0)
267 {
268 SelectObject(hdcMem, hCreditsBitmap);
269 BitBlt(hdc, left, PS.rcPaint.top, PS.rcPaint.right - PS.rcPaint.left, PS.rcPaint.top + pImgInfo->cySource, hdcMem, 0, top, SRCCOPY);
270 }
271 else
272 {
273 SelectObject(hdcMem, pImgInfo->hBitmap);
274 AlphaBlend(hdc, left, PS.rcPaint.top, pImgInfo->cxSource, pImgInfo->cySource, hdcMem, 0, 0, pImgInfo->cxSource, pImgInfo->cySource, BlendFunc);
275 }
276
277 DeleteDC(hdcMem);
278 }
279
280 if (wParam == 0)
281 EndPaint(hwnd,&PS);
282 break;
283 }
284 }
285 return TRUE;
286 }
287
288 static VOID SetRegTextData(HWND hwnd, HKEY hKey, LPTSTR Value, UINT uID)
289 {
290 LPTSTR lpBuf = NULL;
291 DWORD BufSize = 0;
292 DWORD Type;
293
294 if (RegQueryValueEx(hKey, Value, NULL, &Type, NULL, &BufSize) == ERROR_SUCCESS)
295 {
296 lpBuf = HeapAlloc(GetProcessHeap(), 0, BufSize);
297
298 if (!lpBuf)
299 return;
300
301 if (RegQueryValueEx(hKey, Value, NULL, &Type, (PBYTE)lpBuf, &BufSize) == ERROR_SUCCESS)
302 SetDlgItemText(hwnd, uID, lpBuf);
303
304 HeapFree(GetProcessHeap(), 0, lpBuf);
305 }
306 }
307
308 static INT SetProcNameString(HWND hwnd, HKEY hKey, LPTSTR Value, UINT uID1, UINT uID2)
309 {
310 LPTSTR lpBuf = NULL;
311 DWORD BufSize = 0;
312 DWORD Type;
313 INT Ret = 0;
314 TCHAR szBuf[31];
315 TCHAR* szLastSpace;
316 INT LastSpace = 0;
317
318 if (RegQueryValueEx(hKey, Value, NULL, &Type, NULL, &BufSize) == ERROR_SUCCESS)
319 {
320 lpBuf = HeapAlloc(GetProcessHeap(), 0, BufSize);
321
322 if (!lpBuf)
323 return 0;
324
325 if (RegQueryValueEx(hKey, Value, NULL, &Type, (PBYTE)lpBuf, &BufSize) == ERROR_SUCCESS)
326 {
327 if (BufSize > ((30 + 1) * sizeof(TCHAR)))
328 {
329 /* Wrap the Processor Name String like XP does: *
330 * - Take the first 30 characters and look for the last space. *
331 * Then wrap the string after this space. *
332 * - If no space is found, wrap the string after character 30. *
333 * *
334 * For example the Processor Name String of a Pentium 4 is right-aligned. *
335 * With this wrapping the first line looks centered. */
336
337 _tcsncpy(szBuf, lpBuf, 30);
338 szBuf[30] = 0;
339 szLastSpace = _tcsrchr(szBuf, ' ');
340
341 if (szLastSpace == 0)
342 {
343 LastSpace = 30;
344 }
345 else
346 {
347 LastSpace = (szLastSpace - szBuf);
348 szBuf[LastSpace] = 0;
349 }
350
351 _tcsncpy(szBuf, lpBuf, LastSpace);
352
353 SetDlgItemText(hwnd, uID1, szBuf);
354 SetDlgItemText(hwnd, uID2, lpBuf+LastSpace+1);
355
356 /* Return the number of used lines */
357 Ret = 2;
358 }
359 else
360 {
361 SetDlgItemText(hwnd, uID1, lpBuf);
362 Ret = 1;
363 }
364 }
365
366 HeapFree(GetProcessHeap(), 0, lpBuf);
367 }
368
369 return Ret;
370 }
371
372 static VOID MakeFloatValueString(DOUBLE* dFloatValue, LPTSTR szOutput, LPTSTR szAppend)
373 {
374 TCHAR szDecimalSeparator[4];
375
376 /* Get the decimal separator for the current locale */
377 if (GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, szDecimalSeparator, sizeof(szDecimalSeparator) / sizeof(TCHAR)) > 0)
378 {
379 UCHAR uDecimals;
380 UINT uIntegral;
381
382 /* Show the value with two decimals */
383 uIntegral = (UINT)*dFloatValue;
384 uDecimals = (UCHAR)((UINT)(*dFloatValue * 100) - uIntegral * 100);
385
386 wsprintf(szOutput, _T("%u%s%02u %s"), uIntegral, szDecimalSeparator, uDecimals, szAppend);
387 }
388 }
389
390 static VOID SetProcSpeed(HWND hwnd, HKEY hKey, LPTSTR Value, UINT uID)
391 {
392 TCHAR szBuf[64], szHz[16];
393 DWORD BufSize = sizeof(DWORD);
394 DWORD Type = REG_SZ;
395 PROCESSOR_POWER_INFORMATION ppi;
396
397 ZeroMemory(&ppi, sizeof(ppi));
398
399 if ((CallNtPowerInformation(ProcessorInformation,
400 NULL,
401 0,
402 (PVOID)&ppi,
403 sizeof(ppi)) == STATUS_SUCCESS &&
404 ppi.CurrentMhz != 0) || RegQueryValueEx(hKey, Value, NULL, &Type, (PBYTE)&ppi.CurrentMhz, &BufSize) == ERROR_SUCCESS)
405 {
406 if (ppi.CurrentMhz < 1000)
407 {
408 if (!LoadString(hApplet, IDS_MEGAHERTZ, szHz, _countof(szHz)))
409 {
410 return;
411 }
412 StringCchPrintf(szBuf, _countof(szBuf), _T("%lu %s"), ppi.CurrentMhz, szHz);
413 }
414 else
415 {
416 double flt = ppi.CurrentMhz / 1000.0;
417 if (!LoadString(hApplet, IDS_GIGAHERTZ, szHz, _countof(szHz)))
418 {
419 return;
420 }
421 MakeFloatValueString(&flt, szBuf, szHz);
422 }
423
424 SetDlgItemText(hwnd, uID, szBuf);
425 }
426 }
427
428 static VOID GetSystemInformation(HWND hwnd)
429 {
430 HKEY hKey;
431 TCHAR ProcKey[] = _T("HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0");
432 MEMORYSTATUSEX MemStat;
433 TCHAR Buf[32];
434 WCHAR SMBiosName[96];
435 INT CurMachineLine = IDC_MACHINELINE1;
436
437 /*
438 * Get hardware device name or motherboard name
439 * using information from raw SMBIOS data
440 */
441 if (GetSystemName(SMBiosName, _countof(SMBiosName)))
442 {
443 SetDlgItemText(hwnd, CurMachineLine, SMBiosName);
444 CurMachineLine++;
445 }
446 /*
447 * Get Processor information
448 * although undocumented, this information is being pulled
449 * directly out of the registry instead of via setupapi as it
450 * contains all the info we need, and should remain static
451 */
452 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, ProcKey, 0, KEY_READ, &hKey) == ERROR_SUCCESS)
453 {
454 SetRegTextData(hwnd, hKey, _T("VendorIdentifier"), CurMachineLine);
455 CurMachineLine++;
456
457 CurMachineLine += SetProcNameString(hwnd,
458 hKey,
459 _T("ProcessorNameString"),
460 CurMachineLine,
461 CurMachineLine + 1);
462
463 SetProcSpeed(hwnd, hKey, _T("~MHz"), CurMachineLine);
464 CurMachineLine++;
465 }
466
467 /* Get total physical RAM */
468 MemStat.dwLength = sizeof(MemStat);
469
470 if (GlobalMemoryStatusEx(&MemStat))
471 {
472 TCHAR szStr[32];
473 double dTotalPhys;
474
475 if (MemStat.ullTotalPhys > 1024 * 1024 * 1024)
476 {
477 UINT i = 0;
478 static const UINT uStrId[] = { IDS_GIGABYTE, IDS_TERABYTE, IDS_PETABYTE};
479
480 // We're dealing with GBs or more
481 MemStat.ullTotalPhys /= 1024 * 1024;
482
483 if (MemStat.ullTotalPhys > 1024 * 1024)
484 {
485 // We're dealing with TBs or more
486 MemStat.ullTotalPhys /= 1024;
487 i++;
488
489 if (MemStat.ullTotalPhys > 1024 * 1024)
490 {
491 // We're dealing with PBs or more
492 MemStat.ullTotalPhys /= 1024;
493 i++;
494
495 dTotalPhys = (double)MemStat.ullTotalPhys / 1024;
496 }
497 else
498 {
499 dTotalPhys = (double)MemStat.ullTotalPhys / 1024;
500 }
501 }
502 else
503 {
504 dTotalPhys = (double)MemStat.ullTotalPhys / 1024;
505 }
506
507 LoadString(hApplet, uStrId[i], szStr, sizeof(szStr) / sizeof(TCHAR));
508 MakeFloatValueString(&dTotalPhys, Buf, szStr);
509 }
510 else
511 {
512 // We're dealing with MBs, don't show any decimals
513 LoadString(hApplet, IDS_MEGABYTE, szStr, sizeof(szStr) / sizeof(TCHAR));
514 wsprintf(Buf, _T("%u %s"), (UINT)MemStat.ullTotalPhys / 1024 / 1024, szStr);
515 }
516
517 SetDlgItemText(hwnd, CurMachineLine, Buf);
518 }
519 }
520
521 static VOID GetSystemVersion(HWND hwnd)
522 {
523 HWND hRosVersion;
524 SIZE_T lenStr, lenVersion;
525 PCWSTR pwszVersion = L" " TEXT(KERNEL_VERSION_RC);
526 PWSTR pwszStr;
527
528 lenVersion = wcslen(pwszVersion);
529 if (lenVersion == 0)
530 {
531 return;
532 }
533
534 hRosVersion = GetDlgItem(hwnd, IDC_ROSVERSION);
535 if (!hRosVersion)
536 {
537 return;
538 }
539 lenStr = GetWindowTextLengthW(hRosVersion);
540 lenStr += lenVersion + 1;
541 pwszStr = HeapAlloc(GetProcessHeap(), 0, lenStr * sizeof(WCHAR));
542 if (!pwszStr)
543 {
544 return;
545 }
546 GetWindowText(hRosVersion, pwszStr, lenStr);
547
548 StringCchCatW(pwszStr, lenStr, pwszVersion);
549 SetWindowText(hRosVersion, pwszStr);
550
551 HeapFree(GetProcessHeap(), 0, pwszStr);
552 }
553
554 /* Property page dialog callback */
555 INT_PTR CALLBACK GeneralPageProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
556 {
557 UNREFERENCED_PARAMETER(lParam);
558 UNREFERENCED_PARAMETER(wParam);
559
560 switch (uMsg)
561 {
562 case WM_INITDIALOG:
563 pImgInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IMGINFO));
564 if (pImgInfo == NULL)
565 {
566 EndDialog(hwndDlg, 0);
567 return FALSE;
568 }
569
570 InitLogo(hwndDlg);
571 SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_ROSIMG), GWLP_WNDPROC, (LONG_PTR)RosImageProc);
572 GetSystemInformation(hwndDlg);
573 GetSystemVersion(hwndDlg);
574 break;
575
576 case WM_DESTROY:
577 HeapFree(GetProcessHeap(), 0, pImgInfo);
578 break;
579
580 case WM_COMMAND:
581 if (LOWORD(wParam) == IDC_LICENCE)
582 {
583 DialogBox(hApplet, MAKEINTRESOURCE(IDD_LICENCE), hwndDlg, LicenceDlgProc);
584
585 return TRUE;
586 }
587 break;
588
589 case WM_DRAWITEM:
590 {
591 LPDRAWITEMSTRUCT lpDrawItem = (LPDRAWITEMSTRUCT) lParam;
592
593 if (lpDrawItem->CtlID == IDC_ROSIMG)
594 {
595 HDC hdcMem;
596 LONG left;
597
598 /* Position image in centre of dialog */
599 left = (lpDrawItem->rcItem.right - pImgInfo->cxSource) / 2;
600
601 hdcMem = CreateCompatibleDC(lpDrawItem->hDC);
602 if (hdcMem != NULL)
603 {
604 SelectObject(hdcMem, pImgInfo->hBitmap);
605 BitBlt(lpDrawItem->hDC,
606 left,
607 lpDrawItem->rcItem.top,
608 lpDrawItem->rcItem.right - lpDrawItem->rcItem.left,
609 lpDrawItem->rcItem.bottom - lpDrawItem->rcItem.top,
610 hdcMem,
611 0,
612 0,
613 SRCCOPY);
614 DeleteDC(hdcMem);
615 }
616 }
617 return TRUE;
618 }
619
620 case WM_NOTIFY:
621 {
622 NMHDR *nmhdr = (NMHDR *)lParam;
623
624 if (nmhdr->idFrom == IDC_ROSHOMEPAGE_LINK && nmhdr->code == NM_CLICK)
625 {
626 PNMLINK nml = (PNMLINK)nmhdr;
627
628 ShellExecuteW(hwndDlg, L"open", nml->item.szUrl, NULL, NULL, SW_SHOWNORMAL);
629 }
630 break;
631 }
632
633 }
634
635 return FALSE;
636 }