8c1c7aba3f2f05ba202e39b8caa50663189e2075
[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 typedef struct _IMGINFO
16 {
17 HBITMAP hBitmap;
18 INT cxSource;
19 INT cySource;
20 } IMGINFO, *PIMGINFO;
21
22
23 void
24 ShowLastWin32Error(HWND hWndOwner)
25 {
26 LPTSTR lpMsg;
27 DWORD LastError;
28
29 LastError = GetLastError();
30
31 if ((LastError == 0) ||
32 !FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
33 FORMAT_MESSAGE_FROM_SYSTEM,
34 NULL,
35 LastError,
36 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
37 (LPTSTR)&lpMsg,
38 0,
39 NULL))
40 {
41 return;
42 }
43
44 MessageBox(hWndOwner, lpMsg, NULL, MB_OK | MB_ICONERROR);
45
46 LocalFree((LPVOID)lpMsg);
47 }
48
49
50 static VOID
51 InitImageInfo(PIMGINFO ImgInfo)
52 {
53 BITMAP bitmap;
54
55 ZeroMemory(ImgInfo, sizeof(*ImgInfo));
56
57 ImgInfo->hBitmap = LoadImage(hApplet,
58 MAKEINTRESOURCE(IDB_ROSBMP),
59 IMAGE_BITMAP,
60 0,
61 0,
62 LR_DEFAULTCOLOR);
63
64 if (ImgInfo->hBitmap != NULL)
65 {
66 GetObject(ImgInfo->hBitmap, sizeof(BITMAP), &bitmap);
67
68 ImgInfo->cxSource = bitmap.bmWidth;
69 ImgInfo->cySource = bitmap.bmHeight;
70 }
71 }
72
73
74 static VOID
75 SetRegTextData(HWND hwnd,
76 HKEY hKey,
77 LPTSTR Value,
78 UINT uID)
79 {
80 LPTSTR lpBuf = NULL;
81 DWORD BufSize = 0;
82 DWORD Type;
83
84 if (RegQueryValueEx(hKey,
85 Value,
86 NULL,
87 &Type,
88 NULL,
89 &BufSize) == ERROR_SUCCESS)
90 {
91 lpBuf = HeapAlloc(GetProcessHeap(),
92 0,
93 BufSize);
94 if (!lpBuf)
95 return;
96
97 if (RegQueryValueEx(hKey,
98 Value,
99 NULL,
100 &Type,
101 (PBYTE)lpBuf,
102 &BufSize) == ERROR_SUCCESS)
103 {
104 SetDlgItemText(hwnd,
105 uID,
106 lpBuf);
107 }
108
109 HeapFree(GetProcessHeap(),
110 0,
111 lpBuf);
112 }
113 }
114
115 static INT
116 SetProcNameString(HWND hwnd,
117 HKEY hKey,
118 LPTSTR Value,
119 UINT uID1,
120 UINT uID2)
121 {
122 LPTSTR lpBuf = NULL;
123 DWORD BufSize = 0;
124 DWORD Type;
125 INT Ret = 0;
126 TCHAR szBuf[31];
127 TCHAR* szLastSpace;
128 INT LastSpace = 0;
129
130 if (RegQueryValueEx(hKey,
131 Value,
132 NULL,
133 &Type,
134 NULL,
135 &BufSize) == ERROR_SUCCESS)
136 {
137 lpBuf = HeapAlloc(GetProcessHeap(),
138 0,
139 BufSize);
140 if (!lpBuf)
141 return 0;
142
143 if (RegQueryValueEx(hKey,
144 Value,
145 NULL,
146 &Type,
147 (PBYTE)lpBuf,
148 &BufSize) == ERROR_SUCCESS)
149 {
150 if (BufSize > ((30 + 1) * sizeof(TCHAR)))
151 {
152 /* Wrap the Processor Name String like XP does: *
153 * - Take the first 30 characters and look for the last space. *
154 * Then wrap the string after this space. *
155 * - If no space is found, wrap the string after character 30. *
156 * *
157 * For example the Processor Name String of a Pentium 4 is right-aligned. *
158 * With this wrapping the first line looks centered. */
159
160 _tcsncpy(szBuf, lpBuf, 30);
161 szBuf[30] = 0;
162 szLastSpace = _tcsrchr(szBuf, ' ');
163
164 if (szLastSpace == 0)
165 {
166 LastSpace = 30;
167 }
168 else
169 {
170 LastSpace = (szLastSpace - szBuf);
171 szBuf[LastSpace] = 0;
172 }
173
174 _tcsncpy(szBuf, lpBuf, LastSpace);
175
176 SetDlgItemText(hwnd,
177 uID1,
178 szBuf);
179
180 SetDlgItemText(hwnd,
181 uID2,
182 lpBuf+LastSpace+1);
183
184 /* Return the number of used lines */
185 Ret = 2;
186 }
187 else
188 {
189 SetDlgItemText(hwnd,
190 uID1,
191 lpBuf);
192
193 Ret = 1;
194 }
195 }
196
197 HeapFree(GetProcessHeap(),
198 0,
199 lpBuf);
200 }
201
202 return Ret;
203 }
204
205 static VOID
206 MakeFloatValueString(double* dFloatValue,
207 LPTSTR szOutput,
208 LPTSTR szAppend)
209 {
210 TCHAR szDecimalSeparator[4];
211
212 /* Get the decimal separator for the current locale */
213 if (GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, szDecimalSeparator, sizeof(szDecimalSeparator) / sizeof(TCHAR)) > 0)
214 {
215 UCHAR uDecimals;
216 UINT uIntegral;
217
218 /* Show the value with two decimals */
219 uIntegral = (UINT)*dFloatValue;
220 uDecimals = (UCHAR)((UINT)(*dFloatValue * 100) - uIntegral * 100);
221
222 wsprintf(szOutput, _T("%u%s%02u %s"), uIntegral, szDecimalSeparator, uDecimals, szAppend);
223 }
224 }
225
226 static VOID
227 SetProcSpeed(HWND hwnd,
228 HKEY hKey,
229 LPTSTR Value,
230 UINT uID)
231 {
232 TCHAR szBuf[64];
233 DWORD BufSize = sizeof(DWORD);
234 DWORD Type = REG_SZ;
235 PROCESSOR_POWER_INFORMATION ppi;
236
237 ZeroMemory(&ppi,
238 sizeof(ppi));
239
240 if ((CallNtPowerInformation(ProcessorInformation,
241 NULL,
242 0,
243 (PVOID)&ppi,
244 sizeof(ppi)) == STATUS_SUCCESS &&
245 ppi.CurrentMhz != 0) ||
246 RegQueryValueEx(hKey,
247 Value,
248 NULL,
249 &Type,
250 (PBYTE)&ppi.CurrentMhz,
251 &BufSize) == ERROR_SUCCESS)
252 {
253 if (ppi.CurrentMhz < 1000)
254 {
255 wsprintf(szBuf, _T("%lu MHz"), ppi.CurrentMhz);
256 }
257 else
258 {
259 double flt = ppi.CurrentMhz / 1000.0;
260 MakeFloatValueString(&flt, szBuf, _T("GHz"));
261 }
262
263 SetDlgItemText(hwnd,
264 uID,
265 szBuf);
266 }
267 }
268
269 static VOID
270 GetSystemInformation(HWND hwnd)
271 {
272 HKEY hKey;
273 TCHAR ProcKey[] = _T("HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0");
274 MEMORYSTATUSEX MemStat;
275 TCHAR Buf[32];
276 INT CurMachineLine = IDC_MACHINELINE1;
277
278 /*
279 * Get Processor information
280 * although undocumented, this information is being pulled
281 * directly out of the registry instead of via setupapi as it
282 * contains all the info we need, and should remain static
283 */
284 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
285 ProcKey,
286 0,
287 KEY_READ,
288 &hKey) == ERROR_SUCCESS)
289 {
290 SetRegTextData(hwnd,
291 hKey,
292 _T("VendorIdentifier"),
293 CurMachineLine);
294 CurMachineLine++;
295
296 CurMachineLine += SetProcNameString(hwnd,
297 hKey,
298 _T("ProcessorNameString"),
299 CurMachineLine,
300 CurMachineLine + 1);
301
302 SetProcSpeed(hwnd,
303 hKey,
304 _T("~MHz"),
305 CurMachineLine);
306 CurMachineLine++;
307 }
308
309
310 /* Get total physical RAM */
311 MemStat.dwLength = sizeof(MemStat);
312 if (GlobalMemoryStatusEx(&MemStat))
313 {
314 TCHAR szStr[32];
315 double dTotalPhys;
316
317 if (MemStat.ullTotalPhys > 1024 * 1024 * 1024)
318 {
319 UINT i = 0;
320 static const UINT uStrId[] = {
321 IDS_GIGABYTE,
322 IDS_TERABYTE,
323 IDS_PETABYTE
324 };
325
326 // We're dealing with GBs or more
327 MemStat.ullTotalPhys /= 1024 * 1024;
328
329 if (MemStat.ullTotalPhys > 1024 * 1024)
330 {
331 // We're dealing with TBs or more
332 MemStat.ullTotalPhys /= 1024;
333 i++;
334
335 if (MemStat.ullTotalPhys > 1024 * 1024)
336 {
337 // We're dealing with PBs or more
338 MemStat.ullTotalPhys /= 1024;
339 i++;
340
341 dTotalPhys = (double)MemStat.ullTotalPhys / 1024;
342 }
343 else
344 {
345 dTotalPhys = (double)MemStat.ullTotalPhys / 1024;
346 }
347 }
348 else
349 {
350 dTotalPhys = (double)MemStat.ullTotalPhys / 1024;
351 }
352
353 LoadString(hApplet, uStrId[i], szStr, sizeof(szStr) / sizeof(TCHAR));
354 MakeFloatValueString(&dTotalPhys, Buf, szStr);
355 }
356 else
357 {
358 // We're dealing with MBs, don't show any decimals
359 LoadString(hApplet, IDS_MEGABYTE, szStr, sizeof(szStr) / sizeof(TCHAR));
360 wsprintf(Buf, _T("%u %s"), (UINT)MemStat.ullTotalPhys / 1024 / 1024, szStr);
361 }
362
363 SetDlgItemText(hwnd, CurMachineLine, Buf);
364 }
365 }
366
367
368 /* Property page dialog callback */
369 INT_PTR CALLBACK
370 GeneralPageProc(HWND hwndDlg,
371 UINT uMsg,
372 WPARAM wParam,
373 LPARAM lParam)
374 {
375 PIMGINFO pImgInfo;
376
377 UNREFERENCED_PARAMETER(lParam);
378 UNREFERENCED_PARAMETER(wParam);
379
380 pImgInfo = (PIMGINFO)GetWindowLongPtr(hwndDlg, DWLP_USER);
381
382 switch (uMsg)
383 {
384 case WM_INITDIALOG:
385 pImgInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IMGINFO));
386 if (pImgInfo == NULL)
387 {
388 EndDialog(hwndDlg, 0);
389 return FALSE;
390 }
391
392 SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pImgInfo);
393
394 InitImageInfo(pImgInfo);
395 GetSystemInformation(hwndDlg);
396 break;
397
398 case WM_DESTROY:
399 HeapFree(GetProcessHeap(), 0, pImgInfo);
400 break;
401
402 case WM_COMMAND:
403 if (LOWORD(wParam) == IDC_LICENCE)
404 {
405 DialogBox(hApplet,
406 MAKEINTRESOURCE(IDD_LICENCE),
407 hwndDlg,
408 LicenceDlgProc);
409
410 return TRUE;
411 }
412 break;
413
414 case WM_DRAWITEM:
415 {
416 LPDRAWITEMSTRUCT lpDrawItem;
417 lpDrawItem = (LPDRAWITEMSTRUCT) lParam;
418 if (lpDrawItem->CtlID == IDC_ROSIMG)
419 {
420 HDC hdcMem;
421 LONG left;
422
423 /* position image in centre of dialog */
424 left = (lpDrawItem->rcItem.right - pImgInfo->cxSource) / 2;
425
426 hdcMem = CreateCompatibleDC(lpDrawItem->hDC);
427 if (hdcMem != NULL)
428 {
429 SelectObject(hdcMem, pImgInfo->hBitmap);
430 BitBlt(lpDrawItem->hDC,
431 left,
432 lpDrawItem->rcItem.top,
433 lpDrawItem->rcItem.right - lpDrawItem->rcItem.left,
434 lpDrawItem->rcItem.bottom - lpDrawItem->rcItem.top,
435 hdcMem,
436 0,
437 0,
438 SRCCOPY);
439 DeleteDC(hdcMem);
440 }
441 }
442 return TRUE;
443 }
444
445 case WM_NOTIFY:
446 {
447 NMHDR *nmhdr = (NMHDR *)lParam;
448
449 if (nmhdr->idFrom == IDC_ROSHOMEPAGE_LINK && nmhdr->code == NM_CLICK)
450 {
451 PNMLINK nml = (PNMLINK)nmhdr;
452
453 ShellExecuteW(hwndDlg,
454 L"open",
455 nml->item.szUrl,
456 NULL,
457 NULL,
458 SW_SHOWNORMAL);
459 }
460 break;
461 }
462
463 }
464
465 return FALSE;
466 }