/* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS Display Control Panel * FILE: dll/cpl/desk/devsett.c * PURPOSE: ReactOS Display Control Panel Shell Extension Support */ #include "desk.h" #include #define NDEBUG #include #define DEBUG_DEVSETTINGS typedef struct _CDevSettings { const struct IDataObjectVtbl *lpIDataObjectVtbl; DWORD ref; CLIPFORMAT cfExtInterface; /* "Desk.cpl extension interface" */ CLIPFORMAT cfDisplayDevice; /* "Display Device" */ CLIPFORMAT cfDisplayName; /* "Display Name" */ CLIPFORMAT cfDisplayId; /* "Display ID" */ CLIPFORMAT cfMonitorName; /* "Monitor Name" */ CLIPFORMAT cfMonitorDevice; /* "Monitor Device" */ CLIPFORMAT cfDisplayKey; /* "Display Key" */ CLIPFORMAT cfDisplayStateFlags; /* "Display State Flags" */ CLIPFORMAT cfPruningMode; /* "Pruning Mode" */ PWSTR pDisplayDevice; PWSTR pDisplayName; PWSTR pDisplayKey; PWSTR pDisplayId; PWSTR pMonitorName; PWSTR pMonitorDevice; DESK_EXT_INTERFACE ExtInterface; DWORD StateFlags; union { DWORD Flags; struct { DWORD bModesPruned : 1; DWORD bKeyIsReadOnly : 1; DWORD bPruningOn : 1; }; }; } CDevSettings, *PCDevSettings; #define impl_to_interface(impl,iface) (struct iface *)(&(impl)->lp##iface##Vtbl) static __inline PCDevSettings impl_from_IDataObject(struct IDataObject *iface) { return (PCDevSettings)((ULONG_PTR)iface - FIELD_OFFSET(CDevSettings, lpIDataObjectVtbl)); } static __inline VOID pCDevSettings_FreeString(PWCHAR *psz) { if (*psz != NULL) { LocalFree((HLOCAL)*psz); *psz = NULL; } } static PWSTR pCDevSettings_AllocAndCopyString(const TCHAR *pszSrc) { INT c; PWSTR str; c = _tcslen(pszSrc) + 1; str = (PWSTR)LocalAlloc(LMEM_FIXED, c * sizeof(WCHAR)); if (str != NULL) { #ifdef UNICODE StringCbCopyW(str, c * sizeof(WCHAR), pszSrc); #else MultiByteToWideChar(CP_ACP, 0, pszSrc, -1, str, c); #endif } return str; } static PWSTR pCDevSettings_GetMonitorName(const WCHAR *pszDisplayDevice) { DISPLAY_DEVICEW dd, dd2; PWSTR str = NULL; dd.cb = sizeof(dd); if (EnumDisplayDevicesW(pszDisplayDevice, 0, &dd, 0)) { dd2.cb = sizeof(dd2); if (EnumDisplayDevicesW(pszDisplayDevice, 1, &dd2, 0)) { /* There's more than one monitor connected... */ LoadStringW(hApplet, IDS_MULTIPLEMONITORS, dd.DeviceString, sizeof(dd.DeviceString) / sizeof(dd.DeviceString[0])); } } else { /* We can't enumerate a monitor, make sure this fact is reported to the user! */ LoadStringW(hApplet, IDS_UNKNOWNMONITOR, dd.DeviceString, sizeof(dd.DeviceString) / sizeof(dd.DeviceString[0])); } str = LocalAlloc(LMEM_FIXED, (wcslen(dd.DeviceString) + 1) * sizeof(WCHAR)); if (str != NULL) { wcscpy(str, dd.DeviceString); } return str; } static PWSTR pCDevSettings_GetMonitorDevice(const WCHAR *pszDisplayDevice) { DISPLAY_DEVICEW dd; PWSTR str = NULL; dd.cb = sizeof(dd); if (EnumDisplayDevicesW(pszDisplayDevice, 0, &dd, 0)) { str = LocalAlloc(LMEM_FIXED, (wcslen(dd.DeviceName) + 1) * sizeof(WCHAR)); if (str != NULL) { wcscpy(str, dd.DeviceName); } } return str; } static PWSTR pCDevSettings_GetDeviceInstanceId(const WCHAR *pszDevice) { DEVINST DevInst; CONFIGRET cr; ULONG BufLen; LPWSTR lpDevInstId = NULL; DPRINT1("CDevSettings::GetDeviceInstanceId(%ws) UNIMPLEMENTED!\n", pszDevice); cr = CM_Locate_DevNodeW(&DevInst, (DEVINSTID_W)pszDevice, CM_LOCATE_DEVNODE_NORMAL); if (cr == CR_SUCCESS) { DPRINT1("Success1\n"); cr = CM_Get_Device_ID_Size(&BufLen, DevInst, 0); if (cr == CR_SUCCESS) { DPRINT1("Success2\n"); lpDevInstId = LocalAlloc(LMEM_FIXED, (BufLen + 1) * sizeof(WCHAR)); if (lpDevInstId != NULL) { DPRINT1("Success3\n"); cr = CM_Get_Device_IDW(DevInst, lpDevInstId, BufLen, 0); if (cr != CR_SUCCESS) { LocalFree((HLOCAL)lpDevInstId); lpDevInstId = NULL; } DPRINT1("instance id: %ws\n", lpDevInstId); } } } return lpDevInstId; } static HKEY pCDevSettings_OpenDeviceKey(PCDevSettings This, BOOL ReadOnly) { static const WCHAR szRegPrefix[] = L"\\Registry\\Machine\\"; PWSTR lpRegKey; REGSAM Access = KEY_READ; HKEY hKey; lpRegKey = This->pDisplayKey; if (lpRegKey != NULL) { if (wcslen(lpRegKey) >= wcslen(szRegPrefix) && !_wcsnicmp(lpRegKey, szRegPrefix, wcslen(szRegPrefix))) { lpRegKey += wcslen(szRegPrefix); } if (!ReadOnly) Access |= KEY_WRITE; if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, lpRegKey, 0, Access, &hKey) == ERROR_SUCCESS) { return hKey; } } return NULL; } PDEVMODEW DESK_EXT_CALLBACK CDevSettings_EnumAllModes(PVOID Context, DWORD Index) { //PCDevSettings This = impl_from_IDataObject((IDataObject *)Context); /* FIXME: Implement */ DPRINT1("CDevSettings::EnumAllModes(%u)\n", Index); return NULL; } PDEVMODEW DESK_EXT_CALLBACK CDevSettings_GetCurrentMode(PVOID Context) { //PCDevSettings This = impl_from_IDataObject((IDataObject *)Context); /* FIXME: Implement */ DPRINT1("CDevSettings::GetCurrentMode\n"); return NULL; } BOOL DESK_EXT_CALLBACK CDevSettings_SetCurrentMode(PVOID Context, const DEVMODEW *pDevMode) { //PCDevSettings This = impl_from_IDataObject((IDataObject *)Context); /* FIXME: Implement */ DPRINT1("CDevSettings::SetCurrentMode(0x%p)\n", pDevMode); return FALSE; } VOID DESK_EXT_CALLBACK CDevSettings_GetPruningMode(PVOID Context, PBOOL pbModesPruned, PBOOL pbKeyIsReadOnly, PBOOL pbPruningOn) { PCDevSettings This = impl_from_IDataObject((IDataObject *)Context); DPRINT1("CDevSettings::GetPruningMode(%p,%p,%p)\n", pbModesPruned, pbKeyIsReadOnly, pbPruningOn); *pbModesPruned = This->bModesPruned; *pbKeyIsReadOnly = This->bKeyIsReadOnly; *pbPruningOn = This->bPruningOn; } VOID DESK_EXT_CALLBACK CDevSettings_SetPruningMode(PVOID Context, BOOL PruningOn) { HKEY hKey; DWORD dwValue; PCDevSettings This = impl_from_IDataObject((IDataObject *)Context); DPRINT1("CDevSettings::SetPruningMode(%d)\n", PruningOn); if (This->bModesPruned && !This->bKeyIsReadOnly && PruningOn != This->bPruningOn) { This->bPruningOn = (PruningOn != FALSE); hKey = pCDevSettings_OpenDeviceKey(This, FALSE); if (hKey != NULL) { dwValue = (DWORD)This->bPruningOn; RegSetValueEx(hKey, TEXT("PruningMode"), 0, REG_DWORD, (const BYTE *)&dwValue, sizeof(dwValue)); RegCloseKey(hKey); } } } static VOID pCDevSettings_ReadHardwareInfo(HKEY hKey, LPCTSTR lpValueName, LPWSTR lpBuffer) { DWORD type = REG_BINARY; DWORD size = 128 * sizeof(WCHAR); RegQueryValueEx(hKey, lpValueName, NULL, &type, (PBYTE)lpBuffer, &size); } static VOID pCDevSettings_InitializeExtInterface(PCDevSettings This) { PDESK_EXT_INTERFACE Interface = &This->ExtInterface; HKEY hKeyDev; ZeroMemory(Interface, sizeof(*Interface)); Interface->cbSize = sizeof(*Interface); /* Initialize the callback table */ Interface->Context = impl_to_interface(This, IDataObject); Interface->EnumAllModes = CDevSettings_EnumAllModes; Interface->SetCurrentMode = CDevSettings_SetCurrentMode; Interface->GetCurrentMode = CDevSettings_GetCurrentMode; Interface->SetPruningMode = CDevSettings_SetPruningMode; Interface->GetPruningMode = CDevSettings_GetPruningMode; /* Read the HardwareInformation.* values from the registry key */ hKeyDev = pCDevSettings_OpenDeviceKey(This, TRUE); if (hKeyDev != NULL) { DWORD dwType, dwMemSize = 0; DWORD dwSize = sizeof(dwMemSize); if (RegQueryValueEx(hKeyDev, TEXT("HardwareInformation.MemorySize"), NULL, &dwType, (PBYTE)&dwMemSize, &dwSize) == ERROR_SUCCESS && (dwType == REG_BINARY || dwType == REG_DWORD) && dwSize == sizeof(dwMemSize)) { dwMemSize /= 1024; if (dwMemSize > 1024) { dwMemSize /= 1024; if (dwMemSize > 1024) { wsprintf(Interface->MemorySize, _T("%u GB"), dwMemSize / 1024); } else { wsprintf(Interface->MemorySize, _T("%u MB"), dwMemSize); } } else { wsprintf(Interface->MemorySize, _T("%u KB"), dwMemSize); } } pCDevSettings_ReadHardwareInfo(hKeyDev, TEXT("HardwareInformation.ChipType"), Interface->ChipType); pCDevSettings_ReadHardwareInfo(hKeyDev, TEXT("HardwareInformation.DacType"), Interface->DacType); pCDevSettings_ReadHardwareInfo(hKeyDev, TEXT("HardwareInformation.AdapterString"), Interface->AdapterString); pCDevSettings_ReadHardwareInfo(hKeyDev, TEXT("HardwareInformation.BiosString"), Interface->BiosString); RegCloseKey(hKeyDev); } } static HRESULT pCDevSettings_Initialize(PCDevSettings This, PDISPLAY_DEVICE_ENTRY DisplayDeviceInfo) { HKEY hKey; This->Flags = 0; This->StateFlags = DisplayDeviceInfo->DeviceStateFlags; DPRINT1("This->StateFlags: %x\n", This->StateFlags); /* Register clipboard formats */ This->cfExtInterface = RegisterClipboardFormat(DESK_EXT_EXTINTERFACE); This->cfDisplayDevice = RegisterClipboardFormat(DESK_EXT_DISPLAYDEVICE); This->cfDisplayName = RegisterClipboardFormat(DESK_EXT_DISPLAYNAME); This->cfDisplayId = RegisterClipboardFormat(DESK_EXT_DISPLAYID); This->cfDisplayKey = RegisterClipboardFormat(DESK_EXT_DISPLAYKEY); This->cfDisplayStateFlags = RegisterClipboardFormat(DESK_EXT_DISPLAYSTATEFLAGS); This->cfMonitorName = RegisterClipboardFormat(DESK_EXT_MONITORNAME); This->cfMonitorDevice = RegisterClipboardFormat(DESK_EXT_MONITORDEVICE); This->cfPruningMode = RegisterClipboardFormat(DESK_EXT_PRUNINGMODE); /* Copy the device name */ This->pDisplayDevice = pCDevSettings_AllocAndCopyString(DisplayDeviceInfo->DeviceName); DPRINT1("This->pDisplayDevice: %ws\n", This->pDisplayDevice); This->pDisplayName = pCDevSettings_AllocAndCopyString(DisplayDeviceInfo->DeviceDescription); DPRINT1("This->pDisplayName: %ws\n", This->pDisplayName); This->pDisplayKey = pCDevSettings_AllocAndCopyString(DisplayDeviceInfo->DeviceKey); DPRINT1("This->pDisplayKey: %ws\n", This->pDisplayKey); This->pDisplayId = pCDevSettings_GetDeviceInstanceId(DisplayDeviceInfo->DeviceID); DPRINT1("This->pDisplayId: %ws\n", This->pDisplayId); This->pMonitorName = pCDevSettings_GetMonitorName(This->pDisplayDevice); DPRINT1("This->pMonitorName: %ws\n", This->pMonitorName); This->pMonitorDevice = pCDevSettings_GetMonitorDevice(This->pDisplayDevice); DPRINT1("This->pMonitorDevice: %ws\n", This->pMonitorDevice); /* Check pruning mode */ This->bModesPruned = ((DisplayDeviceInfo->DeviceStateFlags & DISPLAY_DEVICE_MODESPRUNED) != 0); hKey = pCDevSettings_OpenDeviceKey(This, FALSE); if (hKey == NULL) { hKey = pCDevSettings_OpenDeviceKey(This, FALSE); This->bKeyIsReadOnly = TRUE; } if (hKey != NULL) { DWORD dw = 0; DWORD dwType, dwSize; dwSize = sizeof(dw); if (RegQueryValueEx(hKey, TEXT("PruningMode"), NULL, &dwType, (PBYTE)&dw, &dwSize) == ERROR_SUCCESS) { if (dwType == REG_DWORD && dwSize == sizeof(dw)) This->bPruningOn = (dw != 0); } RegCloseKey(hKey); } /* Initialize the shell extension interface */ pCDevSettings_InitializeExtInterface(This); return S_OK; } static VOID pCDevSettings_Free(PCDevSettings This) { pCDevSettings_FreeString(&This->pDisplayDevice); pCDevSettings_FreeString(&This->pDisplayName); pCDevSettings_FreeString(&This->pDisplayKey); pCDevSettings_FreeString(&This->pDisplayId); pCDevSettings_FreeString(&This->pMonitorName); pCDevSettings_FreeString(&This->pMonitorDevice); } static HRESULT STDMETHODCALLTYPE CDevSettings_QueryInterface(IDataObject* iface, REFIID riid, void** ppvObject) { PCDevSettings This = impl_from_IDataObject(iface); *ppvObject = NULL; if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IDataObject)) { *ppvObject = (PVOID)impl_to_interface(This, IDataObject); return S_OK; } else { DPRINT1("CDevSettings::QueryInterface: Queried unknown interface\n"); } return E_NOINTERFACE; } static ULONG STDMETHODCALLTYPE CDevSettings_AddRef(IDataObject* iface) { PCDevSettings This = impl_from_IDataObject(iface); return (ULONG)InterlockedIncrement((PLONG)&This->ref); } static ULONG STDMETHODCALLTYPE CDevSettings_Release(IDataObject* iface) { ULONG refs; PCDevSettings This = impl_from_IDataObject(iface); refs = (ULONG)InterlockedDecrement((PLONG)&This->ref); if (refs == 0) pCDevSettings_Free(This); return refs; } static HRESULT STDMETHODCALLTYPE CDevSettings_GetData(IDataObject* iface, FORMATETC* pformatetcIn, STGMEDIUM* pmedium) { static const WCHAR szEmpty[] = {0}; HRESULT hr; PCWSTR pszRet = NULL; PWSTR pszBuf; PCDevSettings This = impl_from_IDataObject(iface); ZeroMemory(pmedium, sizeof(STGMEDIUM)); hr = IDataObject_QueryGetData(iface, pformatetcIn); if (SUCCEEDED(hr)) { /* Return the reqested data back to the shell extension */ if (pformatetcIn->cfFormat == This->cfDisplayDevice) { pszRet = This->pDisplayDevice; DPRINT1("CDevSettings::GetData returns display device %ws\n", pszRet); } else if (pformatetcIn->cfFormat == This->cfDisplayName) { pszRet = This->pDisplayName; DPRINT1("CDevSettings::GetData returns display name %ws\n", pszRet); } else if (pformatetcIn->cfFormat == This->cfDisplayKey) { pszRet = This->pDisplayKey; DPRINT1("CDevSettings::GetData returns display key %ws\n", pszRet); } else if (pformatetcIn->cfFormat == This->cfDisplayId) { pszRet = This->pDisplayId; DPRINT1("CDevSettings::GetData returns display id %ws\n", pszRet); } else if (pformatetcIn->cfFormat == This->cfMonitorName) { pszRet = This->pMonitorName; DPRINT1("CDevSettings::GetData returns monitor name %ws\n", pszRet); } else if (pformatetcIn->cfFormat == This->cfMonitorDevice) { pszRet = This->pMonitorDevice; DPRINT1("CDevSettings::GetData returns monitor device %ws\n", pszRet); } else if (pformatetcIn->cfFormat == This->cfExtInterface) { PDESK_EXT_INTERFACE pIface; pIface = GlobalAlloc(GPTR, sizeof(*pIface)); if (pIface != NULL) { CopyMemory(pIface, &This->ExtInterface, sizeof(This->ExtInterface)); DPRINT1("CDevSettings::GetData returns the desk.cpl extension interface\n"); pmedium->tymed = TYMED_HGLOBAL; pmedium->hGlobal = pIface; return S_OK; } else return E_OUTOFMEMORY; } else if (pformatetcIn->cfFormat == This->cfDisplayStateFlags) { PDWORD pdw; pdw = GlobalAlloc(GPTR, sizeof(*pdw)); if (pdw != NULL) { *pdw = This->StateFlags; DPRINT1("CDevSettings::GetData returns the display state flags %x\n", This->StateFlags); pmedium->tymed = TYMED_HGLOBAL; pmedium->hGlobal = pdw; return S_OK; } else return E_OUTOFMEMORY; } else if (pformatetcIn->cfFormat == This->cfPruningMode) { PBYTE pb; pb = GlobalAlloc(GPTR, sizeof(*pb)); if (pb != NULL) { *pb = (This->bModesPruned && This->bPruningOn); pmedium->tymed = TYMED_HGLOBAL; pmedium->hGlobal = pb; return S_OK; } else return E_OUTOFMEMORY; } /* NOTE: This only returns null-terminated strings! */ if (pszRet == NULL) pszRet = szEmpty; pszBuf = GlobalAlloc(GPTR, (wcslen(pszRet) + 1) * sizeof(WCHAR)); if (pszBuf != NULL) { hr = StringCbCopy(pszBuf, (wcslen(pszRet) + 1) * sizeof(WCHAR), pszRet); if (FAILED(hr)) { GlobalFree(pszBuf); return hr; } pmedium->tymed = TYMED_HGLOBAL; pmedium->hGlobal = pszBuf; hr = S_OK; } else hr = E_OUTOFMEMORY; } return hr; } static HRESULT STDMETHODCALLTYPE CDevSettings_GetDataHere(IDataObject* iface, FORMATETC* pformatetc, STGMEDIUM* pmedium) { ZeroMemory(pformatetc, sizeof(*pformatetc)); return E_NOTIMPL; } static HRESULT STDMETHODCALLTYPE CDevSettings_QueryGetData(IDataObject* iface, FORMATETC* pformatetc) { #if DEBUG TCHAR szFormatName[255]; #endif PCDevSettings This = impl_from_IDataObject(iface); if (pformatetc->dwAspect != DVASPECT_CONTENT) return DV_E_DVASPECT; if (pformatetc->lindex != -1) return DV_E_LINDEX; if (!(pformatetc->tymed & TYMED_HGLOBAL)) return DV_E_TYMED; /* Check if the requested data can be provided */ if (pformatetc->cfFormat == This->cfExtInterface || pformatetc->cfFormat == This->cfDisplayDevice || pformatetc->cfFormat == This->cfDisplayName || pformatetc->cfFormat == This->cfDisplayId || pformatetc->cfFormat == This->cfDisplayKey || pformatetc->cfFormat == This->cfDisplayStateFlags || pformatetc->cfFormat == This->cfMonitorDevice || pformatetc->cfFormat == This->cfMonitorName || pformatetc->cfFormat == This->cfPruningMode) { return S_OK; } #if DEBUG else { if (GetClipboardFormatName(pformatetc->cfFormat, szFormatName, sizeof(szFormatName) / sizeof(szFormatName[0]))) { DPRINT1("CDevSettings::QueryGetData(\"%ws\")\n", szFormatName); } else { DPRINT1("CDevSettings::QueryGetData(Format %u)\n", (unsigned int)pformatetc->cfFormat); } } #endif return DV_E_FORMATETC; } static HRESULT STDMETHODCALLTYPE CDevSettings_GetCanonicalFormatEtc(IDataObject* iface, FORMATETC* pformatectIn, FORMATETC* pformatetcOut) { HRESULT hr; DPRINT1("CDevSettings::GetCanonicalFormatEtc\n"); hr = IDataObject_QueryGetData(iface, pformatectIn); if (SUCCEEDED(hr)) { CopyMemory(pformatetcOut, pformatectIn, sizeof(FORMATETC)); /* Make sure the data is target device independent */ if (pformatectIn->ptd == NULL) hr = DATA_S_SAMEFORMATETC; else { pformatetcOut->ptd = NULL; hr = S_OK; } } else { ZeroMemory(pformatetcOut, sizeof(FORMATETC)); } return hr; } static HRESULT STDMETHODCALLTYPE CDevSettings_SetData(IDataObject* iface, FORMATETC* pformatetc, STGMEDIUM* pmedium, BOOL fRelease) { DPRINT1("CDevSettings::SetData UNIMPLEMENTED\n"); return E_NOTIMPL; } static __inline VOID pCDevSettings_FillFormatEtc(FORMATETC *pFormatEtc, CLIPFORMAT cf) { pFormatEtc->cfFormat = cf; pFormatEtc->ptd = NULL; pFormatEtc->dwAspect = DVASPECT_CONTENT; pFormatEtc->lindex = -1; pFormatEtc->tymed = TYMED_HGLOBAL; } static HRESULT STDMETHODCALLTYPE CDevSettings_EnumFormatEtc(IDataObject* iface, DWORD dwDirection, IEnumFORMATETC** ppenumFormatEtc) { HRESULT hr; FORMATETC fetc[9]; PCDevSettings This = impl_from_IDataObject(iface); *ppenumFormatEtc = NULL; if (dwDirection == DATADIR_GET) { pCDevSettings_FillFormatEtc(&fetc[0], This->cfExtInterface); pCDevSettings_FillFormatEtc(&fetc[1], This->cfDisplayDevice); pCDevSettings_FillFormatEtc(&fetc[2], This->cfDisplayName); pCDevSettings_FillFormatEtc(&fetc[3], This->cfDisplayId); pCDevSettings_FillFormatEtc(&fetc[4], This->cfDisplayKey); pCDevSettings_FillFormatEtc(&fetc[5], This->cfDisplayStateFlags); pCDevSettings_FillFormatEtc(&fetc[6], This->cfMonitorName); pCDevSettings_FillFormatEtc(&fetc[7], This->cfMonitorDevice); pCDevSettings_FillFormatEtc(&fetc[8], This->cfPruningMode); hr = SHCreateStdEnumFmtEtc(sizeof(fetc) / sizeof(fetc[0]), fetc, ppenumFormatEtc); } else hr = E_NOTIMPL; return hr; } static HRESULT STDMETHODCALLTYPE CDevSettings_DAdvise(IDataObject* iface, FORMATETC* pformatetc, DWORD advf, IAdviseSink* pAdvSink, DWORD* pdwConnection) { *pdwConnection = 0; return OLE_E_ADVISENOTSUPPORTED; } static HRESULT STDMETHODCALLTYPE CDevSettings_DUnadvise(IDataObject* iface, DWORD dwConnection) { return OLE_E_ADVISENOTSUPPORTED; } static HRESULT STDMETHODCALLTYPE CDevSettings_EnumDAdvise(IDataObject* iface, IEnumSTATDATA** ppenumAdvise) { *ppenumAdvise = NULL; return OLE_E_ADVISENOTSUPPORTED; } static const struct IDataObjectVtbl vtblIDataObject = { CDevSettings_QueryInterface, CDevSettings_AddRef, CDevSettings_Release, CDevSettings_GetData, CDevSettings_GetDataHere, CDevSettings_QueryGetData, CDevSettings_GetCanonicalFormatEtc, CDevSettings_SetData, CDevSettings_EnumFormatEtc, CDevSettings_DAdvise, CDevSettings_DUnadvise, CDevSettings_EnumDAdvise, }; IDataObject * CreateDevSettings(PDISPLAY_DEVICE_ENTRY DisplayDeviceInfo) { PCDevSettings This; This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); if (This != NULL) { This->lpIDataObjectVtbl = &vtblIDataObject; This->ref = 1; if (SUCCEEDED(pCDevSettings_Initialize(This, DisplayDeviceInfo))) { return impl_to_interface(This, IDataObject); } CDevSettings_Release(impl_to_interface(This, IDataObject)); } return NULL; } LONG WINAPI DisplaySaveSettings(PVOID pContext, HWND hwndPropSheet) { //PCDevSettings This = impl_from_IDataObject((IDataObject *)Context); DPRINT("DisplaySaveSettings() UNIMPLEMENTED!\n"); return DISP_CHANGE_BADPARAM; }