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