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