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 #include "precomp.h"
13
14 #include <winnls.h>
15 #include <powrprof.h>
16 #include <buildno.h>
17
18 #define ANIM_STEP 2
19 #define ANIM_TIME 50
20 #define ID_SYSUPTIME_UPDATE_TIMER 1
21
22 typedef struct _IMGINFO
23 {
24 HBITMAP hBitmap;
25 INT cxSource;
26 INT cySource;
27 INT iPlanes;
28 INT iBits;
29 } IMGINFO, *PIMGINFO;
30
31 typedef ULONGLONG (WINAPI *PFGETTICKCOUNT64)(VOID);
32
33 static PIMGINFO pImgInfo;
34 static const BLENDFUNCTION BlendFunc = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA};
35 static HMODULE hKernel32Vista = NULL;
36 static PFGETTICKCOUNT64 pGetTickCount64 = NULL;
37 static WCHAR szUptimeFormat[64];
38
ShowLastWin32Error(HWND hWndOwner)39 VOID ShowLastWin32Error(HWND hWndOwner)
40 {
41 LPTSTR lpMsg;
42 DWORD LastError;
43
44 LastError = GetLastError();
45 if (LastError == ERROR_SUCCESS)
46 return;
47
48 if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
49 FORMAT_MESSAGE_FROM_SYSTEM |
50 FORMAT_MESSAGE_IGNORE_INSERTS,
51 NULL,
52 LastError,
53 LANG_USER_DEFAULT,
54 (LPTSTR)&lpMsg,
55 0, NULL))
56 {
57 return;
58 }
59
60 MessageBox(hWndOwner, lpMsg, NULL, MB_OK | MB_ICONERROR);
61 LocalFree(lpMsg);
62 }
63
64
InitLogo(HWND hwndDlg)65 static VOID InitLogo(HWND hwndDlg)
66 {
67 BITMAP logoBitmap;
68 BITMAP maskBitmap;
69 BITMAPINFO bmpi;
70 HDC hDC, hDCLogo, hDCMask;
71 HBITMAP hMask = NULL, hLogo = NULL;
72 HBITMAP hAlphaLogo = NULL;
73 COLORREF *pBits;
74 INT line, column;
75
76 hDC = GetDC(hwndDlg);
77 hDCLogo = CreateCompatibleDC(NULL);
78 hDCMask = CreateCompatibleDC(NULL);
79
80 if (hDC == NULL || hDCLogo == NULL || hDCMask == NULL)
81 goto Cleanup;
82
83 ZeroMemory(pImgInfo, sizeof(*pImgInfo));
84 ZeroMemory(&bmpi, sizeof(bmpi));
85
86 hLogo = (HBITMAP)LoadImageW(hApplet, MAKEINTRESOURCEW(IDB_ROSBMP), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR);
87 hMask = (HBITMAP)LoadImageW(hApplet, MAKEINTRESOURCEW(IDB_ROSMASK), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR);
88
89 if (hLogo == NULL || hMask == NULL)
90 goto Cleanup;
91
92 GetObject(hLogo, sizeof(logoBitmap), &logoBitmap);
93 GetObject(hMask, sizeof(maskBitmap), &maskBitmap);
94
95 if (logoBitmap.bmHeight != maskBitmap.bmHeight || logoBitmap.bmWidth != maskBitmap.bmWidth)
96 goto Cleanup;
97
98 bmpi.bmiHeader.biSize = sizeof(BITMAPINFO);
99 bmpi.bmiHeader.biWidth = logoBitmap.bmWidth;
100 bmpi.bmiHeader.biHeight = logoBitmap.bmHeight;
101 bmpi.bmiHeader.biPlanes = 1;
102 bmpi.bmiHeader.biBitCount = 32;
103 bmpi.bmiHeader.biCompression = BI_RGB;
104 bmpi.bmiHeader.biSizeImage = 4 * logoBitmap.bmWidth * logoBitmap.bmHeight;
105
106 /* Create a premultiplied bitmap */
107 hAlphaLogo = CreateDIBSection(hDC, &bmpi, DIB_RGB_COLORS, (PVOID*)&pBits, 0, 0);
108 if (!hAlphaLogo)
109 goto Cleanup;
110
111 SelectObject(hDCLogo, hLogo);
112 SelectObject(hDCMask, hMask);
113
114 for (line = logoBitmap.bmHeight - 1; line >= 0; line--)
115 {
116 for (column = 0; column < logoBitmap.bmWidth; column++)
117 {
118 COLORREF alpha = GetPixel(hDCMask, column, line) & 0xFF;
119 COLORREF Color = GetPixel(hDCLogo, column, line);
120 DWORD r, g, b;
121
122 r = GetRValue(Color) * alpha / 255;
123 g = GetGValue(Color) * alpha / 255;
124 b = GetBValue(Color) * alpha / 255;
125
126 *pBits++ = b | (g << 8) | (r << 16) | (alpha << 24);
127 }
128 }
129
130 pImgInfo->hBitmap = hAlphaLogo;
131 pImgInfo->cxSource = logoBitmap.bmWidth;
132 pImgInfo->cySource = logoBitmap.bmHeight;
133 pImgInfo->iBits = logoBitmap.bmBitsPixel;
134 pImgInfo->iPlanes = logoBitmap.bmPlanes;
135
136 Cleanup:
137 if (hMask != NULL) DeleteObject(hMask);
138 if (hLogo != NULL) DeleteObject(hLogo);
139 if (hDCMask != NULL) DeleteDC(hDCMask);
140 if (hDCLogo != NULL) DeleteDC(hDCLogo);
141 if (hDC != NULL) ReleaseDC(hwndDlg, hDC);
142 }
143
RosImageProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)144 LRESULT CALLBACK RosImageProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
145 {
146 static UINT timerid = 0, top = 0, offset;
147 static HBITMAP hCreditsBitmap;
148
149 switch (uMsg)
150 {
151 case WM_LBUTTONDBLCLK:
152 if (wParam & (MK_CONTROL | MK_SHIFT))
153 {
154 if (timerid == 0)
155 {
156 HDC hDC;
157 HDC hCreditsDC = NULL, hLogoDC = NULL;
158 HFONT hFont = NULL;
159 NONCLIENTMETRICS ncm;
160 RECT rcCredits;
161 TCHAR szCredits[2048];
162 INT iDevsHeight;
163
164 hDC = GetDC(NULL);
165 if (hDC == NULL)
166 goto Cleanup;
167
168 top = 0;
169 offset = 0;
170
171 hCreditsDC = CreateCompatibleDC(hDC);
172 hLogoDC = CreateCompatibleDC(hCreditsDC);
173
174 if (hCreditsDC == NULL || hLogoDC == NULL)
175 goto Cleanup;
176
177 SetRect(&rcCredits, 0, 0, 0, 0);
178
179 ncm.cbSize = sizeof(NONCLIENTMETRICS);
180 SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, 0);
181
182 hFont = CreateFontIndirect(&ncm.lfMessageFont);
183 if (!hFont)
184 goto Cleanup;
185 SelectObject(hCreditsDC, hFont);
186
187 LoadString(hApplet, IDS_DEVS, szCredits, sizeof(szCredits) / sizeof(TCHAR));
188 DrawText(hCreditsDC, szCredits, -1, &rcCredits, DT_CALCRECT);
189
190 iDevsHeight = rcCredits.bottom - rcCredits.top;
191
192 hCreditsBitmap = CreateBitmap(pImgInfo->cxSource, (2 * pImgInfo->cySource) + iDevsHeight + 1, pImgInfo->iPlanes, pImgInfo->iBits, NULL);
193 if (!hCreditsBitmap)
194 goto Cleanup;
195
196 SelectObject(hLogoDC, pImgInfo->hBitmap);
197 SelectObject(hCreditsDC, hCreditsBitmap);
198
199 offset += pImgInfo->cySource;
200
201 SetRect(&rcCredits, 0, 0, pImgInfo->cxSource, (2 * pImgInfo->cySource) + iDevsHeight + 1);
202 FillRect(hCreditsDC, &rcCredits, GetSysColorBrush(COLOR_3DFACE));
203
204 SetRect(&rcCredits, 0, offset, pImgInfo->cxSource, offset + iDevsHeight + 1);
205 SetBkMode(hCreditsDC, TRANSPARENT);
206
207 OffsetRect(&rcCredits, 1, 1);
208 SetTextColor(hCreditsDC, GetSysColor(COLOR_BTNSHADOW));
209 DrawText(hCreditsDC, szCredits, -1, &rcCredits, DT_CENTER);
210
211 OffsetRect(&rcCredits, -1, -1);
212 SetTextColor(hCreditsDC, GetSysColor(COLOR_WINDOWTEXT));
213 DrawText(hCreditsDC, szCredits, -1, &rcCredits, DT_CENTER);
214
215 offset += iDevsHeight;
216
217 AlphaBlend(hCreditsDC, 0, 0, pImgInfo->cxSource, pImgInfo->cySource, hLogoDC, 0, 0, pImgInfo->cxSource, pImgInfo->cySource, BlendFunc);
218 AlphaBlend(hCreditsDC, 0, offset, pImgInfo->cxSource, pImgInfo->cySource, hLogoDC, 0, 0, pImgInfo->cxSource, pImgInfo->cySource, BlendFunc);
219
220 timerid = SetTimer(hwnd, 1, ANIM_TIME, NULL);
221
222 Cleanup:
223 if (hFont != NULL) DeleteObject(hFont);
224 if (hLogoDC != NULL) DeleteDC(hLogoDC);
225 if (hCreditsDC != NULL) DeleteDC(hCreditsDC);
226 if (hDC != NULL) ReleaseDC(NULL, hDC);
227 }
228 }
229 break;
230 case WM_LBUTTONDOWN:
231 if (timerid)
232 {
233 RECT rcCredits;
234 HDC hDC = GetDC(hwnd);
235 if (hDC != NULL)
236 {
237 GetClientRect(hwnd, &rcCredits);
238 SetRect(&rcCredits, 0, 0, rcCredits.right, pImgInfo->cySource);
239 FillRect(hDC, &rcCredits, GetSysColorBrush(COLOR_3DFACE));
240 ReleaseDC(hwnd, hDC);
241 }
242 KillTimer(hwnd, timerid);
243 if (hCreditsBitmap != NULL)
244 DeleteObject(hCreditsBitmap);
245
246 InvalidateRect(hwnd, NULL, FALSE);
247 top = 0;
248 timerid = 0;
249 }
250 break;
251 case WM_TIMER:
252 top += ANIM_STEP;
253
254 if (top > offset)
255 {
256 RECT rcCredits;
257 HDC hDC = GetDC(hwnd);
258 if (hDC != NULL)
259 {
260 GetClientRect(hwnd, &rcCredits);
261 SetRect(&rcCredits, 0, 0, rcCredits.right, pImgInfo->cySource);
262 FillRect(hDC, &rcCredits, GetSysColorBrush(COLOR_3DFACE));
263 ReleaseDC(hwnd, hDC);
264 }
265 KillTimer(hwnd, timerid);
266 if (hCreditsBitmap != NULL)
267 DeleteObject(hCreditsBitmap);
268
269 top = 0;
270 timerid = 0;
271 }
272
273 InvalidateRect(hwnd, NULL, FALSE);
274 break;
275 case WM_PAINT:
276 {
277 PAINTSTRUCT PS;
278 HDC hdcMem, hdc;
279 LONG left;
280
281 hdc = wParam != 0 ? (HDC)wParam : BeginPaint(hwnd, &PS);
282
283 GetClientRect(hwnd, &PS.rcPaint);
284
285 /* Position image in center of dialog */
286 left = (PS.rcPaint.right - pImgInfo->cxSource) / 2;
287 hdcMem = CreateCompatibleDC(hdc);
288
289 if (hdcMem != NULL)
290 {
291 if(timerid != 0)
292 {
293 SelectObject(hdcMem, hCreditsBitmap);
294 BitBlt(hdc, left, PS.rcPaint.top, PS.rcPaint.right - PS.rcPaint.left, PS.rcPaint.top + pImgInfo->cySource, hdcMem, 0, top, SRCCOPY);
295 }
296 else
297 {
298 SelectObject(hdcMem, pImgInfo->hBitmap);
299 AlphaBlend(hdc, left, PS.rcPaint.top, pImgInfo->cxSource, pImgInfo->cySource, hdcMem, 0, 0, pImgInfo->cxSource, pImgInfo->cySource, BlendFunc);
300 }
301
302 DeleteDC(hdcMem);
303 }
304
305 if (wParam == 0)
306 EndPaint(hwnd,&PS);
307 break;
308 }
309 }
310 return TRUE;
311 }
312
SetRegTextData(HWND hwnd,HKEY hKey,LPTSTR Value,UINT uID)313 static VOID SetRegTextData(HWND hwnd, HKEY hKey, LPTSTR Value, UINT uID)
314 {
315 LPTSTR lpBuf = NULL;
316 DWORD BufSize = 0;
317 DWORD Type;
318
319 if (RegQueryValueEx(hKey, Value, NULL, &Type, NULL, &BufSize) == ERROR_SUCCESS)
320 {
321 lpBuf = HeapAlloc(GetProcessHeap(), 0, BufSize);
322
323 if (!lpBuf)
324 return;
325
326 if (RegQueryValueEx(hKey, Value, NULL, &Type, (PBYTE)lpBuf, &BufSize) == ERROR_SUCCESS)
327 SetDlgItemText(hwnd, uID, lpBuf);
328
329 HeapFree(GetProcessHeap(), 0, lpBuf);
330 }
331 }
332
SetProcNameString(HWND hwnd,HKEY hKey,LPTSTR Value,UINT uID1,UINT uID2)333 static INT SetProcNameString(HWND hwnd, HKEY hKey, LPTSTR Value, UINT uID1, UINT uID2)
334 {
335 LPTSTR lpBuf = NULL;
336 DWORD BufSize = 0;
337 DWORD Type;
338 INT Ret = 0;
339 TCHAR szBuf[31];
340 TCHAR* szLastSpace;
341 INT LastSpace = 0;
342
343 if (RegQueryValueEx(hKey, Value, NULL, &Type, NULL, &BufSize) == ERROR_SUCCESS)
344 {
345 lpBuf = HeapAlloc(GetProcessHeap(), 0, BufSize);
346
347 if (!lpBuf)
348 return 0;
349
350 if (RegQueryValueEx(hKey, Value, NULL, &Type, (PBYTE)lpBuf, &BufSize) == ERROR_SUCCESS)
351 {
352 if (BufSize > ((30 + 1) * sizeof(TCHAR)))
353 {
354 /* Wrap the Processor Name String like XP does: *
355 * - Take the first 30 characters and look for the last space. *
356 * Then wrap the string after this space. *
357 * - If no space is found, wrap the string after character 30. *
358 * *
359 * For example the Processor Name String of a Pentium 4 is right-aligned. *
360 * With this wrapping the first line looks centered. */
361
362 _tcsncpy(szBuf, lpBuf, 30);
363 szBuf[30] = 0;
364 szLastSpace = _tcsrchr(szBuf, ' ');
365
366 if (szLastSpace == 0)
367 {
368 LastSpace = 30;
369 }
370 else
371 {
372 LastSpace = (szLastSpace - szBuf);
373 szBuf[LastSpace] = 0;
374 }
375
376 _tcsncpy(szBuf, lpBuf, LastSpace);
377
378 SetDlgItemText(hwnd, uID1, szBuf);
379 SetDlgItemText(hwnd, uID2, lpBuf+LastSpace+1);
380
381 /* Return the number of used lines */
382 Ret = 2;
383 }
384 else
385 {
386 SetDlgItemText(hwnd, uID1, lpBuf);
387 Ret = 1;
388 }
389 }
390
391 HeapFree(GetProcessHeap(), 0, lpBuf);
392 }
393
394 return Ret;
395 }
396
MakeFloatValueString(DOUBLE * dFloatValue,LPTSTR szOutput,LPTSTR szAppend)397 static VOID MakeFloatValueString(DOUBLE* dFloatValue, LPTSTR szOutput, LPTSTR szAppend)
398 {
399 TCHAR szDecimalSeparator[4];
400
401 /* Get the decimal separator for the current locale */
402 if (GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, szDecimalSeparator, sizeof(szDecimalSeparator) / sizeof(TCHAR)) > 0)
403 {
404 UCHAR uDecimals;
405 UINT uIntegral;
406
407 /* Show the value with two decimals */
408 uIntegral = (UINT)*dFloatValue;
409 uDecimals = (UCHAR)((UINT)(*dFloatValue * 100) - uIntegral * 100);
410
411 wsprintf(szOutput, _T("%u%s%02u %s"), uIntegral, szDecimalSeparator, uDecimals, szAppend);
412 }
413 }
414
SetProcSpeed(HWND hwnd,HKEY hKey,LPTSTR Value,UINT uID)415 static BOOL SetProcSpeed(HWND hwnd, HKEY hKey, LPTSTR Value, UINT uID)
416 {
417 TCHAR szBuf[64], szHz[16];
418 DWORD BufSize = sizeof(DWORD);
419 DWORD Type = REG_SZ;
420 PROCESSOR_POWER_INFORMATION ppi;
421
422 ZeroMemory(&ppi, sizeof(ppi));
423
424 if ((CallNtPowerInformation(ProcessorInformation,
425 NULL,
426 0,
427 (PVOID)&ppi,
428 sizeof(ppi)) == STATUS_SUCCESS &&
429 ppi.CurrentMhz != 0) || RegQueryValueEx(hKey, Value, NULL, &Type, (PBYTE)&ppi.CurrentMhz, &BufSize) == ERROR_SUCCESS)
430 {
431 if (ppi.CurrentMhz < 1000)
432 {
433 if (!LoadString(hApplet, IDS_MEGAHERTZ, szHz, _countof(szHz)))
434 {
435 return FALSE;
436 }
437 StringCchPrintf(szBuf, _countof(szBuf), _T("%lu %s"), ppi.CurrentMhz, szHz);
438 }
439 else
440 {
441 double flt = ppi.CurrentMhz / 1000.0;
442 if (!LoadString(hApplet, IDS_GIGAHERTZ, szHz, _countof(szHz)))
443 {
444 return FALSE;
445 }
446 MakeFloatValueString(&flt, szBuf, szHz);
447 }
448
449 SetDlgItemText(hwnd, uID, szBuf);
450 return TRUE;
451 }
452
453 return FALSE;
454 }
455
GetSystemInformation(HWND hwnd)456 static VOID GetSystemInformation(HWND hwnd)
457 {
458 HKEY hKey;
459 TCHAR SysKey[] = _T("HARDWARE\\DESCRIPTION\\System");
460 TCHAR ProcKey[] = _T("HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0");
461 MEMORYSTATUSEX MemStat;
462 TCHAR Buf[32];
463 WCHAR SMBiosName[96];
464 INT CurMachineLine = IDC_MACHINELINE1;
465
466 /*
467 * Get hardware device name or motherboard name
468 * using information from raw SMBIOS data
469 */
470 if (GetSystemName(SMBiosName, _countof(SMBiosName)))
471 {
472 SetDlgItemText(hwnd, CurMachineLine, SMBiosName);
473 CurMachineLine++;
474 }
475 else
476 {
477 /* If SMBIOS is not available, use System Identifier */
478 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, SysKey, 0, KEY_READ, &hKey) == ERROR_SUCCESS)
479 {
480 SetRegTextData(hwnd, hKey, _T("Identifier"), CurMachineLine);
481 CurMachineLine++;
482 RegCloseKey(hKey);
483 }
484 }
485 /*
486 * Get Processor information
487 * although undocumented, this information is being pulled
488 * directly out of the registry instead of via setupapi as it
489 * contains all the info we need, and should remain static
490 */
491 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, ProcKey, 0, KEY_READ, &hKey) == ERROR_SUCCESS)
492 {
493 INT PrevMachineLine;
494
495 SetRegTextData(hwnd, hKey, _T("VendorIdentifier"), CurMachineLine);
496 CurMachineLine++;
497
498 PrevMachineLine = CurMachineLine;
499 CurMachineLine += SetProcNameString(hwnd,
500 hKey,
501 _T("ProcessorNameString"),
502 CurMachineLine,
503 CurMachineLine + 1);
504
505 if (CurMachineLine == PrevMachineLine)
506 {
507 /* TODO: Try obtaining CPU name from WMI (i.e. CIM_Processor) */
508
509 /* Brand String is not available, use Identifier instead */
510 CurMachineLine += SetProcNameString(hwnd,
511 hKey,
512 _T("Identifier"),
513 CurMachineLine,
514 CurMachineLine + 1);
515 }
516
517 if (SetProcSpeed(hwnd, hKey, _T("~MHz"), CurMachineLine))
518 CurMachineLine++;
519 RegCloseKey(hKey);
520 }
521
522 /* Get total physical RAM */
523 MemStat.dwLength = sizeof(MemStat);
524
525 if (GlobalMemoryStatusEx(&MemStat))
526 {
527 TCHAR szStr[32];
528 double dTotalPhys;
529
530 if (MemStat.ullTotalPhys > 1024 * 1024 * 1024)
531 {
532 UINT i = 0;
533 static const UINT uStrId[] = { IDS_GIGABYTE, IDS_TERABYTE, IDS_PETABYTE};
534
535 // We're dealing with GBs or more
536 MemStat.ullTotalPhys /= 1024 * 1024;
537
538 if (MemStat.ullTotalPhys > 1024 * 1024)
539 {
540 // We're dealing with TBs or more
541 MemStat.ullTotalPhys /= 1024;
542 i++;
543
544 if (MemStat.ullTotalPhys > 1024 * 1024)
545 {
546 // We're dealing with PBs or more
547 MemStat.ullTotalPhys /= 1024;
548 i++;
549
550 dTotalPhys = (double)MemStat.ullTotalPhys / 1024;
551 }
552 else
553 {
554 dTotalPhys = (double)MemStat.ullTotalPhys / 1024;
555 }
556 }
557 else
558 {
559 dTotalPhys = (double)MemStat.ullTotalPhys / 1024;
560 }
561
562 LoadString(hApplet, uStrId[i], szStr, sizeof(szStr) / sizeof(TCHAR));
563 MakeFloatValueString(&dTotalPhys, Buf, szStr);
564 }
565 else
566 {
567 // We're dealing with MBs, don't show any decimals
568 LoadString(hApplet, IDS_MEGABYTE, szStr, sizeof(szStr) / sizeof(TCHAR));
569 wsprintf(Buf, _T("%u %s"), (UINT)MemStat.ullTotalPhys / 1024 / 1024, szStr);
570 }
571
572 SetDlgItemText(hwnd, CurMachineLine, Buf);
573 }
574 }
575
GetSystemVersion(HWND hwnd)576 static VOID GetSystemVersion(HWND hwnd)
577 {
578 HWND hRosVersion;
579 SIZE_T lenStr, lenVersion;
580 PCWSTR pwszVersion = L" " TEXT(KERNEL_VERSION_RC);
581 PWSTR pwszStr;
582
583 lenVersion = wcslen(pwszVersion);
584 if (lenVersion == 0)
585 {
586 return;
587 }
588
589 hRosVersion = GetDlgItem(hwnd, IDC_ROSVERSION);
590 if (!hRosVersion)
591 {
592 return;
593 }
594 lenStr = GetWindowTextLengthW(hRosVersion);
595 lenStr += lenVersion + 1;
596 pwszStr = HeapAlloc(GetProcessHeap(), 0, lenStr * sizeof(WCHAR));
597 if (!pwszStr)
598 {
599 return;
600 }
601 GetWindowText(hRosVersion, pwszStr, lenStr);
602
603 StringCchCatW(pwszStr, lenStr, pwszVersion);
604 SetWindowText(hRosVersion, pwszStr);
605
606 HeapFree(GetProcessHeap(), 0, pwszStr);
607 }
608
609 /**
610 * @brief
611 * An equivalent of GetTickCount64, implemented using QueryPerformanceCounter.
612 *
613 * @return
614 * The number of milliseconds that have elapsed since the system was started.
615 */
GetTickCountQPC(VOID)616 static ULONGLONG GetTickCountQPC(VOID)
617 {
618 LARGE_INTEGER Counter, Frequency;
619
620 QueryPerformanceCounter(&Counter);
621 QueryPerformanceFrequency(&Frequency);
622
623 return (Counter.QuadPart * 1000) / Frequency.QuadPart;
624 }
625
GetSystemUptime(HWND hwndDlg)626 static VOID GetSystemUptime(HWND hwndDlg)
627 {
628 HWND hUptimeLabel;
629 ULONGLONG cMilliseconds;
630 ULONG cSeconds;
631 WCHAR szBuf[64];
632
633 hUptimeLabel = GetDlgItem(hwndDlg, IDC_UPTIME);
634 if (!hUptimeLabel)
635 {
636 return;
637 }
638
639 if (pGetTickCount64)
640 {
641 cMilliseconds = pGetTickCount64();
642 }
643 else
644 {
645 cMilliseconds = GetTickCountQPC();
646 }
647
648 cSeconds = cMilliseconds / 1000;
649 StringCchPrintfW(szBuf, _countof(szBuf), szUptimeFormat,
650 cSeconds / (60*60*24), // Days
651 (cSeconds / (60*60)) % 24, // Hours
652 (cSeconds / 60) % 60, // Minutes
653 cSeconds % 60); // Seconds
654
655 SetWindowTextW(hUptimeLabel, szBuf);
656
657 /* Set update timer (reset timeout if the timer exists) */
658 SetTimer(hwndDlg, ID_SYSUPTIME_UPDATE_TIMER, 1000 - (cMilliseconds % 1000), NULL);
659 }
660
InitSystemUptime(HWND hwndDlg)661 static VOID InitSystemUptime(HWND hwndDlg)
662 {
663 HMODULE hKernel32;
664
665 /* Load time format string */
666 if (LoadStringW(hApplet, IDS_UPTIME_FORMAT, szUptimeFormat, _countof(szUptimeFormat)) == 0)
667 {
668 return;
669 }
670
671 /* Load required DLLs */
672 hKernel32 = GetModuleHandleW(L"kernel32.dll");
673 if (hKernel32)
674 {
675 pGetTickCount64 = (PFGETTICKCOUNT64)GetProcAddress(hKernel32, "GetTickCount64");
676 if (!pGetTickCount64)
677 {
678 hKernel32Vista = LoadLibraryW(L"kernel32_vista.dll");
679 if (hKernel32Vista)
680 {
681 pGetTickCount64 = (PFGETTICKCOUNT64)GetProcAddress(hKernel32Vista, "GetTickCount64");
682 }
683 }
684 }
685
686 /* Show system uptime and set update timer */
687 GetSystemUptime(hwndDlg);
688 }
689
690 /* Property page dialog callback */
GeneralPageProc(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam)691 INT_PTR CALLBACK GeneralPageProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
692 {
693 UNREFERENCED_PARAMETER(lParam);
694 UNREFERENCED_PARAMETER(wParam);
695
696 switch (uMsg)
697 {
698 case WM_INITDIALOG:
699 {
700 pImgInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IMGINFO));
701 if (pImgInfo == NULL)
702 {
703 EndDialog(hwndDlg, 0);
704 return FALSE;
705 }
706
707 InitLogo(hwndDlg);
708 SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_ROSIMG), GWLP_WNDPROC, (LONG_PTR)RosImageProc);
709 GetSystemInformation(hwndDlg);
710 GetSystemVersion(hwndDlg);
711 InitSystemUptime(hwndDlg);
712 break;
713 }
714
715 case WM_DESTROY:
716 {
717 KillTimer(hwndDlg, ID_SYSUPTIME_UPDATE_TIMER);
718
719 if (hKernel32Vista)
720 {
721 FreeLibrary(hKernel32Vista);
722 }
723
724 HeapFree(GetProcessHeap(), 0, pImgInfo);
725 break;
726 }
727
728 case WM_TIMER:
729 {
730 if (wParam == ID_SYSUPTIME_UPDATE_TIMER)
731 {
732 /* Update system uptime */
733 GetSystemUptime(hwndDlg);
734 }
735
736 break;
737 }
738
739 case WM_COMMAND:
740 {
741 if (LOWORD(wParam) == IDC_LICENCE)
742 {
743 DialogBox(hApplet, MAKEINTRESOURCE(IDD_LICENCE), hwndDlg, LicenceDlgProc);
744
745 return TRUE;
746 }
747 break;
748 }
749
750 case WM_DRAWITEM:
751 {
752 LPDRAWITEMSTRUCT lpDrawItem = (LPDRAWITEMSTRUCT)lParam;
753
754 if (lpDrawItem->CtlID == IDC_ROSIMG)
755 {
756 HDC hdcMem;
757 LONG left;
758
759 /* Position image in centre of dialog */
760 left = (lpDrawItem->rcItem.right - pImgInfo->cxSource) / 2;
761
762 hdcMem = CreateCompatibleDC(lpDrawItem->hDC);
763 if (hdcMem != NULL)
764 {
765 SelectObject(hdcMem, pImgInfo->hBitmap);
766 BitBlt(lpDrawItem->hDC,
767 left,
768 lpDrawItem->rcItem.top,
769 lpDrawItem->rcItem.right - lpDrawItem->rcItem.left,
770 lpDrawItem->rcItem.bottom - lpDrawItem->rcItem.top,
771 hdcMem,
772 0,
773 0,
774 SRCCOPY);
775 DeleteDC(hdcMem);
776 }
777 }
778 return TRUE;
779 }
780
781 case WM_NOTIFY:
782 {
783 NMHDR *nmhdr = (NMHDR *)lParam;
784
785 if (nmhdr->idFrom == IDC_ROSHOMEPAGE_LINK && nmhdr->code == NM_CLICK)
786 {
787 PNMLINK nml = (PNMLINK)nmhdr;
788
789 ShellExecuteW(hwndDlg, L"open", nml->item.szUrl, NULL, NULL, SW_SHOWNORMAL);
790 }
791 break;
792 }
793
794 }
795
796 return FALSE;
797 }
798