- Bugfix: As szBuf was not null-terminated after the _tcscpy, the Processor Name...
[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) return;
95
96 if (RegQueryValueEx(hKey,
97 Value,
98 NULL,
99 &Type,
100 (PBYTE)lpBuf,
101 &BufSize) == ERROR_SUCCESS)
102 {
103 SetDlgItemText(hwnd,
104 uID,
105 lpBuf);
106 }
107
108 HeapFree(GetProcessHeap(),
109 0,
110 lpBuf);
111 }
112 }
113
114 static INT
115 SetProcNameString(HWND hwnd,
116 HKEY hKey,
117 LPTSTR Value,
118 UINT uID1,
119 UINT uID2)
120 {
121 LPTSTR lpBuf = NULL;
122 DWORD BufSize = 0;
123 DWORD Type;
124 INT Ret = 0;
125 TCHAR szBuf[31];
126 TCHAR* szLastSpace;
127 INT LastSpace = 0;
128
129 if (RegQueryValueEx(hKey,
130 Value,
131 NULL,
132 &Type,
133 NULL,
134 &BufSize) == ERROR_SUCCESS)
135 {
136 lpBuf = HeapAlloc(GetProcessHeap(),
137 0,
138 BufSize);
139 if (!lpBuf) return 0;
140
141 if (RegQueryValueEx(hKey,
142 Value,
143 NULL,
144 &Type,
145 (PBYTE)lpBuf,
146 &BufSize) == ERROR_SUCCESS)
147 {
148 if(BufSize > ((30 + 1) * sizeof(TCHAR)))
149 {
150 /* Wrap the Processor Name String like XP does: *
151 * - Take the first 30 characters and look for the last space. *
152 * Then wrap the string after this space. *
153 * - If no space is found, wrap the string after character 30. *
154 * *
155 * For example the Processor Name String of a Pentium 4 is right-aligned. *
156 * With this wrapping the first line looks centered. */
157
158 _tcsncpy(szBuf, lpBuf, 30);
159 szBuf[30] = 0;
160 szLastSpace = _tcsrchr(szBuf, ' ');
161
162 if(szLastSpace == 0)
163 LastSpace = 30;
164 else
165 {
166 LastSpace = (szLastSpace - szBuf);
167 szBuf[LastSpace] = 0;
168 }
169
170 _tcsncpy(szBuf, lpBuf, LastSpace);
171
172 SetDlgItemText(hwnd,
173 uID1,
174 szBuf);
175
176 SetDlgItemText(hwnd,
177 uID2,
178 lpBuf+LastSpace+1);
179
180 /* Return the number of used lines */
181 Ret = 2;
182 }
183 else
184 {
185 SetDlgItemText(hwnd,
186 uID1,
187 lpBuf);
188
189 Ret = 1;
190 }
191 }
192
193 HeapFree(GetProcessHeap(),
194 0,
195 lpBuf);
196
197 return Ret;
198 }
199
200 return 0;
201 }
202
203 static VOID
204 SetProcSpeed(HWND hwnd,
205 HKEY hKey,
206 LPTSTR Value,
207 UINT uID)
208
209 {
210 TCHAR szBuf[64];
211 DWORD BufSize = sizeof(DWORD);
212 DWORD Type = REG_SZ;
213 PROCESSOR_POWER_INFORMATION ppi;
214
215 ZeroMemory(&ppi,
216 sizeof(ppi));
217
218 if ((CallNtPowerInformation(ProcessorInformation,
219 NULL,
220 0,
221 (PVOID)&ppi,
222 sizeof(ppi)) == STATUS_SUCCESS &&
223 ppi.CurrentMhz != 0) ||
224 RegQueryValueEx(hKey,
225 Value,
226 NULL,
227 &Type,
228 (PBYTE)&ppi.CurrentMhz,
229 &BufSize) == ERROR_SUCCESS)
230 {
231 if (ppi.CurrentMhz < 1000)
232 {
233 _stprintf(szBuf, _T("%lu MHz"), ppi.CurrentMhz);
234 }
235 else
236 {
237 double flt = ppi.CurrentMhz / 1000.0;
238 _stprintf(szBuf, _T("%.2f GHz"), flt);
239 }
240
241 SetDlgItemText(hwnd,
242 uID,
243 szBuf);
244 }
245 }
246
247 static VOID
248 GetSystemInformation(HWND hwnd)
249 {
250 HKEY hKey;
251 TCHAR ProcKey[] = _T("HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0");
252 MEMORYSTATUSEX MemStat;
253 TCHAR Buf[32];
254 INT Ret = 0;
255 INT CurMachineLine = IDC_MACHINELINE1;
256
257
258 /* Get Processor information *
259 * although undocumented, this information is being pulled
260 * directly out of the registry instead of via setupapi as it
261 * contains all the info we need, and should remain static
262 */
263 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
264 ProcKey,
265 0,
266 KEY_READ,
267 &hKey) == ERROR_SUCCESS)
268 {
269 SetRegTextData(hwnd,
270 hKey,
271 _T("VendorIdentifier"),
272 CurMachineLine);
273 CurMachineLine++;
274
275 Ret = SetProcNameString(hwnd,
276 hKey,
277 _T("ProcessorNameString"),
278 CurMachineLine,
279 CurMachineLine+1);
280 CurMachineLine += Ret;
281
282 SetProcSpeed(hwnd,
283 hKey,
284 _T("~MHz"),
285 CurMachineLine);
286 CurMachineLine++;
287 }
288
289
290 /* Get total physical RAM */
291 MemStat.dwLength = sizeof(MemStat);
292 if (GlobalMemoryStatusEx(&MemStat))
293 {
294 TCHAR szStr[32];
295 double dTotalPhys;
296 UINT i = 0;
297 static const UINT uStrId[] = {
298 IDS_MEGABYTE,
299 IDS_GIGABYTE,
300 IDS_TERABYTE,
301 IDS_PETABYTE
302 };
303
304 if (MemStat.ullTotalPhys > 1024 * 1024 * 1024)
305 {
306 /* We're dealing with GBs or more */
307 MemStat.ullTotalPhys /= 1024 * 1024;
308 i++;
309
310 if (MemStat.ullTotalPhys > 1024 * 1024)
311 {
312 /* We're dealing with TBs or more */
313 MemStat.ullTotalPhys /= 1024;
314 i++;
315
316 if (MemStat.ullTotalPhys > 1024 * 1024)
317 {
318 /* We're dealing with PBs or more */
319
320 MemStat.ullTotalPhys /= 1024;
321 i++;
322
323 dTotalPhys = (double)MemStat.ullTotalPhys / 1024;
324 }
325 else
326 dTotalPhys = (double)MemStat.ullTotalPhys / 1024;
327 }
328 else
329 dTotalPhys = (double)MemStat.ullTotalPhys / 1024;
330 }
331 else
332 {
333 /* We're daling with MBs */
334 dTotalPhys = (double)MemStat.ullTotalPhys / 1024 / 1024;
335 }
336
337 if (LoadString(hApplet, uStrId[i], szStr, sizeof(szStr) / sizeof(szStr[0])))
338 {
339 Ret = _stprintf(Buf, _T("%.2f %s"), dTotalPhys, szStr);
340 }
341 }
342
343 if (Ret)
344 {
345 SetDlgItemText(hwnd,
346 CurMachineLine,
347 Buf);
348 }
349 }
350
351
352 /* Property page dialog callback */
353 INT_PTR CALLBACK
354 GeneralPageProc(HWND hwndDlg,
355 UINT uMsg,
356 WPARAM wParam,
357 LPARAM lParam)
358 {
359 static IMGINFO ImgInfo;
360
361 UNREFERENCED_PARAMETER(lParam);
362 UNREFERENCED_PARAMETER(wParam);
363
364 switch(uMsg)
365 {
366 case WM_INITDIALOG:
367 {
368 InitImageInfo(&ImgInfo);
369 GetSystemInformation(hwndDlg);
370 }
371 break;
372
373 case WM_COMMAND:
374 {
375 if (LOWORD(wParam) == IDC_LICENCE)
376 {
377 DialogBox(hApplet,
378 MAKEINTRESOURCE(IDD_LICENCE),
379 hwndDlg,
380 LicenceDlgProc);
381
382 return TRUE;
383 }
384 }
385 break;
386
387 case WM_DRAWITEM:
388 {
389 LPDRAWITEMSTRUCT lpDrawItem;
390 lpDrawItem = (LPDRAWITEMSTRUCT) lParam;
391 if(lpDrawItem->CtlID == IDC_ROSIMG)
392 {
393 HDC hdcMem;
394 LONG left;
395
396 /* position image in centre of dialog */
397 left = (lpDrawItem->rcItem.right - ImgInfo.cxSource) / 2;
398
399 hdcMem = CreateCompatibleDC(lpDrawItem->hDC);
400 if (hdcMem != NULL)
401 {
402 SelectObject(hdcMem, ImgInfo.hBitmap);
403 BitBlt(lpDrawItem->hDC,
404 left,
405 lpDrawItem->rcItem.top,
406 lpDrawItem->rcItem.right - lpDrawItem->rcItem.left,
407 lpDrawItem->rcItem.bottom - lpDrawItem->rcItem.top,
408 hdcMem,
409 0,
410 0,
411 SRCCOPY);
412 DeleteDC(hdcMem);
413 }
414 }
415 return TRUE;
416 }
417
418 case WM_NOTIFY:
419 {
420 NMHDR *nmhdr = (NMHDR *)lParam;
421
422 if (nmhdr->idFrom == IDC_ROSHOMEPAGE_LINK && nmhdr->code == NM_CLICK)
423 {
424 PNMLINK nml = (PNMLINK)nmhdr;
425
426 ShellExecuteW(hwndDlg,
427 L"open",
428 nml->item.szUrl,
429 NULL,
430 NULL,
431 SW_SHOWNORMAL);
432 }
433 break;
434 }
435
436 }
437
438 return FALSE;
439 }
440
441
442
443
444