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