1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS Display Control Panel 4 * FILE: dll/cpl/desk/devsett.c 5 * PURPOSE: ReactOS Display Control Panel Shell Extension Support 6 */ 7 8 #include "desk.h" 9 10 #include <cfgmgr32.h> 11 12 #define NDEBUG 13 #include <debug.h> 14 15 #define DEBUG_DEVSETTINGS 16 17 typedef struct _CDevSettings 18 { 19 const struct IDataObjectVtbl *lpIDataObjectVtbl; 20 DWORD ref; 21 22 CLIPFORMAT cfExtInterface; /* "Desk.cpl extension interface" */ 23 CLIPFORMAT cfDisplayDevice; /* "Display Device" */ 24 CLIPFORMAT cfDisplayName; /* "Display Name" */ 25 CLIPFORMAT cfDisplayId; /* "Display ID" */ 26 CLIPFORMAT cfMonitorName; /* "Monitor Name" */ 27 CLIPFORMAT cfMonitorDevice; /* "Monitor Device" */ 28 CLIPFORMAT cfDisplayKey; /* "Display Key" */ 29 CLIPFORMAT cfDisplayStateFlags; /* "Display State Flags" */ 30 CLIPFORMAT cfPruningMode; /* "Pruning Mode" */ 31 32 PWSTR pDisplayDevice; 33 PWSTR pDisplayName; 34 PWSTR pDisplayKey; 35 PWSTR pDisplayId; 36 PWSTR pMonitorName; 37 PWSTR pMonitorDevice; 38 39 DESK_EXT_INTERFACE ExtInterface; 40 41 PDEVMODEW lpOrigDevMode; 42 PDEVMODEW lpCurDevMode; 43 PDEVMODEW * DevModes; 44 DWORD nDevModes; 45 DWORD StateFlags; 46 47 union 48 { 49 DWORD Flags; 50 struct 51 { 52 DWORD bModesPruned : 1; 53 DWORD bKeyIsReadOnly : 1; 54 DWORD bPruningOn : 1; 55 }; 56 }; 57 } CDevSettings, *PCDevSettings; 58 59 #define impl_to_interface(impl,iface) (struct iface *)(&(impl)->lp##iface##Vtbl) 60 61 static __inline PCDevSettings 62 impl_from_IDataObject(struct IDataObject *iface) 63 { 64 return (PCDevSettings)((ULONG_PTR)iface - FIELD_OFFSET(CDevSettings, 65 lpIDataObjectVtbl)); 66 } 67 68 static __inline VOID 69 pCDevSettings_FreeString(PWCHAR *psz) 70 { 71 if (*psz != NULL) 72 { 73 LocalFree((HLOCAL)*psz); 74 *psz = NULL; 75 } 76 } 77 78 static PWSTR 79 pCDevSettings_AllocAndCopyString(const TCHAR *pszSrc) 80 { 81 SIZE_T c; 82 PWSTR str; 83 84 c = _tcslen(pszSrc) + 1; 85 str = (PWSTR)LocalAlloc(LMEM_FIXED, 86 c * sizeof(WCHAR)); 87 if (str != NULL) 88 { 89 #ifdef UNICODE 90 StringCbCopyW(str, c * sizeof(WCHAR), 91 pszSrc); 92 #else 93 MultiByteToWideChar(CP_ACP, 94 0, 95 pszSrc, 96 -1, 97 str, 98 c); 99 #endif 100 } 101 102 return str; 103 } 104 105 static PWSTR 106 pCDevSettings_GetMonitorName(const WCHAR *pszDisplayDevice) 107 { 108 DISPLAY_DEVICEW dd, dd2; 109 PWSTR str = NULL; 110 111 dd.cb = sizeof(dd); 112 if (EnumDisplayDevicesW(pszDisplayDevice, 113 0, 114 &dd, 115 0)) 116 { 117 dd2.cb = sizeof(dd2); 118 if (EnumDisplayDevicesW(pszDisplayDevice, 119 1, 120 &dd2, 121 0)) 122 { 123 /* There's more than one monitor connected... */ 124 LoadStringW(hApplet, 125 IDS_MULTIPLEMONITORS, 126 dd.DeviceString, 127 sizeof(dd.DeviceString) / sizeof(dd.DeviceString[0])); 128 } 129 } 130 else 131 { 132 /* We can't enumerate a monitor, make sure this fact is reported 133 to the user! */ 134 LoadStringW(hApplet, 135 IDS_UNKNOWNMONITOR, 136 dd.DeviceString, 137 sizeof(dd.DeviceString) / sizeof(dd.DeviceString[0])); 138 } 139 140 str = LocalAlloc(LMEM_FIXED, 141 (wcslen(dd.DeviceString) + 1) * sizeof(WCHAR)); 142 if (str != NULL) 143 { 144 wcscpy(str, 145 dd.DeviceString); 146 } 147 148 return str; 149 } 150 151 static PWSTR 152 pCDevSettings_GetMonitorDevice(const WCHAR *pszDisplayDevice) 153 { 154 DISPLAY_DEVICEW dd; 155 PWSTR str = NULL; 156 157 dd.cb = sizeof(dd); 158 if (EnumDisplayDevicesW(pszDisplayDevice, 159 0, 160 &dd, 161 0)) 162 { 163 str = LocalAlloc(LMEM_FIXED, 164 (wcslen(dd.DeviceName) + 1) * sizeof(WCHAR)); 165 if (str != NULL) 166 { 167 wcscpy(str, 168 dd.DeviceName); 169 } 170 } 171 172 return str; 173 } 174 175 /** 176 * @brief 177 * Converts a Hardware ID (DeviceID from EnumDisplayDevices) 178 * to an unique Device Instance ID. 179 * 180 * @param[in] pszDevice 181 * A pointer to a null-terminated Unicode string 182 * containing a Hardware ID. 183 * e.g. "PCI\VEN_80EE&DEV_BEEF&SUBSYS_00000000&REV_00" 184 * 185 * @return 186 * A pointer to a null-terminated Unicode string 187 * containing an unique Device Instance ID 188 * or NULL in case of error. 189 * e.g. "PCI\VEN_80EE&DEV_BEEF&SUBSYS_00000000&REV_00\3&267A616A&0&10" 190 * 191 * @remarks 192 * The caller must free the returned string with LocalFree. 193 */ 194 static PWSTR 195 pCDevSettings_GetDeviceInstanceId(const WCHAR *pszDevice) 196 { 197 HDEVINFO DevInfo; 198 SP_DEVINFO_DATA InfoData; 199 ULONG BufLen; 200 LPWSTR lpDevInstId = NULL; 201 202 DPRINT("CDevSettings::GetDeviceInstanceId(%ws)!\n", pszDevice); 203 204 DevInfo = SetupDiGetClassDevsW(NULL, pszDevice, NULL, DIGCF_ALLCLASSES | DIGCF_PRESENT); 205 if (DevInfo == INVALID_HANDLE_VALUE) 206 { 207 DPRINT1("SetupDiGetClassDevsW(\"%ws\") failed: %d\n", pszDevice, GetLastError()); 208 return NULL; 209 } 210 211 ZeroMemory(&InfoData, sizeof(InfoData)); 212 InfoData.cbSize = sizeof(InfoData); 213 214 /* Try to enumerate the first matching device */ 215 if (!SetupDiEnumDeviceInfo(DevInfo, 0, &InfoData)) 216 { 217 DPRINT1("SetupDiEnumDeviceInfo failed: %d\n", GetLastError()); 218 return NULL; 219 } 220 221 if (SetupDiGetDeviceInstanceId(DevInfo, &InfoData, NULL, 0, &BufLen) || 222 GetLastError() != ERROR_INSUFFICIENT_BUFFER) 223 { 224 DPRINT1("SetupDiGetDeviceInstanceId failed: %d\n", GetLastError()); 225 return NULL; 226 } 227 228 lpDevInstId = LocalAlloc(LMEM_FIXED, 229 (BufLen + 1) * sizeof(WCHAR)); 230 231 if (lpDevInstId == NULL) 232 { 233 DPRINT1("LocalAlloc failed\n"); 234 return NULL; 235 } 236 237 if (!SetupDiGetDeviceInstanceId(DevInfo, &InfoData, lpDevInstId, BufLen, NULL)) 238 { 239 DPRINT1("SetupDiGetDeviceInstanceId failed: %d\n", GetLastError()); 240 LocalFree((HLOCAL)lpDevInstId); 241 lpDevInstId = NULL; 242 } 243 else 244 { 245 DPRINT("instance id: %ws\n", lpDevInstId); 246 } 247 248 return lpDevInstId; 249 } 250 251 252 static HKEY 253 pCDevSettings_OpenDeviceKey(PCDevSettings This, 254 BOOL ReadOnly) 255 { 256 static const WCHAR szRegPrefix[] = L"\\Registry\\Machine\\"; 257 PWSTR lpRegKey; 258 REGSAM Access = KEY_READ; 259 HKEY hKey; 260 261 lpRegKey = This->pDisplayKey; 262 if (lpRegKey != NULL) 263 { 264 if (wcslen(lpRegKey) >= wcslen(szRegPrefix) && 265 !_wcsnicmp(lpRegKey, 266 szRegPrefix, 267 wcslen(szRegPrefix))) 268 { 269 lpRegKey += wcslen(szRegPrefix); 270 } 271 272 if (!ReadOnly) 273 Access |= KEY_WRITE; 274 275 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, 276 lpRegKey, 277 0, 278 Access, 279 &hKey) == ERROR_SUCCESS) 280 { 281 return hKey; 282 } 283 } 284 285 return NULL; 286 } 287 288 PDEVMODEW DESK_EXT_CALLBACK 289 CDevSettings_EnumAllModes(PVOID Context, 290 DWORD Index) 291 { 292 PCDevSettings This = impl_from_IDataObject((IDataObject *)Context); 293 DWORD i, idx = 0; 294 295 DPRINT1("CDevSettings::EnumAllModes(%u)\n", Index); 296 297 if (!This->DevModes) 298 return NULL; 299 300 for (i = 0; i < This->nDevModes; i++) 301 { 302 /* FIXME: Add more sanity checks */ 303 if (!This->DevModes[i]) 304 continue; 305 306 if (idx == Index) 307 return This->DevModes[i]; 308 309 idx++; 310 } 311 312 return NULL; 313 } 314 315 PDEVMODEW DESK_EXT_CALLBACK 316 CDevSettings_GetCurrentMode(PVOID Context) 317 { 318 PCDevSettings This = impl_from_IDataObject((IDataObject *)Context); 319 320 DPRINT1("CDevSettings::GetCurrentMode\n"); 321 return This->lpCurDevMode; 322 } 323 324 BOOL DESK_EXT_CALLBACK 325 CDevSettings_SetCurrentMode(PVOID Context, 326 DEVMODEW *pDevMode) 327 { 328 PCDevSettings This = impl_from_IDataObject((IDataObject *)Context); 329 DWORD i; 330 331 DPRINT1("CDevSettings::SetCurrentMode(0x%p)\n", pDevMode); 332 333 if (!This->DevModes) 334 return FALSE; 335 336 for (i = 0; i < This->nDevModes; i++) 337 { 338 /* FIXME: Add more sanity checks */ 339 if (!This->DevModes[i]) 340 continue; 341 342 if (This->DevModes[i] == pDevMode) 343 { 344 This->lpCurDevMode = pDevMode; 345 return TRUE; 346 } 347 } 348 349 return FALSE; 350 } 351 352 VOID DESK_EXT_CALLBACK 353 CDevSettings_GetPruningMode(PVOID Context, 354 PBOOL pbModesPruned, 355 PBOOL pbKeyIsReadOnly, 356 PBOOL pbPruningOn) 357 { 358 PCDevSettings This = impl_from_IDataObject((IDataObject *)Context); 359 360 DPRINT1("CDevSettings::GetPruningMode(%p,%p,%p)\n", pbModesPruned, pbKeyIsReadOnly, pbPruningOn); 361 362 *pbModesPruned = This->bModesPruned; 363 *pbKeyIsReadOnly = This->bKeyIsReadOnly; 364 *pbPruningOn = This->bPruningOn; 365 } 366 367 VOID DESK_EXT_CALLBACK 368 CDevSettings_SetPruningMode(PVOID Context, 369 BOOL PruningOn) 370 { 371 HKEY hKey; 372 DWORD dwValue; 373 PCDevSettings This = impl_from_IDataObject((IDataObject *)Context); 374 375 DPRINT1("CDevSettings::SetPruningMode(%d)\n", PruningOn); 376 377 if (This->bModesPruned && !This->bKeyIsReadOnly && 378 PruningOn != This->bPruningOn) 379 { 380 This->bPruningOn = (PruningOn != FALSE); 381 382 hKey = pCDevSettings_OpenDeviceKey(This, 383 FALSE); 384 if (hKey != NULL) 385 { 386 dwValue = (DWORD)This->bPruningOn; 387 388 RegSetValueEx(hKey, 389 TEXT("PruningMode"), 390 0, 391 REG_DWORD, 392 (const BYTE *)&dwValue, 393 sizeof(dwValue)); 394 395 RegCloseKey(hKey); 396 } 397 } 398 } 399 400 static VOID 401 pCDevSettings_ReadHardwareInfo(HKEY hKey, 402 LPCTSTR lpValueName, 403 LPWSTR lpBuffer) 404 { 405 DWORD type = REG_BINARY; 406 DWORD size = 128 * sizeof(WCHAR); 407 RegQueryValueEx(hKey, 408 lpValueName, 409 NULL, 410 &type, 411 (PBYTE)lpBuffer, 412 &size); 413 } 414 415 static VOID 416 pCDevSettings_InitializeExtInterface(PCDevSettings This) 417 { 418 PDESK_EXT_INTERFACE Interface = &This->ExtInterface; 419 HKEY hKeyDev; 420 421 ZeroMemory(Interface, 422 sizeof(*Interface)); 423 Interface->cbSize = sizeof(*Interface); 424 425 /* Initialize the callback table */ 426 Interface->Context = impl_to_interface(This, IDataObject); 427 Interface->EnumAllModes = CDevSettings_EnumAllModes; 428 Interface->SetCurrentMode = CDevSettings_SetCurrentMode; 429 Interface->GetCurrentMode = CDevSettings_GetCurrentMode; 430 Interface->SetPruningMode = CDevSettings_SetPruningMode; 431 Interface->GetPruningMode = CDevSettings_GetPruningMode; 432 433 /* Read the HardwareInformation.* values from the registry key */ 434 hKeyDev = pCDevSettings_OpenDeviceKey(This, 435 TRUE); 436 if (hKeyDev != NULL) 437 { 438 DWORD dwType, dwMemSize = 0; 439 DWORD dwSize = sizeof(dwMemSize); 440 441 if (RegQueryValueEx(hKeyDev, 442 TEXT("HardwareInformation.MemorySize"), 443 NULL, 444 &dwType, 445 (PBYTE)&dwMemSize, 446 &dwSize) == ERROR_SUCCESS && 447 (dwType == REG_BINARY || dwType == REG_DWORD) && 448 dwSize == sizeof(dwMemSize)) 449 { 450 dwMemSize /= 1024; 451 452 if (dwMemSize > 1024) 453 { 454 dwMemSize /= 1024; 455 if (dwMemSize > 1024) 456 { 457 wsprintf(Interface->MemorySize, 458 _T("%u GB"), 459 dwMemSize / 1024); 460 } 461 else 462 { 463 wsprintf(Interface->MemorySize, 464 _T("%u MB"), 465 dwMemSize); 466 } 467 } 468 else 469 { 470 wsprintf(Interface->MemorySize, 471 _T("%u KB"), 472 dwMemSize); 473 } 474 } 475 476 pCDevSettings_ReadHardwareInfo(hKeyDev, 477 TEXT("HardwareInformation.ChipType"), 478 Interface->ChipType); 479 pCDevSettings_ReadHardwareInfo(hKeyDev, 480 TEXT("HardwareInformation.DacType"), 481 Interface->DacType); 482 pCDevSettings_ReadHardwareInfo(hKeyDev, 483 TEXT("HardwareInformation.AdapterString"), 484 Interface->AdapterString); 485 pCDevSettings_ReadHardwareInfo(hKeyDev, 486 TEXT("HardwareInformation.BiosString"), 487 Interface->BiosString); 488 RegCloseKey(hKeyDev); 489 } 490 } 491 492 static HRESULT 493 pCDevSettings_Initialize(PCDevSettings This, 494 PDISPLAY_DEVICE_ENTRY DisplayDeviceInfo) 495 { 496 HKEY hKey; 497 DWORD i = 0, dwSize; 498 DEVMODEW devmode; 499 500 This->lpOrigDevMode = NULL; 501 This->lpCurDevMode = NULL; 502 This->DevModes = NULL; 503 This->nDevModes = 0; 504 This->Flags = 0; 505 This->StateFlags = DisplayDeviceInfo->DeviceStateFlags; 506 DPRINT1("This->StateFlags: %x\n", This->StateFlags); 507 508 /* Register clipboard formats */ 509 This->cfExtInterface = RegisterClipboardFormat(DESK_EXT_EXTINTERFACE); 510 This->cfDisplayDevice = RegisterClipboardFormat(DESK_EXT_DISPLAYDEVICE); 511 This->cfDisplayName = RegisterClipboardFormat(DESK_EXT_DISPLAYNAME); 512 This->cfDisplayId = RegisterClipboardFormat(DESK_EXT_DISPLAYID); 513 This->cfDisplayKey = RegisterClipboardFormat(DESK_EXT_DISPLAYKEY); 514 This->cfDisplayStateFlags = RegisterClipboardFormat(DESK_EXT_DISPLAYSTATEFLAGS); 515 This->cfMonitorName = RegisterClipboardFormat(DESK_EXT_MONITORNAME); 516 This->cfMonitorDevice = RegisterClipboardFormat(DESK_EXT_MONITORDEVICE); 517 This->cfPruningMode = RegisterClipboardFormat(DESK_EXT_PRUNINGMODE); 518 519 /* Copy the device name */ 520 This->pDisplayDevice = pCDevSettings_AllocAndCopyString(DisplayDeviceInfo->DeviceName); 521 DPRINT1("This->pDisplayDevice: %ws\n", This->pDisplayDevice); 522 This->pDisplayName = pCDevSettings_AllocAndCopyString(DisplayDeviceInfo->DeviceDescription); 523 DPRINT1("This->pDisplayName: %ws\n", This->pDisplayName); 524 This->pDisplayKey = pCDevSettings_AllocAndCopyString(DisplayDeviceInfo->DeviceKey); 525 DPRINT1("This->pDisplayKey: %ws\n", This->pDisplayKey); 526 This->pDisplayId = pCDevSettings_GetDeviceInstanceId(DisplayDeviceInfo->DeviceID); 527 DPRINT1("This->pDisplayId: %ws\n", This->pDisplayId); 528 This->pMonitorName = pCDevSettings_GetMonitorName(This->pDisplayDevice); 529 DPRINT1("This->pMonitorName: %ws\n", This->pMonitorName); 530 This->pMonitorDevice = pCDevSettings_GetMonitorDevice(This->pDisplayDevice); 531 DPRINT1("This->pMonitorDevice: %ws\n", This->pMonitorDevice); 532 533 /* Check pruning mode */ 534 This->bModesPruned = ((DisplayDeviceInfo->DeviceStateFlags & DISPLAY_DEVICE_MODESPRUNED) != 0); 535 hKey = pCDevSettings_OpenDeviceKey(This, 536 FALSE); 537 if (hKey == NULL) 538 { 539 hKey = pCDevSettings_OpenDeviceKey(This, 540 FALSE); 541 This->bKeyIsReadOnly = TRUE; 542 } 543 if (hKey != NULL) 544 { 545 DWORD dw = 0; 546 DWORD dwType; 547 548 dwSize = sizeof(dw); 549 if (RegQueryValueEx(hKey, 550 TEXT("PruningMode"), 551 NULL, 552 &dwType, 553 (PBYTE)&dw, 554 &dwSize) == ERROR_SUCCESS) 555 { 556 if (dwType == REG_DWORD && dwSize == sizeof(dw)) 557 This->bPruningOn = (dw != 0); 558 } 559 560 RegCloseKey(hKey); 561 } 562 563 /* Initialize display modes */ 564 ZeroMemory(&devmode, sizeof(devmode)); 565 devmode.dmSize = (WORD)sizeof(devmode); 566 while (EnumDisplaySettingsExW(This->pDisplayDevice, i, &devmode, EDS_RAWMODE)) 567 { 568 dwSize = devmode.dmSize + devmode.dmDriverExtra; 569 PDEVMODEW pDevMode = LocalAlloc(LMEM_FIXED, dwSize); 570 PDEVMODEW * DevModesNew = NULL; 571 572 if (pDevMode) 573 { 574 CopyMemory(pDevMode, 575 &devmode, 576 dwSize); 577 578 dwSize = (This->nDevModes + 1) * sizeof(pDevMode); 579 DevModesNew = LocalAlloc(LMEM_FIXED, dwSize); 580 if (DevModesNew) 581 { 582 if (This->DevModes) 583 { 584 CopyMemory(DevModesNew, 585 This->DevModes, 586 This->nDevModes * sizeof(pDevMode)); 587 588 LocalFree(This->DevModes); 589 } 590 591 This->DevModes = DevModesNew; 592 This->DevModes[This->nDevModes++] = pDevMode; 593 } 594 else 595 { 596 DPRINT1("LocalAlloc failed to allocate %d bytes\n", dwSize); 597 return E_OUTOFMEMORY; 598 } 599 } 600 else 601 { 602 DPRINT1("LocalAlloc failed to allocate %d bytes\n", dwSize); 603 return E_OUTOFMEMORY; 604 } 605 606 devmode.dmDriverExtra = 0; 607 i++; 608 } 609 610 /* FIXME: Detect duplicated modes and mark them. 611 * Enumeration functions should check these marks 612 * and skip corresponding array entries. */ 613 614 /* Get current display mode */ 615 ZeroMemory(&devmode, sizeof(devmode)); 616 devmode.dmSize = (WORD)sizeof(devmode); 617 if (EnumDisplaySettingsExW(This->pDisplayDevice, ENUM_CURRENT_SETTINGS, &devmode, 0)) 618 { 619 for (i = 0; i < This->nDevModes; i++) 620 { 621 PDEVMODEW CurMode = This->DevModes[i]; 622 623 if (!CurMode) 624 continue; 625 626 if (((CurMode->dmFields & DM_PELSWIDTH) && devmode.dmPelsWidth == CurMode->dmPelsWidth) && 627 ((CurMode->dmFields & DM_PELSHEIGHT) && devmode.dmPelsHeight == CurMode->dmPelsHeight) && 628 ((CurMode->dmFields & DM_BITSPERPEL) && devmode.dmBitsPerPel == CurMode->dmBitsPerPel) && 629 ((CurMode->dmFields & DM_DISPLAYFREQUENCY) && devmode.dmDisplayFrequency == CurMode->dmDisplayFrequency)) 630 { 631 This->lpOrigDevMode = This->lpCurDevMode = CurMode; 632 break; 633 } 634 } 635 } 636 637 /* Initialize the shell extension interface */ 638 pCDevSettings_InitializeExtInterface(This); 639 640 return S_OK; 641 } 642 643 static VOID 644 pCDevSettings_Free(PCDevSettings This) 645 { 646 This->lpOrigDevMode = NULL; 647 This->lpCurDevMode = NULL; 648 while (This->nDevModes) 649 { 650 LocalFree(This->DevModes[--This->nDevModes]); 651 } 652 LocalFree(This->DevModes); 653 This->DevModes = NULL; 654 655 pCDevSettings_FreeString(&This->pDisplayDevice); 656 pCDevSettings_FreeString(&This->pDisplayName); 657 pCDevSettings_FreeString(&This->pDisplayKey); 658 pCDevSettings_FreeString(&This->pDisplayId); 659 pCDevSettings_FreeString(&This->pMonitorName); 660 pCDevSettings_FreeString(&This->pMonitorDevice); 661 } 662 663 static HRESULT STDMETHODCALLTYPE 664 CDevSettings_QueryInterface(IDataObject* iface, 665 REFIID riid, 666 void** ppvObject) 667 { 668 PCDevSettings This = impl_from_IDataObject(iface); 669 670 *ppvObject = NULL; 671 672 if (IsEqualGUID(riid, 673 &IID_IUnknown) || 674 IsEqualGUID(riid, 675 &IID_IDataObject)) 676 { 677 *ppvObject = (PVOID)impl_to_interface(This, IDataObject); 678 return S_OK; 679 } 680 else 681 { 682 DPRINT1("CDevSettings::QueryInterface: Queried unknown interface\n"); 683 } 684 685 return E_NOINTERFACE; 686 } 687 688 static ULONG STDMETHODCALLTYPE 689 CDevSettings_AddRef(IDataObject* iface) 690 { 691 PCDevSettings This = impl_from_IDataObject(iface); 692 return (ULONG)InterlockedIncrement((PLONG)&This->ref); 693 } 694 695 static ULONG STDMETHODCALLTYPE 696 CDevSettings_Release(IDataObject* iface) 697 { 698 ULONG refs; 699 PCDevSettings This = impl_from_IDataObject(iface); 700 refs = (ULONG)InterlockedDecrement((PLONG)&This->ref); 701 if (refs == 0) 702 pCDevSettings_Free(This); 703 704 return refs; 705 } 706 707 static HRESULT STDMETHODCALLTYPE 708 CDevSettings_GetData(IDataObject* iface, 709 FORMATETC* pformatetcIn, 710 STGMEDIUM* pmedium) 711 { 712 static const WCHAR szEmpty[] = {0}; 713 HRESULT hr; 714 PCWSTR pszRet = NULL; 715 PWSTR pszBuf; 716 PCDevSettings This = impl_from_IDataObject(iface); 717 718 ZeroMemory(pmedium, 719 sizeof(STGMEDIUM)); 720 721 hr = IDataObject_QueryGetData(iface, 722 pformatetcIn); 723 if (SUCCEEDED(hr)) 724 { 725 /* Return the requested data back to the shell extension */ 726 727 if (pformatetcIn->cfFormat == This->cfDisplayDevice) 728 { 729 pszRet = This->pDisplayDevice; 730 DPRINT1("CDevSettings::GetData returns display device %ws\n", pszRet); 731 } 732 else if (pformatetcIn->cfFormat == This->cfDisplayName) 733 { 734 pszRet = This->pDisplayName; 735 DPRINT1("CDevSettings::GetData returns display name %ws\n", pszRet); 736 } 737 else if (pformatetcIn->cfFormat == This->cfDisplayKey) 738 { 739 pszRet = This->pDisplayKey; 740 DPRINT1("CDevSettings::GetData returns display key %ws\n", pszRet); 741 } 742 else if (pformatetcIn->cfFormat == This->cfDisplayId) 743 { 744 pszRet = This->pDisplayId; 745 DPRINT1("CDevSettings::GetData returns display id %ws\n", pszRet); 746 } 747 else if (pformatetcIn->cfFormat == This->cfMonitorName) 748 { 749 pszRet = This->pMonitorName; 750 DPRINT1("CDevSettings::GetData returns monitor name %ws\n", pszRet); 751 } 752 else if (pformatetcIn->cfFormat == This->cfMonitorDevice) 753 { 754 pszRet = This->pMonitorDevice; 755 DPRINT1("CDevSettings::GetData returns monitor device %ws\n", pszRet); 756 } 757 else if (pformatetcIn->cfFormat == This->cfExtInterface) 758 { 759 PDESK_EXT_INTERFACE pIface; 760 761 pIface = GlobalAlloc(GPTR, 762 sizeof(*pIface)); 763 if (pIface != NULL) 764 { 765 CopyMemory(pIface, 766 &This->ExtInterface, 767 sizeof(This->ExtInterface)); 768 769 DPRINT1("CDevSettings::GetData returns the desk.cpl extension interface\n"); 770 771 pmedium->tymed = TYMED_HGLOBAL; 772 pmedium->hGlobal = pIface; 773 774 return S_OK; 775 } 776 else 777 return E_OUTOFMEMORY; 778 } 779 else if (pformatetcIn->cfFormat == This->cfDisplayStateFlags) 780 { 781 PDWORD pdw; 782 783 pdw = GlobalAlloc(GPTR, 784 sizeof(*pdw)); 785 if (pdw != NULL) 786 { 787 *pdw = This->StateFlags; 788 789 DPRINT1("CDevSettings::GetData returns the display state flags %x\n", This->StateFlags); 790 791 pmedium->tymed = TYMED_HGLOBAL; 792 pmedium->hGlobal = pdw; 793 794 return S_OK; 795 } 796 else 797 return E_OUTOFMEMORY; 798 } 799 else if (pformatetcIn->cfFormat == This->cfPruningMode) 800 { 801 PBYTE pb; 802 803 pb = GlobalAlloc(GPTR, 804 sizeof(*pb)); 805 if (pb != NULL) 806 { 807 *pb = (This->bModesPruned && This->bPruningOn); 808 809 pmedium->tymed = TYMED_HGLOBAL; 810 pmedium->hGlobal = pb; 811 812 return S_OK; 813 } 814 else 815 return E_OUTOFMEMORY; 816 } 817 818 /* NOTE: This only returns null-terminated strings! */ 819 if (pszRet == NULL) 820 pszRet = szEmpty; 821 822 pszBuf = GlobalAlloc(GPTR, 823 (wcslen(pszRet) + 1) * sizeof(WCHAR)); 824 if (pszBuf != NULL) 825 { 826 hr = StringCbCopyW(pszBuf, (wcslen(pszRet) + 1) * sizeof(WCHAR), pszRet); 827 if (FAILED(hr)) 828 { 829 GlobalFree(pszBuf); 830 return hr; 831 } 832 833 pmedium->tymed = TYMED_HGLOBAL; 834 pmedium->hGlobal = pszBuf; 835 836 hr = S_OK; 837 } 838 else 839 hr = E_OUTOFMEMORY; 840 } 841 842 return hr; 843 } 844 845 static HRESULT STDMETHODCALLTYPE 846 CDevSettings_GetDataHere(IDataObject* iface, 847 FORMATETC* pformatetc, 848 STGMEDIUM* pmedium) 849 { 850 ZeroMemory(pformatetc, 851 sizeof(*pformatetc)); 852 return E_NOTIMPL; 853 } 854 855 static HRESULT STDMETHODCALLTYPE 856 CDevSettings_QueryGetData(IDataObject* iface, 857 FORMATETC* pformatetc) 858 { 859 #if DEBUG 860 TCHAR szFormatName[255]; 861 #endif 862 PCDevSettings This = impl_from_IDataObject(iface); 863 864 if (pformatetc->dwAspect != DVASPECT_CONTENT) 865 return DV_E_DVASPECT; 866 867 if (pformatetc->lindex != -1) 868 return DV_E_LINDEX; 869 870 if (!(pformatetc->tymed & TYMED_HGLOBAL)) 871 return DV_E_TYMED; 872 873 /* Check if the requested data can be provided */ 874 if (pformatetc->cfFormat == This->cfExtInterface || 875 pformatetc->cfFormat == This->cfDisplayDevice || 876 pformatetc->cfFormat == This->cfDisplayName || 877 pformatetc->cfFormat == This->cfDisplayId || 878 pformatetc->cfFormat == This->cfDisplayKey || 879 pformatetc->cfFormat == This->cfDisplayStateFlags || 880 pformatetc->cfFormat == This->cfMonitorDevice || 881 pformatetc->cfFormat == This->cfMonitorName || 882 pformatetc->cfFormat == This->cfPruningMode) 883 { 884 return S_OK; 885 } 886 #if DEBUG 887 else 888 { 889 if (GetClipboardFormatName(pformatetc->cfFormat, 890 szFormatName, 891 sizeof(szFormatName) / sizeof(szFormatName[0]))) 892 { 893 DPRINT1("CDevSettings::QueryGetData(\"%ws\")\n", szFormatName); 894 } 895 else 896 { 897 DPRINT1("CDevSettings::QueryGetData(Format %u)\n", (unsigned int)pformatetc->cfFormat); 898 } 899 } 900 #endif 901 902 return DV_E_FORMATETC; 903 } 904 905 static HRESULT STDMETHODCALLTYPE 906 CDevSettings_GetCanonicalFormatEtc(IDataObject* iface, 907 FORMATETC* pformatectIn, 908 FORMATETC* pformatetcOut) 909 { 910 HRESULT hr; 911 912 DPRINT1("CDevSettings::GetCanonicalFormatEtc\n"); 913 914 hr = IDataObject_QueryGetData(iface, 915 pformatectIn); 916 if (SUCCEEDED(hr)) 917 { 918 CopyMemory(pformatetcOut, 919 pformatectIn, 920 sizeof(FORMATETC)); 921 922 /* Make sure the data is target device independent */ 923 if (pformatectIn->ptd == NULL) 924 hr = DATA_S_SAMEFORMATETC; 925 else 926 { 927 pformatetcOut->ptd = NULL; 928 hr = S_OK; 929 } 930 } 931 else 932 { 933 ZeroMemory(pformatetcOut, 934 sizeof(FORMATETC)); 935 } 936 937 return hr; 938 } 939 940 static HRESULT STDMETHODCALLTYPE 941 CDevSettings_SetData(IDataObject* iface, 942 FORMATETC* pformatetc, 943 STGMEDIUM* pmedium, 944 BOOL fRelease) 945 { 946 DPRINT1("CDevSettings::SetData UNIMPLEMENTED\n"); 947 return E_NOTIMPL; 948 } 949 950 static __inline VOID 951 pCDevSettings_FillFormatEtc(FORMATETC *pFormatEtc, 952 CLIPFORMAT cf) 953 { 954 pFormatEtc->cfFormat = cf; 955 pFormatEtc->ptd = NULL; 956 pFormatEtc->dwAspect = DVASPECT_CONTENT; 957 pFormatEtc->lindex = -1; 958 pFormatEtc->tymed = TYMED_HGLOBAL; 959 } 960 961 static HRESULT STDMETHODCALLTYPE 962 CDevSettings_EnumFormatEtc(IDataObject* iface, 963 DWORD dwDirection, 964 IEnumFORMATETC** ppenumFormatEtc) 965 { 966 HRESULT hr; 967 FORMATETC fetc[9]; 968 PCDevSettings This = impl_from_IDataObject(iface); 969 970 *ppenumFormatEtc = NULL; 971 972 if (dwDirection == DATADIR_GET) 973 { 974 pCDevSettings_FillFormatEtc(&fetc[0], 975 This->cfExtInterface); 976 pCDevSettings_FillFormatEtc(&fetc[1], 977 This->cfDisplayDevice); 978 pCDevSettings_FillFormatEtc(&fetc[2], 979 This->cfDisplayName); 980 pCDevSettings_FillFormatEtc(&fetc[3], 981 This->cfDisplayId); 982 pCDevSettings_FillFormatEtc(&fetc[4], 983 This->cfDisplayKey); 984 pCDevSettings_FillFormatEtc(&fetc[5], 985 This->cfDisplayStateFlags); 986 pCDevSettings_FillFormatEtc(&fetc[6], 987 This->cfMonitorName); 988 pCDevSettings_FillFormatEtc(&fetc[7], 989 This->cfMonitorDevice); 990 pCDevSettings_FillFormatEtc(&fetc[8], 991 This->cfPruningMode); 992 993 hr = SHCreateStdEnumFmtEtc(sizeof(fetc) / sizeof(fetc[0]), 994 fetc, 995 ppenumFormatEtc); 996 } 997 else 998 hr = E_NOTIMPL; 999 1000 return hr; 1001 } 1002 1003 static HRESULT STDMETHODCALLTYPE 1004 CDevSettings_DAdvise(IDataObject* iface, 1005 FORMATETC* pformatetc, 1006 DWORD advf, 1007 IAdviseSink* pAdvSink, 1008 DWORD* pdwConnection) 1009 { 1010 *pdwConnection = 0; 1011 return OLE_E_ADVISENOTSUPPORTED; 1012 } 1013 1014 static HRESULT STDMETHODCALLTYPE 1015 CDevSettings_DUnadvise(IDataObject* iface, 1016 DWORD dwConnection) 1017 { 1018 return OLE_E_ADVISENOTSUPPORTED; 1019 } 1020 1021 static HRESULT STDMETHODCALLTYPE 1022 CDevSettings_EnumDAdvise(IDataObject* iface, 1023 IEnumSTATDATA** ppenumAdvise) 1024 { 1025 *ppenumAdvise = NULL; 1026 return OLE_E_ADVISENOTSUPPORTED; 1027 } 1028 1029 static const struct IDataObjectVtbl vtblIDataObject = { 1030 CDevSettings_QueryInterface, 1031 CDevSettings_AddRef, 1032 CDevSettings_Release, 1033 CDevSettings_GetData, 1034 CDevSettings_GetDataHere, 1035 CDevSettings_QueryGetData, 1036 CDevSettings_GetCanonicalFormatEtc, 1037 CDevSettings_SetData, 1038 CDevSettings_EnumFormatEtc, 1039 CDevSettings_DAdvise, 1040 CDevSettings_DUnadvise, 1041 CDevSettings_EnumDAdvise, 1042 }; 1043 1044 IDataObject * 1045 CreateDevSettings(PDISPLAY_DEVICE_ENTRY DisplayDeviceInfo) 1046 { 1047 PCDevSettings This; 1048 1049 This = HeapAlloc(GetProcessHeap(), 1050 0, 1051 sizeof(*This)); 1052 if (This != NULL) 1053 { 1054 This->lpIDataObjectVtbl = &vtblIDataObject; 1055 This->ref = 1; 1056 1057 if (SUCCEEDED(pCDevSettings_Initialize(This, 1058 DisplayDeviceInfo))) 1059 { 1060 return impl_to_interface(This, IDataObject); 1061 } 1062 1063 CDevSettings_Release(impl_to_interface(This, IDataObject)); 1064 } 1065 1066 return NULL; 1067 } 1068 1069 LONG WINAPI 1070 DisplaySaveSettings(PVOID pContext, 1071 HWND hwndPropSheet) 1072 { 1073 PCDevSettings This = impl_from_IDataObject((IDataObject *)pContext); 1074 LONG rc = DISP_CHANGE_SUCCESSFUL; 1075 1076 if (This->lpCurDevMode != This->lpOrigDevMode) 1077 { 1078 SETTINGS_ENTRY seOrig, seCur; 1079 BOOL Ret; 1080 1081 seOrig.dmPelsWidth = This->lpOrigDevMode->dmPelsWidth; 1082 seOrig.dmPelsHeight = This->lpOrigDevMode->dmPelsHeight; 1083 seOrig.dmBitsPerPel = This->lpOrigDevMode->dmBitsPerPel; 1084 seOrig.dmDisplayFrequency = This->lpOrigDevMode->dmDisplayFrequency; 1085 1086 seCur.dmPelsWidth = This->lpCurDevMode->dmPelsWidth; 1087 seCur.dmPelsHeight = This->lpCurDevMode->dmPelsHeight; 1088 seCur.dmBitsPerPel = This->lpCurDevMode->dmBitsPerPel; 1089 seCur.dmDisplayFrequency = This->lpCurDevMode->dmDisplayFrequency; 1090 1091 Ret = SwitchDisplayMode(hwndPropSheet, 1092 This->pDisplayDevice, 1093 &seOrig, 1094 &seCur, 1095 &rc); 1096 1097 if (rc == DISP_CHANGE_SUCCESSFUL) 1098 { 1099 if (Ret) 1100 This->lpOrigDevMode = This->lpCurDevMode; 1101 else 1102 This->lpCurDevMode = This->lpOrigDevMode; 1103 } 1104 } 1105 1106 return rc; 1107 } 1108