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