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