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