Sync with trunk r62529.
[reactos.git] / dll / cpl / desk / devsett.c
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 DWORD StateFlags;
42
43 union
44 {
45 DWORD Flags;
46 struct
47 {
48 DWORD bModesPruned : 1;
49 DWORD bKeyIsReadOnly : 1;
50 DWORD bPruningOn : 1;
51 };
52 };
53 } CDevSettings, *PCDevSettings;
54
55 #define impl_to_interface(impl,iface) (struct iface *)(&(impl)->lp##iface##Vtbl)
56
57 static __inline PCDevSettings
58 impl_from_IDataObject(struct IDataObject *iface)
59 {
60 return (PCDevSettings)((ULONG_PTR)iface - FIELD_OFFSET(CDevSettings,
61 lpIDataObjectVtbl));
62 }
63
64 static __inline VOID
65 pCDevSettings_FreeString(PWCHAR *psz)
66 {
67 if (*psz != NULL)
68 {
69 LocalFree((HLOCAL)*psz);
70 *psz = NULL;
71 }
72 }
73
74 static PWSTR
75 pCDevSettings_AllocAndCopyString(const TCHAR *pszSrc)
76 {
77 INT c;
78 PWSTR str;
79
80 c = _tcslen(pszSrc) + 1;
81 str = (PWSTR)LocalAlloc(LMEM_FIXED,
82 c * sizeof(WCHAR));
83 if (str != NULL)
84 {
85 #ifdef UNICODE
86 StringCbCopyW(str, c * sizeof(WCHAR),
87 pszSrc);
88 #else
89 MultiByteToWideChar(CP_ACP,
90 0,
91 pszSrc,
92 -1,
93 str,
94 c);
95 #endif
96 }
97
98 return str;
99 }
100
101 static PWSTR
102 pCDevSettings_GetMonitorName(const WCHAR *pszDisplayDevice)
103 {
104 DISPLAY_DEVICEW dd, dd2;
105 PWSTR str = NULL;
106
107 dd.cb = sizeof(dd);
108 if (EnumDisplayDevicesW(pszDisplayDevice,
109 0,
110 &dd,
111 0))
112 {
113 dd2.cb = sizeof(dd2);
114 if (EnumDisplayDevicesW(pszDisplayDevice,
115 1,
116 &dd2,
117 0))
118 {
119 /* There's more than one monitor connected... */
120 LoadStringW(hApplet,
121 IDS_MULTIPLEMONITORS,
122 dd.DeviceString,
123 sizeof(dd.DeviceString) / sizeof(dd.DeviceString[0]));
124 }
125 }
126 else
127 {
128 /* We can't enumerate a monitor, make sure this fact is reported
129 to the user! */
130 LoadStringW(hApplet,
131 IDS_UNKNOWNMONITOR,
132 dd.DeviceString,
133 sizeof(dd.DeviceString) / sizeof(dd.DeviceString[0]));
134 }
135
136 str = LocalAlloc(LMEM_FIXED,
137 (wcslen(dd.DeviceString) + 1) * sizeof(WCHAR));
138 if (str != NULL)
139 {
140 wcscpy(str,
141 dd.DeviceString);
142 }
143
144 return str;
145 }
146
147 static PWSTR
148 pCDevSettings_GetMonitorDevice(const WCHAR *pszDisplayDevice)
149 {
150 DISPLAY_DEVICEW dd;
151 PWSTR str = NULL;
152
153 dd.cb = sizeof(dd);
154 if (EnumDisplayDevicesW(pszDisplayDevice,
155 0,
156 &dd,
157 0))
158 {
159 str = LocalAlloc(LMEM_FIXED,
160 (wcslen(dd.DeviceName) + 1) * sizeof(WCHAR));
161 if (str != NULL)
162 {
163 wcscpy(str,
164 dd.DeviceName);
165 }
166 }
167
168 return str;
169 }
170
171 static PWSTR
172 pCDevSettings_GetDeviceInstanceId(const WCHAR *pszDevice)
173 {
174 DEVINST DevInst;
175 CONFIGRET cr;
176 ULONG BufLen;
177 LPWSTR lpDevInstId = NULL;
178
179 DPRINT1("CDevSettings::GetDeviceInstanceId(%ws) UNIMPLEMENTED!\n", pszDevice);
180
181 cr = CM_Locate_DevNodeW(&DevInst,
182 (DEVINSTID_W)pszDevice,
183 CM_LOCATE_DEVNODE_NORMAL);
184 if (cr == CR_SUCCESS)
185 {
186 DPRINT1("Success1\n");
187 cr = CM_Get_Device_ID_Size(&BufLen,
188 DevInst,
189 0);
190 if (cr == CR_SUCCESS)
191 {
192 DPRINT1("Success2\n");
193 lpDevInstId = LocalAlloc(LMEM_FIXED,
194 (BufLen + 1) * sizeof(WCHAR));
195
196 if (lpDevInstId != NULL)
197 {
198 DPRINT1("Success3\n");
199 cr = CM_Get_Device_IDW(DevInst,
200 lpDevInstId,
201 BufLen,
202 0);
203
204 if (cr != CR_SUCCESS)
205 {
206 LocalFree((HLOCAL)lpDevInstId);
207 lpDevInstId = NULL;
208 }
209 DPRINT1("instance id: %ws\n", lpDevInstId);
210 }
211 }
212 }
213
214 return lpDevInstId;
215 }
216
217
218 static HKEY
219 pCDevSettings_OpenDeviceKey(PCDevSettings This,
220 BOOL ReadOnly)
221 {
222 static const WCHAR szRegPrefix[] = L"\\Registry\\Machine\\";
223 PWSTR lpRegKey;
224 REGSAM Access = KEY_READ;
225 HKEY hKey;
226
227 lpRegKey = This->pDisplayKey;
228 if (lpRegKey != NULL)
229 {
230 if (wcslen(lpRegKey) >= wcslen(szRegPrefix) &&
231 !_wcsnicmp(lpRegKey,
232 szRegPrefix,
233 wcslen(szRegPrefix)))
234 {
235 lpRegKey += wcslen(szRegPrefix);
236 }
237
238 if (!ReadOnly)
239 Access |= KEY_WRITE;
240
241 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
242 lpRegKey,
243 0,
244 Access,
245 &hKey) == ERROR_SUCCESS)
246 {
247 return hKey;
248 }
249 }
250
251 return NULL;
252 }
253
254 PDEVMODEW DESK_EXT_CALLBACK
255 CDevSettings_EnumAllModes(PVOID Context,
256 DWORD Index)
257 {
258 //PCDevSettings This = impl_from_IDataObject((IDataObject *)Context);
259 /* FIXME: Implement */
260 DPRINT1("CDevSettings::EnumAllModes(%u)\n", Index);
261 return NULL;
262 }
263
264 PDEVMODEW DESK_EXT_CALLBACK
265 CDevSettings_GetCurrentMode(PVOID Context)
266 {
267 //PCDevSettings This = impl_from_IDataObject((IDataObject *)Context);
268 /* FIXME: Implement */
269 DPRINT1("CDevSettings::GetCurrentMode\n");
270 return NULL;
271 }
272
273 BOOL DESK_EXT_CALLBACK
274 CDevSettings_SetCurrentMode(PVOID Context,
275 const DEVMODEW *pDevMode)
276 {
277 //PCDevSettings This = impl_from_IDataObject((IDataObject *)Context);
278 /* FIXME: Implement */
279 DPRINT1("CDevSettings::SetCurrentMode(0x%p)\n", pDevMode);
280 return FALSE;
281 }
282
283 VOID DESK_EXT_CALLBACK
284 CDevSettings_GetPruningMode(PVOID Context,
285 PBOOL pbModesPruned,
286 PBOOL pbKeyIsReadOnly,
287 PBOOL pbPruningOn)
288 {
289 PCDevSettings This = impl_from_IDataObject((IDataObject *)Context);
290
291 DPRINT1("CDevSettings::GetPruningMode(%p,%p,%p)\n", pbModesPruned, pbKeyIsReadOnly, pbPruningOn);
292
293 *pbModesPruned = This->bModesPruned;
294 *pbKeyIsReadOnly = This->bKeyIsReadOnly;
295 *pbPruningOn = This->bPruningOn;
296 }
297
298 VOID DESK_EXT_CALLBACK
299 CDevSettings_SetPruningMode(PVOID Context,
300 BOOL PruningOn)
301 {
302 HKEY hKey;
303 DWORD dwValue;
304 PCDevSettings This = impl_from_IDataObject((IDataObject *)Context);
305
306 DPRINT1("CDevSettings::SetPruningMode(%d)\n", PruningOn);
307
308 if (This->bModesPruned && !This->bKeyIsReadOnly &&
309 PruningOn != This->bPruningOn)
310 {
311 This->bPruningOn = (PruningOn != FALSE);
312
313 hKey = pCDevSettings_OpenDeviceKey(This,
314 FALSE);
315 if (hKey != NULL)
316 {
317 dwValue = (DWORD)This->bPruningOn;
318
319 RegSetValueEx(hKey,
320 TEXT("PruningMode"),
321 0,
322 REG_DWORD,
323 (const BYTE *)&dwValue,
324 sizeof(dwValue));
325
326 RegCloseKey(hKey);
327 }
328 }
329 }
330
331 static VOID
332 pCDevSettings_ReadHardwareInfo(HKEY hKey,
333 LPCTSTR lpValueName,
334 LPWSTR lpBuffer)
335 {
336 DWORD type = REG_BINARY;
337 DWORD size = 128 * sizeof(WCHAR);
338 RegQueryValueEx(hKey,
339 lpValueName,
340 NULL,
341 &type,
342 (PBYTE)lpBuffer,
343 &size);
344 }
345
346 static VOID
347 pCDevSettings_InitializeExtInterface(PCDevSettings This)
348 {
349 PDESK_EXT_INTERFACE Interface = &This->ExtInterface;
350 HKEY hKeyDev;
351
352 ZeroMemory(Interface,
353 sizeof(*Interface));
354 Interface->cbSize = sizeof(*Interface);
355
356 /* Initialize the callback table */
357 Interface->Context = impl_to_interface(This, IDataObject);
358 Interface->EnumAllModes = CDevSettings_EnumAllModes;
359 Interface->SetCurrentMode = CDevSettings_SetCurrentMode;
360 Interface->GetCurrentMode = CDevSettings_GetCurrentMode;
361 Interface->SetPruningMode = CDevSettings_SetPruningMode;
362 Interface->GetPruningMode = CDevSettings_GetPruningMode;
363
364 /* Read the HardwareInformation.* values from the registry key */
365 hKeyDev = pCDevSettings_OpenDeviceKey(This,
366 TRUE);
367 if (hKeyDev != NULL)
368 {
369 DWORD dwType, dwMemSize = 0;
370 DWORD dwSize = sizeof(dwMemSize);
371
372 if (RegQueryValueEx(hKeyDev,
373 TEXT("HardwareInformation.MemorySize"),
374 NULL,
375 &dwType,
376 (PBYTE)&dwMemSize,
377 &dwSize) == ERROR_SUCCESS &&
378 (dwType == REG_BINARY || dwType == REG_DWORD) &&
379 dwSize == sizeof(dwMemSize))
380 {
381 dwMemSize /= 1024;
382
383 if (dwMemSize > 1024)
384 {
385 dwMemSize /= 1024;
386 if (dwMemSize > 1024)
387 {
388 wsprintf(Interface->MemorySize,
389 _T("%u GB"),
390 dwMemSize / 1024);
391 }
392 else
393 {
394 wsprintf(Interface->MemorySize,
395 _T("%u MB"),
396 dwMemSize);
397 }
398 }
399 else
400 {
401 wsprintf(Interface->MemorySize,
402 _T("%u KB"),
403 dwMemSize);
404 }
405 }
406
407 pCDevSettings_ReadHardwareInfo(hKeyDev,
408 TEXT("HardwareInformation.ChipType"),
409 Interface->ChipType);
410 pCDevSettings_ReadHardwareInfo(hKeyDev,
411 TEXT("HardwareInformation.DacType"),
412 Interface->DacType);
413 pCDevSettings_ReadHardwareInfo(hKeyDev,
414 TEXT("HardwareInformation.AdapterString"),
415 Interface->AdapterString);
416 pCDevSettings_ReadHardwareInfo(hKeyDev,
417 TEXT("HardwareInformation.BiosString"),
418 Interface->BiosString);
419 RegCloseKey(hKeyDev);
420 }
421 }
422
423 static HRESULT
424 pCDevSettings_Initialize(PCDevSettings This,
425 PDISPLAY_DEVICE_ENTRY DisplayDeviceInfo)
426 {
427 HKEY hKey;
428
429 This->Flags = 0;
430 This->StateFlags = DisplayDeviceInfo->DeviceStateFlags;
431 DPRINT1("This->StateFlags: %x\n", This->StateFlags);
432
433 /* Register clipboard formats */
434 This->cfExtInterface = RegisterClipboardFormat(DESK_EXT_EXTINTERFACE);
435 This->cfDisplayDevice = RegisterClipboardFormat(DESK_EXT_DISPLAYDEVICE);
436 This->cfDisplayName = RegisterClipboardFormat(DESK_EXT_DISPLAYNAME);
437 This->cfDisplayId = RegisterClipboardFormat(DESK_EXT_DISPLAYID);
438 This->cfDisplayKey = RegisterClipboardFormat(DESK_EXT_DISPLAYKEY);
439 This->cfDisplayStateFlags = RegisterClipboardFormat(DESK_EXT_DISPLAYSTATEFLAGS);
440 This->cfMonitorName = RegisterClipboardFormat(DESK_EXT_MONITORNAME);
441 This->cfMonitorDevice = RegisterClipboardFormat(DESK_EXT_MONITORDEVICE);
442 This->cfPruningMode = RegisterClipboardFormat(DESK_EXT_PRUNINGMODE);
443
444 /* Copy the device name */
445 This->pDisplayDevice = pCDevSettings_AllocAndCopyString(DisplayDeviceInfo->DeviceName);
446 DPRINT1("This->pDisplayDevice: %ws\n", This->pDisplayDevice);
447 This->pDisplayName = pCDevSettings_AllocAndCopyString(DisplayDeviceInfo->DeviceDescription);
448 DPRINT1("This->pDisplayName: %ws\n", This->pDisplayName);
449 This->pDisplayKey = pCDevSettings_AllocAndCopyString(DisplayDeviceInfo->DeviceKey);
450 DPRINT1("This->pDisplayKey: %ws\n", This->pDisplayKey);
451 This->pDisplayId = pCDevSettings_GetDeviceInstanceId(DisplayDeviceInfo->DeviceID);
452 DPRINT1("This->pDisplayId: %ws\n", This->pDisplayId);
453 This->pMonitorName = pCDevSettings_GetMonitorName(This->pDisplayDevice);
454 DPRINT1("This->pMonitorName: %ws\n", This->pMonitorName);
455 This->pMonitorDevice = pCDevSettings_GetMonitorDevice(This->pDisplayDevice);
456 DPRINT1("This->pMonitorDevice: %ws\n", This->pMonitorDevice);
457
458 /* Check pruning mode */
459 This->bModesPruned = ((DisplayDeviceInfo->DeviceStateFlags & DISPLAY_DEVICE_MODESPRUNED) != 0);
460 hKey = pCDevSettings_OpenDeviceKey(This,
461 FALSE);
462 if (hKey == NULL)
463 {
464 hKey = pCDevSettings_OpenDeviceKey(This,
465 FALSE);
466 This->bKeyIsReadOnly = TRUE;
467 }
468 if (hKey != NULL)
469 {
470 DWORD dw = 0;
471 DWORD dwType, dwSize;
472
473 dwSize = sizeof(dw);
474 if (RegQueryValueEx(hKey,
475 TEXT("PruningMode"),
476 NULL,
477 &dwType,
478 (PBYTE)&dw,
479 &dwSize) == ERROR_SUCCESS)
480 {
481 if (dwType == REG_DWORD && dwSize == sizeof(dw))
482 This->bPruningOn = (dw != 0);
483 }
484
485 RegCloseKey(hKey);
486 }
487
488 /* Initialize the shell extension interface */
489 pCDevSettings_InitializeExtInterface(This);
490
491 return S_OK;
492 }
493
494 static VOID
495 pCDevSettings_Free(PCDevSettings This)
496 {
497 pCDevSettings_FreeString(&This->pDisplayDevice);
498 pCDevSettings_FreeString(&This->pDisplayName);
499 pCDevSettings_FreeString(&This->pDisplayKey);
500 pCDevSettings_FreeString(&This->pDisplayId);
501 pCDevSettings_FreeString(&This->pMonitorName);
502 pCDevSettings_FreeString(&This->pMonitorDevice);
503 }
504
505 static HRESULT STDMETHODCALLTYPE
506 CDevSettings_QueryInterface(IDataObject* iface,
507 REFIID riid,
508 void** ppvObject)
509 {
510 PCDevSettings This = impl_from_IDataObject(iface);
511
512 *ppvObject = NULL;
513
514 if (IsEqualGUID(riid,
515 &IID_IUnknown) ||
516 IsEqualGUID(riid,
517 &IID_IDataObject))
518 {
519 *ppvObject = (PVOID)impl_to_interface(This, IDataObject);
520 return S_OK;
521 }
522 else
523 {
524 DPRINT1("CDevSettings::QueryInterface: Queried unknown interface\n");
525 }
526
527 return E_NOINTERFACE;
528 }
529
530 static ULONG STDMETHODCALLTYPE
531 CDevSettings_AddRef(IDataObject* iface)
532 {
533 PCDevSettings This = impl_from_IDataObject(iface);
534 return (ULONG)InterlockedIncrement((PLONG)&This->ref);
535 }
536
537 static ULONG STDMETHODCALLTYPE
538 CDevSettings_Release(IDataObject* iface)
539 {
540 ULONG refs;
541 PCDevSettings This = impl_from_IDataObject(iface);
542 refs = (ULONG)InterlockedDecrement((PLONG)&This->ref);
543 if (refs == 0)
544 pCDevSettings_Free(This);
545
546 return refs;
547 }
548
549 static HRESULT STDMETHODCALLTYPE
550 CDevSettings_GetData(IDataObject* iface,
551 FORMATETC* pformatetcIn,
552 STGMEDIUM* pmedium)
553 {
554 static const WCHAR szEmpty[] = {0};
555 HRESULT hr;
556 PCWSTR pszRet = NULL;
557 PWSTR pszBuf;
558 PCDevSettings This = impl_from_IDataObject(iface);
559
560 ZeroMemory(pmedium,
561 sizeof(STGMEDIUM));
562
563 hr = IDataObject_QueryGetData(iface,
564 pformatetcIn);
565 if (SUCCEEDED(hr))
566 {
567 /* Return the reqested data back to the shell extension */
568
569 if (pformatetcIn->cfFormat == This->cfDisplayDevice)
570 {
571 pszRet = This->pDisplayDevice;
572 DPRINT1("CDevSettings::GetData returns display device %ws\n", pszRet);
573 }
574 else if (pformatetcIn->cfFormat == This->cfDisplayName)
575 {
576 pszRet = This->pDisplayName;
577 DPRINT1("CDevSettings::GetData returns display name %ws\n", pszRet);
578 }
579 else if (pformatetcIn->cfFormat == This->cfDisplayKey)
580 {
581 pszRet = This->pDisplayKey;
582 DPRINT1("CDevSettings::GetData returns display key %ws\n", pszRet);
583 }
584 else if (pformatetcIn->cfFormat == This->cfDisplayId)
585 {
586 pszRet = This->pDisplayId;
587 DPRINT1("CDevSettings::GetData returns display id %ws\n", pszRet);
588 }
589 else if (pformatetcIn->cfFormat == This->cfMonitorName)
590 {
591 pszRet = This->pMonitorName;
592 DPRINT1("CDevSettings::GetData returns monitor name %ws\n", pszRet);
593 }
594 else if (pformatetcIn->cfFormat == This->cfMonitorDevice)
595 {
596 pszRet = This->pMonitorDevice;
597 DPRINT1("CDevSettings::GetData returns monitor device %ws\n", pszRet);
598 }
599 else if (pformatetcIn->cfFormat == This->cfExtInterface)
600 {
601 PDESK_EXT_INTERFACE pIface;
602
603 pIface = GlobalAlloc(GPTR,
604 sizeof(*pIface));
605 if (pIface != NULL)
606 {
607 CopyMemory(pIface,
608 &This->ExtInterface,
609 sizeof(This->ExtInterface));
610
611 DPRINT1("CDevSettings::GetData returns the desk.cpl extension interface\n");
612
613 pmedium->tymed = TYMED_HGLOBAL;
614 pmedium->hGlobal = pIface;
615
616 return S_OK;
617 }
618 else
619 return E_OUTOFMEMORY;
620 }
621 else if (pformatetcIn->cfFormat == This->cfDisplayStateFlags)
622 {
623 PDWORD pdw;
624
625 pdw = GlobalAlloc(GPTR,
626 sizeof(*pdw));
627 if (pdw != NULL)
628 {
629 *pdw = This->StateFlags;
630
631 DPRINT1("CDevSettings::GetData returns the display state flags %x\n", This->StateFlags);
632
633 pmedium->tymed = TYMED_HGLOBAL;
634 pmedium->hGlobal = pdw;
635
636 return S_OK;
637 }
638 else
639 return E_OUTOFMEMORY;
640 }
641 else if (pformatetcIn->cfFormat == This->cfPruningMode)
642 {
643 PBYTE pb;
644
645 pb = GlobalAlloc(GPTR,
646 sizeof(*pb));
647 if (pb != NULL)
648 {
649 *pb = (This->bModesPruned && This->bPruningOn);
650
651 pmedium->tymed = TYMED_HGLOBAL;
652 pmedium->hGlobal = pb;
653
654 return S_OK;
655 }
656 else
657 return E_OUTOFMEMORY;
658 }
659
660 /* NOTE: This only returns null-terminated strings! */
661 if (pszRet == NULL)
662 pszRet = szEmpty;
663
664 pszBuf = GlobalAlloc(GPTR,
665 (wcslen(pszRet) + 1) * sizeof(WCHAR));
666 if (pszBuf != NULL)
667 {
668 hr = StringCbCopy(pszBuf, (wcslen(pszRet) + 1) * sizeof(WCHAR), pszRet);
669 if (FAILED(hr))
670 return hr;
671
672 pmedium->tymed = TYMED_HGLOBAL;
673 pmedium->hGlobal = pszBuf;
674
675 hr = S_OK;
676 }
677 else
678 hr = E_OUTOFMEMORY;
679 }
680
681 return hr;
682 }
683
684 static HRESULT STDMETHODCALLTYPE
685 CDevSettings_GetDataHere(IDataObject* iface,
686 FORMATETC* pformatetc,
687 STGMEDIUM* pmedium)
688 {
689 ZeroMemory(pformatetc,
690 sizeof(*pformatetc));
691 return E_NOTIMPL;
692 }
693
694 static HRESULT STDMETHODCALLTYPE
695 CDevSettings_QueryGetData(IDataObject* iface,
696 FORMATETC* pformatetc)
697 {
698 #if DEBUG
699 TCHAR szFormatName[255];
700 #endif
701 PCDevSettings This = impl_from_IDataObject(iface);
702
703 if (pformatetc->dwAspect != DVASPECT_CONTENT)
704 return DV_E_DVASPECT;
705
706 if (pformatetc->lindex != -1)
707 return DV_E_LINDEX;
708
709 if (!(pformatetc->tymed & TYMED_HGLOBAL))
710 return DV_E_TYMED;
711
712 /* Check if the requested data can be provided */
713 if (pformatetc->cfFormat == This->cfExtInterface ||
714 pformatetc->cfFormat == This->cfDisplayDevice ||
715 pformatetc->cfFormat == This->cfDisplayName ||
716 pformatetc->cfFormat == This->cfDisplayId ||
717 pformatetc->cfFormat == This->cfDisplayKey ||
718 pformatetc->cfFormat == This->cfDisplayStateFlags ||
719 pformatetc->cfFormat == This->cfMonitorDevice ||
720 pformatetc->cfFormat == This->cfMonitorName ||
721 pformatetc->cfFormat == This->cfPruningMode)
722 {
723 return S_OK;
724 }
725 #if DEBUG
726 else
727 {
728 if (GetClipboardFormatName(pformatetc->cfFormat,
729 szFormatName,
730 sizeof(szFormatName) / sizeof(szFormatName[0])))
731 {
732 DPRINT1("CDevSettings::QueryGetData(\"%ws\")\n", szFormatName);
733 }
734 else
735 {
736 DPRINT1("CDevSettings::QueryGetData(Format %u)\n", (unsigned int)pformatetc->cfFormat);
737 }
738 }
739 #endif
740
741 return DV_E_FORMATETC;
742 }
743
744 static HRESULT STDMETHODCALLTYPE
745 CDevSettings_GetCanonicalFormatEtc(IDataObject* iface,
746 FORMATETC* pformatectIn,
747 FORMATETC* pformatetcOut)
748 {
749 HRESULT hr;
750
751 DPRINT1("CDevSettings::GetCanonicalFormatEtc\n");
752
753 hr = IDataObject_QueryGetData(iface,
754 pformatectIn);
755 if (SUCCEEDED(hr))
756 {
757 CopyMemory(pformatetcOut,
758 pformatectIn,
759 sizeof(FORMATETC));
760
761 /* Make sure the data is target device independent */
762 if (pformatectIn->ptd == NULL)
763 hr = DATA_S_SAMEFORMATETC;
764 else
765 {
766 pformatetcOut->ptd = NULL;
767 hr = S_OK;
768 }
769 }
770 else
771 {
772 ZeroMemory(pformatetcOut,
773 sizeof(FORMATETC));
774 }
775
776 return hr;
777 }
778
779 static HRESULT STDMETHODCALLTYPE
780 CDevSettings_SetData(IDataObject* iface,
781 FORMATETC* pformatetc,
782 STGMEDIUM* pmedium,
783 BOOL fRelease)
784 {
785 DPRINT1("CDevSettings::SetData UNIMPLEMENTED\n");
786 return E_NOTIMPL;
787 }
788
789 static __inline VOID
790 pCDevSettings_FillFormatEtc(FORMATETC *pFormatEtc,
791 CLIPFORMAT cf)
792 {
793 pFormatEtc->cfFormat = cf;
794 pFormatEtc->ptd = NULL;
795 pFormatEtc->dwAspect = DVASPECT_CONTENT;
796 pFormatEtc->lindex = -1;
797 pFormatEtc->tymed = TYMED_HGLOBAL;
798 }
799
800 static HRESULT STDMETHODCALLTYPE
801 CDevSettings_EnumFormatEtc(IDataObject* iface,
802 DWORD dwDirection,
803 IEnumFORMATETC** ppenumFormatEtc)
804 {
805 HRESULT hr;
806 FORMATETC fetc[9];
807 PCDevSettings This = impl_from_IDataObject(iface);
808
809 *ppenumFormatEtc = NULL;
810
811 if (dwDirection == DATADIR_GET)
812 {
813 pCDevSettings_FillFormatEtc(&fetc[0],
814 This->cfExtInterface);
815 pCDevSettings_FillFormatEtc(&fetc[1],
816 This->cfDisplayDevice);
817 pCDevSettings_FillFormatEtc(&fetc[2],
818 This->cfDisplayName);
819 pCDevSettings_FillFormatEtc(&fetc[3],
820 This->cfDisplayId);
821 pCDevSettings_FillFormatEtc(&fetc[4],
822 This->cfDisplayKey);
823 pCDevSettings_FillFormatEtc(&fetc[5],
824 This->cfDisplayStateFlags);
825 pCDevSettings_FillFormatEtc(&fetc[6],
826 This->cfMonitorName);
827 pCDevSettings_FillFormatEtc(&fetc[7],
828 This->cfMonitorDevice);
829 pCDevSettings_FillFormatEtc(&fetc[8],
830 This->cfPruningMode);
831
832 hr = SHCreateStdEnumFmtEtc(sizeof(fetc) / sizeof(fetc[0]),
833 fetc,
834 ppenumFormatEtc);
835 }
836 else
837 hr = E_NOTIMPL;
838
839 return hr;
840 }
841
842 static HRESULT STDMETHODCALLTYPE
843 CDevSettings_DAdvise(IDataObject* iface,
844 FORMATETC* pformatetc,
845 DWORD advf,
846 IAdviseSink* pAdvSink,
847 DWORD* pdwConnection)
848 {
849 *pdwConnection = 0;
850 return OLE_E_ADVISENOTSUPPORTED;
851 }
852
853 static HRESULT STDMETHODCALLTYPE
854 CDevSettings_DUnadvise(IDataObject* iface,
855 DWORD dwConnection)
856 {
857 return OLE_E_ADVISENOTSUPPORTED;
858 }
859
860 static HRESULT STDMETHODCALLTYPE
861 CDevSettings_EnumDAdvise(IDataObject* iface,
862 IEnumSTATDATA** ppenumAdvise)
863 {
864 *ppenumAdvise = NULL;
865 return OLE_E_ADVISENOTSUPPORTED;
866 }
867
868 static const struct IDataObjectVtbl vtblIDataObject = {
869 CDevSettings_QueryInterface,
870 CDevSettings_AddRef,
871 CDevSettings_Release,
872 CDevSettings_GetData,
873 CDevSettings_GetDataHere,
874 CDevSettings_QueryGetData,
875 CDevSettings_GetCanonicalFormatEtc,
876 CDevSettings_SetData,
877 CDevSettings_EnumFormatEtc,
878 CDevSettings_DAdvise,
879 CDevSettings_DUnadvise,
880 CDevSettings_EnumDAdvise,
881 };
882
883 IDataObject *
884 CreateDevSettings(PDISPLAY_DEVICE_ENTRY DisplayDeviceInfo)
885 {
886 PCDevSettings This;
887
888 This = HeapAlloc(GetProcessHeap(),
889 0,
890 sizeof(*This));
891 if (This != NULL)
892 {
893 This->lpIDataObjectVtbl = &vtblIDataObject;
894 This->ref = 1;
895
896 if (SUCCEEDED(pCDevSettings_Initialize(This,
897 DisplayDeviceInfo)))
898 {
899 return impl_to_interface(This, IDataObject);
900 }
901
902 CDevSettings_Release(impl_to_interface(This, IDataObject));
903 }
904
905 return NULL;
906 }
907
908 LONG WINAPI
909 DisplaySaveSettings(PVOID pContext,
910 HWND hwndPropSheet)
911 {
912 //PCDevSettings This = impl_from_IDataObject((IDataObject *)Context);
913 DPRINT("DisplaySaveSettings() UNIMPLEMENTED!\n");
914 return DISP_CHANGE_BADPARAM;
915 }