72b87de1154b5016a34a2e665cc7612eb675407a
[reactos.git] / reactos / 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 } else
174 {
175 hdc = BeginPaint(hwnd,&PS);
176 }
177 GetClientRect(hwnd,&PS.rcPaint);
178
179 /* position image in center of dialog */
180 left = (PS.rcPaint.right - pImgInfo->cxSource) / 2;
181 hdcMem = CreateCompatibleDC(hdc);
182
183 if (hdcMem != NULL)
184 {
185 SelectObject(hdcMem, timerid ? hBitmap2 : pImgInfo->hBitmap);
186 BitBlt(hdc,
187 left,
188 PS.rcPaint.top,
189 PS.rcPaint.right - PS.rcPaint.left,
190 PS.rcPaint.top + pImgInfo->cySource,
191 hdcMem,
192 0,
193 top,
194 SRCCOPY);
195 DeleteDC(hdcMem);
196 }
197 if (wParam == 0)
198 EndPaint(hwnd,&PS);
199 break;
200 }
201 }
202 return TRUE;
203 }
204
205 static VOID
206 SetRegTextData(HWND hwnd,
207 HKEY hKey,
208 LPTSTR Value,
209 UINT uID)
210 {
211 LPTSTR lpBuf = NULL;
212 DWORD BufSize = 0;
213 DWORD Type;
214
215 if (RegQueryValueEx(hKey,
216 Value,
217 NULL,
218 &Type,
219 NULL,
220 &BufSize) == ERROR_SUCCESS)
221 {
222 lpBuf = HeapAlloc(GetProcessHeap(),
223 0,
224 BufSize);
225 if (!lpBuf)
226 return;
227
228 if (RegQueryValueEx(hKey,
229 Value,
230 NULL,
231 &Type,
232 (PBYTE)lpBuf,
233 &BufSize) == ERROR_SUCCESS)
234 {
235 SetDlgItemText(hwnd,
236 uID,
237 lpBuf);
238 }
239
240 HeapFree(GetProcessHeap(),
241 0,
242 lpBuf);
243 }
244 }
245
246 static INT
247 SetProcNameString(HWND hwnd,
248 HKEY hKey,
249 LPTSTR Value,
250 UINT uID1,
251 UINT uID2)
252 {
253 LPTSTR lpBuf = NULL;
254 DWORD BufSize = 0;
255 DWORD Type;
256 INT Ret = 0;
257 TCHAR szBuf[31];
258 TCHAR* szLastSpace;
259 INT LastSpace = 0;
260
261 if (RegQueryValueEx(hKey,
262 Value,
263 NULL,
264 &Type,
265 NULL,
266 &BufSize) == ERROR_SUCCESS)
267 {
268 lpBuf = HeapAlloc(GetProcessHeap(),
269 0,
270 BufSize);
271 if (!lpBuf)
272 return 0;
273
274 if (RegQueryValueEx(hKey,
275 Value,
276 NULL,
277 &Type,
278 (PBYTE)lpBuf,
279 &BufSize) == ERROR_SUCCESS)
280 {
281 if (BufSize > ((30 + 1) * sizeof(TCHAR)))
282 {
283 /* Wrap the Processor Name String like XP does: *
284 * - Take the first 30 characters and look for the last space. *
285 * Then wrap the string after this space. *
286 * - If no space is found, wrap the string after character 30. *
287 * *
288 * For example the Processor Name String of a Pentium 4 is right-aligned. *
289 * With this wrapping the first line looks centered. */
290
291 _tcsncpy(szBuf, lpBuf, 30);
292 szBuf[30] = 0;
293 szLastSpace = _tcsrchr(szBuf, ' ');
294
295 if (szLastSpace == 0)
296 {
297 LastSpace = 30;
298 }
299 else
300 {
301 LastSpace = (szLastSpace - szBuf);
302 szBuf[LastSpace] = 0;
303 }
304
305 _tcsncpy(szBuf, lpBuf, LastSpace);
306
307 SetDlgItemText(hwnd,
308 uID1,
309 szBuf);
310
311 SetDlgItemText(hwnd,
312 uID2,
313 lpBuf+LastSpace+1);
314
315 /* Return the number of used lines */
316 Ret = 2;
317 }
318 else
319 {
320 SetDlgItemText(hwnd,
321 uID1,
322 lpBuf);
323
324 Ret = 1;
325 }
326 }
327
328 HeapFree(GetProcessHeap(),
329 0,
330 lpBuf);
331 }
332
333 return Ret;
334 }
335
336 static VOID
337 MakeFloatValueString(double* dFloatValue,
338 LPTSTR szOutput,
339 LPTSTR szAppend)
340 {
341 TCHAR szDecimalSeparator[4];
342
343 /* Get the decimal separator for the current locale */
344 if (GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, szDecimalSeparator, sizeof(szDecimalSeparator) / sizeof(TCHAR)) > 0)
345 {
346 UCHAR uDecimals;
347 UINT uIntegral;
348
349 /* Show the value with two decimals */
350 uIntegral = (UINT)*dFloatValue;
351 uDecimals = (UCHAR)((UINT)(*dFloatValue * 100) - uIntegral * 100);
352
353 wsprintf(szOutput, _T("%u%s%02u %s"), uIntegral, szDecimalSeparator, uDecimals, szAppend);
354 }
355 }
356
357 static VOID
358 SetProcSpeed(HWND hwnd,
359 HKEY hKey,
360 LPTSTR Value,
361 UINT uID)
362 {
363 TCHAR szBuf[64];
364 DWORD BufSize = sizeof(DWORD);
365 DWORD Type = REG_SZ;
366 PROCESSOR_POWER_INFORMATION ppi;
367
368 ZeroMemory(&ppi,
369 sizeof(ppi));
370
371 if ((CallNtPowerInformation(ProcessorInformation,
372 NULL,
373 0,
374 (PVOID)&ppi,
375 sizeof(ppi)) == STATUS_SUCCESS &&
376 ppi.CurrentMhz != 0) ||
377 RegQueryValueEx(hKey,
378 Value,
379 NULL,
380 &Type,
381 (PBYTE)&ppi.CurrentMhz,
382 &BufSize) == ERROR_SUCCESS)
383 {
384 if (ppi.CurrentMhz < 1000)
385 {
386 wsprintf(szBuf, _T("%lu MHz"), ppi.CurrentMhz);
387 }
388 else
389 {
390 double flt = ppi.CurrentMhz / 1000.0;
391 MakeFloatValueString(&flt, szBuf, _T("GHz"));
392 }
393
394 SetDlgItemText(hwnd,
395 uID,
396 szBuf);
397 }
398 }
399
400 static VOID
401 GetSystemInformation(HWND hwnd)
402 {
403 HKEY hKey;
404 TCHAR ProcKey[] = _T("HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0");
405 MEMORYSTATUSEX MemStat;
406 TCHAR Buf[32];
407 INT CurMachineLine = IDC_MACHINELINE1;
408
409 /*
410 * Get Processor information
411 * although undocumented, this information is being pulled
412 * directly out of the registry instead of via setupapi as it
413 * contains all the info we need, and should remain static
414 */
415 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
416 ProcKey,
417 0,
418 KEY_READ,
419 &hKey) == ERROR_SUCCESS)
420 {
421 SetRegTextData(hwnd,
422 hKey,
423 _T("VendorIdentifier"),
424 CurMachineLine);
425 CurMachineLine++;
426
427 CurMachineLine += SetProcNameString(hwnd,
428 hKey,
429 _T("ProcessorNameString"),
430 CurMachineLine,
431 CurMachineLine + 1);
432
433 SetProcSpeed(hwnd,
434 hKey,
435 _T("~MHz"),
436 CurMachineLine);
437 CurMachineLine++;
438 }
439
440
441 /* Get total physical RAM */
442 MemStat.dwLength = sizeof(MemStat);
443 if (GlobalMemoryStatusEx(&MemStat))
444 {
445 TCHAR szStr[32];
446 double dTotalPhys;
447
448 if (MemStat.ullTotalPhys > 1024 * 1024 * 1024)
449 {
450 UINT i = 0;
451 static const UINT uStrId[] = {
452 IDS_GIGABYTE,
453 IDS_TERABYTE,
454 IDS_PETABYTE
455 };
456
457 // We're dealing with GBs or more
458 MemStat.ullTotalPhys /= 1024 * 1024;
459
460 if (MemStat.ullTotalPhys > 1024 * 1024)
461 {
462 // We're dealing with TBs or more
463 MemStat.ullTotalPhys /= 1024;
464 i++;
465
466 if (MemStat.ullTotalPhys > 1024 * 1024)
467 {
468 // We're dealing with PBs or more
469 MemStat.ullTotalPhys /= 1024;
470 i++;
471
472 dTotalPhys = (double)MemStat.ullTotalPhys / 1024;
473 }
474 else
475 {
476 dTotalPhys = (double)MemStat.ullTotalPhys / 1024;
477 }
478 }
479 else
480 {
481 dTotalPhys = (double)MemStat.ullTotalPhys / 1024;
482 }
483
484 LoadString(hApplet, uStrId[i], szStr, sizeof(szStr) / sizeof(TCHAR));
485 MakeFloatValueString(&dTotalPhys, Buf, szStr);
486 }
487 else
488 {
489 // We're dealing with MBs, don't show any decimals
490 LoadString(hApplet, IDS_MEGABYTE, szStr, sizeof(szStr) / sizeof(TCHAR));
491 wsprintf(Buf, _T("%u %s"), (UINT)MemStat.ullTotalPhys / 1024 / 1024, szStr);
492 }
493
494 SetDlgItemText(hwnd, CurMachineLine, Buf);
495 }
496 }
497
498
499 /* Property page dialog callback */
500 INT_PTR CALLBACK
501 GeneralPageProc(HWND hwndDlg,
502 UINT uMsg,
503 WPARAM wParam,
504 LPARAM lParam)
505 {
506
507 UNREFERENCED_PARAMETER(lParam);
508 UNREFERENCED_PARAMETER(wParam);
509
510 switch (uMsg)
511 {
512 case WM_INITDIALOG:
513 pImgInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IMGINFO));
514 if (pImgInfo == NULL)
515 {
516 EndDialog(hwndDlg, 0);
517 return FALSE;
518 }
519
520 InitImageInfo(pImgInfo);
521 SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_ROSIMG), GWL_WNDPROC, (LONG)RosImageProc);
522 GetSystemInformation(hwndDlg);
523 break;
524
525 case WM_DESTROY:
526 HeapFree(GetProcessHeap(), 0, pImgInfo);
527 break;
528
529 case WM_COMMAND:
530 if (LOWORD(wParam) == IDC_LICENCE)
531 {
532 DialogBox(hApplet,
533 MAKEINTRESOURCE(IDD_LICENCE),
534 hwndDlg,
535 LicenceDlgProc);
536
537 return TRUE;
538 }
539 break;
540
541 case WM_DRAWITEM:
542 {
543 LPDRAWITEMSTRUCT lpDrawItem;
544 lpDrawItem = (LPDRAWITEMSTRUCT) lParam;
545 if (lpDrawItem->CtlID == IDC_ROSIMG)
546 {
547 HDC hdcMem;
548 LONG left;
549
550 /* position image in centre of dialog */
551 left = (lpDrawItem->rcItem.right - pImgInfo->cxSource) / 2;
552
553 hdcMem = CreateCompatibleDC(lpDrawItem->hDC);
554 if (hdcMem != NULL)
555 {
556 SelectObject(hdcMem, pImgInfo->hBitmap);
557 BitBlt(lpDrawItem->hDC,
558 left,
559 lpDrawItem->rcItem.top,
560 lpDrawItem->rcItem.right - lpDrawItem->rcItem.left,
561 lpDrawItem->rcItem.bottom - lpDrawItem->rcItem.top,
562 hdcMem,
563 0,
564 0,
565 SRCCOPY);
566 DeleteDC(hdcMem);
567 }
568 }
569 return TRUE;
570 }
571
572 case WM_NOTIFY:
573 {
574 NMHDR *nmhdr = (NMHDR *)lParam;
575
576 if (nmhdr->idFrom == IDC_ROSHOMEPAGE_LINK && nmhdr->code == NM_CLICK)
577 {
578 PNMLINK nml = (PNMLINK)nmhdr;
579
580 ShellExecuteW(hwndDlg,
581 L"open",
582 nml->item.szUrl,
583 NULL,
584 NULL,
585 SW_SHOWNORMAL);
586 }
587 break;
588 }
589
590 }
591
592 return FALSE;
593 }