|
|
/**************************************************************************\
* Module Name: settings.cpp * * Contains Implementation of the CDisplaySettings class who is in charge of * the settings of a single display. This is the data base class who does the * real change display settings work * * Copyright (c) Microsoft Corp. 1992-1998 All Rights Reserved * \**************************************************************************/
#include "priv.h"
#include "DisplaySettings.h"
#include "ntreg.hxx"
extern int AskDynaCDS(HWND hDlg); INT_PTR CALLBACK KeepNewDlgProc(HWND hDlg, UINT message , WPARAM wParam, LPARAM lParam);
UINT g_cfDisplayDevice = 0; UINT g_cfDisplayName = 0; UINT g_cfDisplayDeviceID = 0; UINT g_cfMonitorDevice = 0; UINT g_cfMonitorName = 0; UINT g_cfMonitorDeviceID = 0; UINT g_cfExtensionInterface = 0; UINT g_cfDisplayDeviceKey = 0; UINT g_cfDisplayStateFlags = 0; UINT g_cfDisplayPruningMode = 0;
#define TF_DISPLAYSETTINGS 0
/*****************************************************************\
* * helper routine * \*****************************************************************/
int CDisplaySettings::_InsertSortedDwords( int val1, int val2, int cval, int **ppval) { int *oldpval = *ppval; int *tmppval; int i;
for (i=0; i<cval; i++) { tmppval = (*ppval) + (i * 2);
if (*tmppval == val1) { if (*(tmppval + 1) == val2) { return cval; } else if (*(tmppval + 1) > val2) { break; } } else if (*tmppval > val1) { break; } }
TraceMsg(TF_FUNC,"_InsertSortedDword, vals = %d %d, cval = %d, index = %d", val1, val2, cval, i);
*ppval = (int *) LocalAlloc(LPTR, (cval + 1) * 2 * sizeof(DWORD));
if (*ppval) { //
// Insert the items at the right location in the array
//
if (oldpval) { CopyMemory(*ppval, oldpval, i * 2 * sizeof(DWORD)); }
*(*ppval + (i * 2)) = val1; *(*ppval + (i * 2) + 1) = val2;
if (oldpval) { CopyMemory((*ppval) + 2 * (i + 1), oldpval+ (i * 2), (cval-i) * 2 * sizeof(DWORD));
LocalFree(oldpval); }
return (cval + 1); }
return 0; }
/*****************************************************************\
* * debug routine * \*****************************************************************/
#ifdef DEBUG
void CDisplaySettings::_Dump_CDisplaySettings(BOOL bAll) { TraceMsg(TF_DUMP_CSETTINGS,"Dump of CDisplaySettings structure"); TraceMsg(TF_DUMP_CSETTINGS,"\t _DisplayDevice = %s", _pDisplayDevice->DeviceName); TraceMsg(TF_DUMP_CSETTINGS,"\t _cpdm = %d", _cpdm ); TraceMsg(TF_DUMP_CSETTINGS,"\t _apdm = %08lx", _apdm );
TraceMsg(TF_DUMP_CSETTINGS,"\t OrgResolution = %d, %d", _ORGXRES, _ORGYRES ); TraceMsg(TF_DUMP_CSETTINGS,"\t _ptOrgPos = %d, %d", _ptOrgPos.x ,_ptOrgPos.y); TraceMsg(TF_DUMP_CSETTINGS,"\t OrgColor = %d", _ORGCOLOR ); TraceMsg(TF_DUMP_CSETTINGS,"\t OrgFrequency = %d", _ORGFREQ ); TraceMsg(TF_DUMP_CSETTINGS,"\t _pOrgDevmode = %08lx", _pOrgDevmode ); TraceMsg(TF_DUMP_CSETTINGS,"\t _fOrgAttached = %d", _fOrgAttached );
TraceMsg(TF_DUMP_CSETTINGS,"\t CurResolution = %d, %d", _CURXRES, _CURYRES ); TraceMsg(TF_DUMP_CSETTINGS,"\t _ptCurPos = %d, %d", _ptCurPos.x ,_ptCurPos.y); TraceMsg(TF_DUMP_CSETTINGS,"\t CurColor = %d", _CURCOLOR ); TraceMsg(TF_DUMP_CSETTINGS,"\t CurFrequency = %d", _CURFREQ ); TraceMsg(TF_DUMP_CSETTINGS,"\t _pCurDevmode = %08lx", _pCurDevmode ); TraceMsg(TF_DUMP_CSETTINGS,"\t _fCurAttached = %d", _fCurAttached );
TraceMsg(TF_DUMP_CSETTINGS,"\t _fUsingDefault = %d", _fUsingDefault ); TraceMsg(TF_DUMP_CSETTINGS,"\t _fPrimary = %d", _fPrimary ); TraceMsg(TF_DUMP_CSETTINGS,"\t _cRef = %d", _cRef );
if (bAll) { _Dump_CDevmodeList(); } }
void CDisplaySettings::_Dump_CDevmodeList(VOID) { ULONG i;
for (i=0; _apdm && (i<_cpdm); i++) { LPDEVMODE lpdm = (_apdm + i)->lpdm;
TraceMsg(TF_DUMP_CSETTINGS,"\t\t mode %d, %08lx, Flags %08lx, X=%d Y=%d C=%d F=%d O=%d FO=%d", i, lpdm, (_apdm + i)->dwFlags, lpdm->dmPelsWidth, lpdm->dmPelsHeight, lpdm->dmBitsPerPel, lpdm->dmDisplayFrequency, lpdm->dmDisplayOrientation, lpdm->dmDisplayFixedOutput); } }
void CDisplaySettings::_Dump_CDevmode(LPDEVMODE pdm) { TraceMsg(TF_DUMP_DEVMODE," Size = %d", pdm->dmSize); TraceMsg(TF_DUMP_DEVMODE," Fields = %08lx", pdm->dmFields); TraceMsg(TF_DUMP_DEVMODE," XPosition = %d", pdm->dmPosition.x); TraceMsg(TF_DUMP_DEVMODE," YPosition = %d", pdm->dmPosition.y); TraceMsg(TF_DUMP_DEVMODE," XResolution = %d", pdm->dmPelsWidth); TraceMsg(TF_DUMP_DEVMODE," YResolution = %d", pdm->dmPelsHeight); TraceMsg(TF_DUMP_DEVMODE," Bpp = %d", pdm->dmBitsPerPel); TraceMsg(TF_DUMP_DEVMODE," Frequency = %d", pdm->dmDisplayFrequency); TraceMsg(TF_DUMP_DEVMODE," Flags = %d", pdm->dmDisplayFlags); TraceMsg(TF_DUMP_DEVMODE," XPanning = %d", pdm->dmPanningWidth); TraceMsg(TF_DUMP_DEVMODE," YPanning = %d", pdm->dmPanningHeight); TraceMsg(TF_DUMP_DEVMODE," DPI = %d", pdm->dmLogPixels); TraceMsg(TF_DUMP_DEVMODE," DriverExtra = %d", pdm->dmDriverExtra); TraceMsg(TF_DUMP_DEVMODE," Orientation = %d", pdm->dmDisplayOrientation); TraceMsg(TF_DUMP_DEVMODE," FixedOutput = %d", pdm->dmDisplayFixedOutput); if (pdm->dmDriverExtra) { TraceMsg(TF_DUMP_CSETTINGS,"\t - %08lx %08lx", *(PULONG)(((PUCHAR)pdm)+pdm->dmSize), *(PULONG)(((PUCHAR)pdm)+pdm->dmSize + 4)); } }
#endif // DEBUG
//
// Lets perform the following operations on the list
//
// (1) Remove identical modes
// (2) Remove 16 color modes for which there is a 256
// color equivalent.
// (3) Remove modes with any dimension less than 640x480
//
void CDisplaySettings::_FilterModes() { DWORD i, j; LPDEVMODE pdm, pdm2; PMODEARRAY pMode, pMode2;
for (i = 0; _apdm && i < _cpdm; i++) { pMode = _apdm + i; pdm = pMode->lpdm;
// Skip any invalid modes
if (pMode->dwFlags & MODE_INVALID) { continue; }
//
// If any of the following conditions are true, then we want to
// remove the current mode.
//
// Remove any modes that are too small
if (pdm->dmPelsHeight < 480 || pdm->dmPelsWidth < 640) { TraceMsg(TF_DUMP_CSETTINGS,"_FilterModes: Mode %d - resolution too small", i); pMode->dwFlags |= MODE_INVALID; continue; }
// Remove any modes that would change the orientation
if (_bFilterOrientation) { if (pdm->dmFields & DM_DISPLAYORIENTATION && pdm->dmDisplayOrientation != _dwOrientation) { pMode->dwFlags |= MODE_INVALID; TraceMsg(TF_DUMP_CSETTINGS,"_FilterModes: Mode %d - Wrong Orientation", i); continue; } }
// Remove any modes that would change fixed output unless our current mode is
// native resolution
if (_bFilterFixedOutput && _dwFixedOutput != DMDFO_DEFAULT) { if (pdm->dmFields & DM_DISPLAYFIXEDOUTPUT && pdm->dmDisplayFixedOutput != _dwFixedOutput) { pMode->dwFlags |= MODE_INVALID; TraceMsg(TF_DUMP_CSETTINGS,"_FilterModes: Mode %d - Wrong FixedOutput", i); continue; } } // Remove any duplicate modes
for (j = i + 1; j < _cpdm; j++) { pMode2 = _apdm + j; pdm2 = pMode2->lpdm;
if (!(pMode2->dwFlags & MODE_INVALID) && pdm2->dmBitsPerPel == pdm->dmBitsPerPel && pdm2->dmPelsWidth == pdm->dmPelsWidth && pdm2->dmPelsHeight == pdm->dmPelsHeight && pdm2->dmDisplayFrequency == pdm->dmDisplayFrequency) { TraceMsg(TF_DUMP_CSETTINGS,"_FilterModes: Mode %d - Duplicate Mode", i); pMode2->dwFlags |= MODE_INVALID; } } } }
//
// _AddDevMode method
//
// This method builds the index lists for the matrix. There is one
// index list for each axes of the three dimemsional matrix of device
// modes.
//
// The entry is also automatically added to the linked list of modes if
// it is not alreay present in the list.
//
BOOL CDisplaySettings::_AddDevMode(LPDEVMODE lpdm) { if (lpdm) { PMODEARRAY newapdm, tempapdm;
newapdm = (PMODEARRAY) LocalAlloc(LPTR, (_cpdm + 1) * sizeof(MODEARRAY)); if (newapdm) { CopyMemory(newapdm, _apdm, _cpdm * sizeof(MODEARRAY));
(newapdm + _cpdm)->dwFlags &= ~MODE_INVALID; (newapdm + _cpdm)->dwFlags |= MODE_RAW; (newapdm + _cpdm)->lpdm = lpdm;
}
tempapdm = _apdm; _apdm = newapdm; _cpdm++;
if (tempapdm) { LocalFree(tempapdm); } }
return TRUE; }
//
// Return a list of Resolutions supported, given a color depth
//
int CDisplaySettings::GetResolutionList( int Color, PPOINT *ppRes) { DWORD i; int cRes = 0; int *pResTmp = NULL; LPDEVMODE pdm;
*ppRes = NULL;
for (i = 0; _apdm && (i < _cpdm); i++) { if(!_IsModeVisible(i)) { continue; }
if(!_IsModePreferred(i)) { continue; }
pdm = (_apdm + i)->lpdm;
if ((Color == -1) || (Color == (int)pdm->dmBitsPerPel)) { cRes = _InsertSortedDwords(pdm->dmPelsWidth, pdm->dmPelsHeight, cRes, &pResTmp); } }
*ppRes = (PPOINT) pResTmp;
return cRes; }
//
//
// Return a list of color depths supported
//
int CDisplaySettings::GetColorList( LPPOINT Res, PLONGLONG *ppColor) { DWORD i; int cColor = 0; int *pColorTmp = NULL; LPDEVMODE pdm;
for (i = 0; _apdm && (i < _cpdm); i++) { if(!_IsModeVisible(i)) { continue; }
if(!_IsModePreferred(i)) { continue; }
pdm = (_apdm + i)->lpdm;
if ((Res == NULL) || (Res->x == -1) || (Res->y == -1) || (Res->x == (int)pdm->dmPelsWidth) || (Res->y == (int)pdm->dmPelsHeight)) { cColor = _InsertSortedDwords(pdm->dmBitsPerPel, 0, cColor, &pColorTmp); } }
*ppColor = (PLONGLONG) pColorTmp;
return cColor; }
int CDisplaySettings::GetFrequencyList(int Color, LPPOINT Res, PLONGLONG *ppFreq) { DWORD i; int cFreq = 0; int *pFreqTmp = NULL; LPDEVMODE pdm; POINT res;
if (Color == -1) { Color = _CURCOLOR; }
if (Res == NULL) { MAKEXYRES(&res, _CURXRES, _CURYRES); } else { res = *Res; }
for (i = 0; _apdm && (i < _cpdm); i++) { if(!_IsModeVisible(i)) { continue; }
pdm = (_apdm + i)->lpdm;
if (res.x == (int)pdm->dmPelsWidth && res.y == (int)pdm->dmPelsHeight && Color == (int)pdm->dmBitsPerPel) { cFreq = _InsertSortedDwords(pdm->dmDisplayFrequency, 0, cFreq, &pFreqTmp); } }
*ppFreq = (PLONGLONG) pFreqTmp;
return cFreq; }
void CDisplaySettings::_SetCurrentValues(LPDEVMODE lpdm) { _pCurDevmode = lpdm;
//
// Don't save the other fields (like position) as they are programmed by
// the UI separately.
//
// This should only save hardware specific fields.
//
#ifdef DEBUG
TraceMsg(TF_DUMP_CSETTINGS,""); TraceMsg(TF_DUMP_CSETTINGS,"_SetCurrentValues complete"); _Dump_CDisplaySettings(FALSE); #endif
}
BOOL CDisplaySettings::_PerfectMatch(LPDEVMODE lpdm) { for (DWORD i = 0; _apdm && (i < _cpdm); i++) { if(!_IsModeVisible(i)) { continue; }
if ((_apdm + i)->lpdm == lpdm) { _SetCurrentValues((_apdm + i)->lpdm);
TraceMsg(TF_DISPLAYSETTINGS, "_PerfectMatch -- return TRUE");
return TRUE; } }
TraceMsg(TF_DISPLAYSETTINGS, "_PerfectMatch -- return FALSE");
return FALSE; }
BOOL CDisplaySettings::_ExactMatch(LPDEVMODE lpdm, BOOL bForceVisible) { LPDEVMODE pdm; ULONG i;
for (i = 0; _apdm && (i < _cpdm); i++) { pdm = (_apdm + i)->lpdm;
if ( ((lpdm->dmFields & DM_BITSPERPEL) && (pdm->dmBitsPerPel != lpdm->dmBitsPerPel))
||
((lpdm->dmFields & DM_PELSWIDTH) && (pdm->dmPelsWidth != lpdm->dmPelsWidth))
||
((lpdm->dmFields & DM_PELSHEIGHT) && (pdm->dmPelsHeight != lpdm->dmPelsHeight))
||
((lpdm->dmFields & DM_DISPLAYFREQUENCY) && (pdm->dmDisplayFrequency != lpdm->dmDisplayFrequency)) ) { continue; }
if (!_IsModeVisible(i)) { if (bForceVisible && ((((_apdm + i)->dwFlags) & MODE_INVALID) == 0) && _bIsPruningOn && ((((_apdm + i)->dwFlags) & MODE_RAW) == MODE_RAW)) { (_apdm + i)->dwFlags &= ~MODE_RAW; } else { continue; } }
_SetCurrentValues(pdm);
TraceMsg(TF_DISPLAYSETTINGS, "_ExactMatch -- return TRUE");
return TRUE; }
TraceMsg(TF_DISPLAYSETTINGS, "_ExactMatch -- return FALSE");
return FALSE; }
// JoelGros defined a feature where we prefer to give the user
// a color depth of at least 32-bit, or as close to that as the
// display supports. Bryan Starbuck (BryanSt) 3/9/2000
#define MAX_PREFERED_COLOR_DEPTH 32
void CDisplaySettings::_BestMatch(LPPOINT Res, int Color, IN BOOL fAutoSetColorDepth) { // -1 means match loosely, based on current _xxx value
LPDEVMODE pdm; LPDEVMODE pdmMatch = NULL; ULONG i;
for (i = 0; _apdm && (i < _cpdm); i++) { if(!_IsModeVisible(i)) { continue; }
pdm = (_apdm + i)->lpdm;
// Take care of exact matches
if ((Color != -1) && (Color != (int)pdm->dmBitsPerPel)) { continue; }
if ((Res != NULL) && (Res->x != -1) && ( (Res->x != (int)pdm->dmPelsWidth) || (Res->y != (int)pdm->dmPelsHeight)) ) { continue; }
// Find Best Match
if (pdmMatch == NULL) { pdmMatch = pdm; }
// Find best Color.
if (Color == -1) // Do they want best color matching?
{ if (fAutoSetColorDepth) { // This will use the "auto-set a good color depth" feature.
// The best match color depth will not equal the current color depth if
// we are going to need to work closer and closer to our desired color depth.
// (We may never reach it because the user may just have increased the resolution
// so the current color depth isn't supported)
// We prefer keep increasing the color depth to at least the current color depth.
// That may not be possible if that depth isn't supported at this resolution.
// We also would like to keep increasing it until we hit MAX_PREFERED_COLOR_DEPTH
// because colors of at least that deep benefit users.
// Do we need to decrease the color depth? Yes if
if (((int)pdmMatch->dmBitsPerPel > _CURCOLOR) && // the match is more than the current, and
((int)pdmMatch->dmBitsPerPel > MAX_PREFERED_COLOR_DEPTH)) // the match is more than the prefered max
{ // We will want to decrease it if this entry is smaller than our match.
if ((int)pdm->dmBitsPerPel < (int)pdmMatch->dmBitsPerPel) { pdmMatch = pdm; } } else { // We want to increase it if:
if (((int)pdm->dmBitsPerPel > (int)pdmMatch->dmBitsPerPel) && // this entry is larger than our match, and
((int)pdm->dmBitsPerPel <= max(_CURCOLOR, MAX_PREFERED_COLOR_DEPTH))) // this doesn't take us over our prefered max or current depth (which ever is higher).
{ pdmMatch = pdm; } } } else { // This falls back to the old behavior.
if ((int)pdmMatch->dmBitsPerPel > _CURCOLOR) { if ((int)pdm->dmBitsPerPel < (int)pdmMatch->dmBitsPerPel) { pdmMatch = pdm; } } else { if (((int)pdm->dmBitsPerPel > (int)pdmMatch->dmBitsPerPel) && ((int)pdm->dmBitsPerPel <= _CURCOLOR)) { pdmMatch = pdm; } } } }
// Find best Resolution.
if (((Res == NULL) || (Res->x == -1)) && (((int)pdmMatch->dmPelsWidth != _CURXRES) || ((int)pdmMatch->dmPelsHeight != _CURYRES))) { if (((int)pdmMatch->dmPelsWidth > _CURXRES) || (((int)pdmMatch->dmPelsWidth == _CURXRES) && ((int)pdmMatch->dmPelsHeight > _CURYRES))) { if (((int)pdm->dmPelsWidth < (int)pdmMatch->dmPelsWidth) || (((int)pdm->dmPelsWidth == (int)pdmMatch->dmPelsWidth) && ((int)pdm->dmPelsHeight < (int)pdmMatch->dmPelsHeight))) { pdmMatch = pdm; } } else { if (((int)pdm->dmPelsWidth > (int)pdmMatch->dmPelsWidth) || (((int)pdm->dmPelsWidth == (int)pdmMatch->dmPelsWidth) && ((int)pdm->dmPelsHeight > (int)pdmMatch->dmPelsHeight))) { if (((int)pdm->dmPelsWidth <= _CURXRES) || (((int)pdm->dmPelsWidth == _CURXRES) && ((int)pdm->dmPelsHeight <= _CURYRES))) { pdmMatch = pdm; } } } }
// Find best Frequency.
if (((int)pdmMatch->dmDisplayFrequency != _CURFREQ) && (!((Res == NULL) && ((int)pdmMatch->dmPelsWidth == _CURXRES) && ((int)pdmMatch->dmPelsHeight == _CURYRES) && (((int)pdm->dmPelsWidth != _CURXRES) || ((int)pdm->dmPelsHeight != _CURYRES)))) && (!((Color == -1) && ((int)pdmMatch->dmBitsPerPel == _CURCOLOR) && ((int)pdm->dmBitsPerPel != _CURCOLOR)))) { if ((int)pdmMatch->dmDisplayFrequency > _CURFREQ) { if ((int)pdm->dmDisplayFrequency < (int)pdmMatch->dmDisplayFrequency) { pdmMatch = pdm; } } else { if (((int)pdm->dmDisplayFrequency > (int)pdmMatch->dmDisplayFrequency) && ((int)pdm->dmDisplayFrequency <= _CURFREQ)) { pdmMatch = pdm; } } } }
_SetCurrentValues(pdmMatch); }
BOOL CDisplaySettings::GetMonitorName(LPTSTR pszName, DWORD cchSize) { DISPLAY_DEVICE ddTmp; DWORD cAttachedMonitors = 0, nMonitor = 0;
ZeroMemory(&ddTmp, sizeof(ddTmp)); ddTmp.cb = sizeof(DISPLAY_DEVICE);
while (EnumDisplayDevices(_pDisplayDevice->DeviceName, nMonitor, &ddTmp, 0)) { if (ddTmp.StateFlags & DISPLAY_DEVICE_ATTACHED) { ++cAttachedMonitors; if (cAttachedMonitors > 1) break;
// Single monitor
StringCchCopy(pszName, cchSize, (LPTSTR)ddTmp.DeviceString); } ++nMonitor;
ZeroMemory(&ddTmp, sizeof(ddTmp)); ddTmp.cb = sizeof(DISPLAY_DEVICE); }
if (cAttachedMonitors == 0) { // No monitors
LoadString(HINST_THISDLL, IDS_UNKNOWNMONITOR, pszName, cchSize); } else if (cAttachedMonitors > 1) { // Multiple monitors
LoadString(HINST_THISDLL, IDS_MULTIPLEMONITORS, pszName, cchSize); }
return (cAttachedMonitors != 0); }
BOOL CDisplaySettings::GetMonitorDevice(LPTSTR pszDevice, DWORD cchSize) { DISPLAY_DEVICE ddTmp;
ZeroMemory(&ddTmp, sizeof(ddTmp)); ddTmp.cb = sizeof(DISPLAY_DEVICE);
if (EnumDisplayDevices(_pDisplayDevice->DeviceName, 0, &ddTmp, 0)) { StringCchCopy(pszDevice, cchSize, (LPTSTR)ddTmp.DeviceName);
return TRUE; }
return FALSE; }
STDMETHODIMP CDisplaySettings::GetData(FORMATETC *pfmtetc, STGMEDIUM *pstgmed) { HRESULT hr;
ASSERT(this); ASSERT(pfmtetc); ASSERT(pstgmed);
// Ignore pfmtetc.ptd. All supported data formats are device-independent.
ZeroMemory(pstgmed, sizeof(*pstgmed));
if ((hr = QueryGetData(pfmtetc)) == S_OK) { LPTSTR pszOut = NULL; TCHAR szMonitorName[130]; TCHAR szMonitorDevice[40];
if (pfmtetc->cfFormat == g_cfExtensionInterface) { //
// Get the array of information back to the device
//
// Allocate a buffer large enough to store all of the information
//
PDESK_EXTENSION_INTERFACE pInterface;
pInterface = (PDESK_EXTENSION_INTERFACE) GlobalAlloc(GPTR, sizeof(DESK_EXTENSION_INTERFACE));
if (pInterface) { CRegistrySettings * RegSettings = new CRegistrySettings(_pDisplayDevice->DeviceKey);
if (RegSettings) { pInterface->cbSize = sizeof(DESK_EXTENSION_INTERFACE); pInterface->pContext = this;
pInterface->lpfnEnumAllModes = CDisplaySettings::_lpfnEnumAllModes; pInterface->lpfnSetSelectedMode = CDisplaySettings::_lpfnSetSelectedMode; pInterface->lpfnGetSelectedMode = CDisplaySettings::_lpfnGetSelectedMode; pInterface->lpfnSetPruningMode = CDisplaySettings::_lpfnSetPruningMode; pInterface->lpfnGetPruningMode = CDisplaySettings::_lpfnGetPruningMode;
RegSettings->GetHardwareInformation(&pInterface->Info);
pstgmed->tymed = TYMED_HGLOBAL; pstgmed->hGlobal = pInterface; pstgmed->pUnkForRelease = NULL;
hr = S_OK;
delete RegSettings; } } else { hr = E_OUTOFMEMORY; } } else if (pfmtetc->cfFormat == g_cfMonitorDeviceID) { hr = E_UNEXPECTED; } else if (pfmtetc->cfFormat == g_cfDisplayStateFlags) { DWORD* pdwStateFlags = (DWORD*)GlobalAlloc(GPTR, sizeof(DWORD)); if (pdwStateFlags) { *pdwStateFlags = _pDisplayDevice->StateFlags; pstgmed->tymed = TYMED_HGLOBAL; pstgmed->hGlobal = pdwStateFlags; pstgmed->pUnkForRelease = NULL; hr = S_OK; } else { hr = E_OUTOFMEMORY; } } else if (pfmtetc->cfFormat == g_cfDisplayPruningMode) { BYTE* pPruningMode = (BYTE*)GlobalAlloc(GPTR, sizeof(BYTE)); if (pPruningMode) { *pPruningMode = (BYTE)(_bCanBePruned && _bIsPruningOn ? 1 : 0); pstgmed->tymed = TYMED_HGLOBAL; pstgmed->hGlobal = pPruningMode; pstgmed->pUnkForRelease = NULL; hr = S_OK; } else { hr = E_OUTOFMEMORY; } } else if (pfmtetc->cfFormat == g_cfDisplayDeviceID) { { CRegistrySettings *pRegSettings = new CRegistrySettings(_pDisplayDevice->DeviceKey); if (pRegSettings) { pszOut = pRegSettings->GetDeviceInstanceId(); hr = CopyDataToStorage(pstgmed, pszOut); delete pRegSettings; } else { hr = E_OUTOFMEMORY; } } } else { if (pfmtetc->cfFormat == g_cfMonitorName) { GetMonitorName(szMonitorName, ARRAYSIZE(szMonitorName)); pszOut = szMonitorName; } else if (pfmtetc->cfFormat == g_cfMonitorDevice) { GetMonitorDevice(szMonitorDevice, ARRAYSIZE(szMonitorDevice)); pszOut = szMonitorDevice; } else if (pfmtetc->cfFormat == g_cfDisplayDevice) { pszOut = (LPTSTR)_pDisplayDevice->DeviceName; } else if (pfmtetc->cfFormat == g_cfDisplayDeviceKey) { pszOut = (LPTSTR)_pDisplayDevice->DeviceKey; } else { ASSERT(pfmtetc->cfFormat == g_cfDisplayName); pszOut = (LPTSTR)_pDisplayDevice->DeviceString; }
hr = CopyDataToStorage(pstgmed, pszOut); } }
return(hr); }
STDMETHODIMP CDisplaySettings::CopyDataToStorage(STGMEDIUM *pstgmed, LPTSTR pszOut) { HRESULT hr = E_UNEXPECTED; int cch;
if (NULL != pszOut) { cch = lstrlen(pszOut) + 1;
LPWSTR pwszDevice = (LPWSTR)GlobalAlloc(GPTR, cch * sizeof(WCHAR)); if (pwszDevice) { //
// We always return UNICODE string
//
StringCchCopy(pwszDevice, cch, pszOut); pstgmed->tymed = TYMED_HGLOBAL; pstgmed->hGlobal = pwszDevice; pstgmed->pUnkForRelease = NULL;
hr = S_OK; } else { hr = E_OUTOFMEMORY; } }
return hr; }
STDMETHODIMP CDisplaySettings::GetDataHere(FORMATETC *pfmtetc, STGMEDIUM *pstgpmed) { ZeroMemory(pfmtetc, sizeof(*pfmtetc)); return E_NOTIMPL; }
//
// Check that all the parameters to the interface are appropriately
//
STDMETHODIMP CDisplaySettings::QueryGetData(FORMATETC *pfmtetc) { CLIPFORMAT cfFormat;
if (pfmtetc->dwAspect != DVASPECT_CONTENT) { return DV_E_DVASPECT; }
if ((pfmtetc->tymed & TYMED_HGLOBAL) == 0) { return DV_E_TYMED; }
cfFormat = pfmtetc->cfFormat;
if ((cfFormat != g_cfDisplayDevice) && (cfFormat != g_cfDisplayName) && (cfFormat != g_cfDisplayDeviceID) && (cfFormat != g_cfMonitorDevice) && (cfFormat != g_cfMonitorName) && (cfFormat != g_cfMonitorDeviceID) && (cfFormat != g_cfExtensionInterface) && (cfFormat != g_cfDisplayDeviceKey) && (cfFormat != g_cfDisplayStateFlags) && (cfFormat != g_cfDisplayPruningMode)) { return DV_E_FORMATETC; }
if (pfmtetc->lindex != -1) { return DV_E_LINDEX; }
return S_OK; }
STDMETHODIMP CDisplaySettings::GetCanonicalFormatEtc(FORMATETC *pfmtetcIn, FORMATETC *pfmtetcOut) { HRESULT hr; ASSERT(pfmtetcIn); ASSERT(pfmtetcOut);
hr = QueryGetData(pfmtetcIn);
if (hr == S_OK) { *pfmtetcOut = *pfmtetcIn;
if (pfmtetcIn->ptd == NULL) hr = DATA_S_SAMEFORMATETC; else { pfmtetcIn->ptd = NULL; ASSERT(hr == S_OK); } } else ZeroMemory(pfmtetcOut, sizeof(*pfmtetcOut)); return(hr); }
STDMETHODIMP CDisplaySettings::SetData(FORMATETC *pfmtetc, STGMEDIUM *pstgmed, BOOL bRelease) { return E_NOTIMPL; }
STDMETHODIMP CDisplaySettings::EnumFormatEtc(DWORD dwDirFlags, IEnumFORMATETC ** ppiefe) { HRESULT hr;
ASSERT(ppiefe); *ppiefe = NULL;
if (dwDirFlags == DATADIR_GET) { FORMATETC rgfmtetc[] = { { (CLIPFORMAT)g_cfDisplayDevice, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }, { (CLIPFORMAT)g_cfDisplayName, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }, { (CLIPFORMAT)g_cfMonitorDevice, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }, { (CLIPFORMAT)g_cfMonitorName, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }, { (CLIPFORMAT)g_cfExtensionInterface, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }, { (CLIPFORMAT)g_cfDisplayDeviceID, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }, { (CLIPFORMAT)g_cfMonitorDeviceID, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }, { (CLIPFORMAT)g_cfDisplayDeviceKey, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }, { (CLIPFORMAT)g_cfDisplayStateFlags, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }, { (CLIPFORMAT)g_cfDisplayPruningMode, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }, };
hr = SHCreateStdEnumFmtEtc(ARRAYSIZE(rgfmtetc), rgfmtetc, ppiefe); } else hr = E_NOTIMPL;
return(hr); }
STDMETHODIMP CDisplaySettings::DAdvise(FORMATETC *pfmtetc, DWORD dwAdviseFlags, IAdviseSink * piadvsink, DWORD * pdwConnection) { ASSERT(pfmtetc); ASSERT(pdwConnection);
*pdwConnection = 0; return OLE_E_ADVISENOTSUPPORTED; }
STDMETHODIMP CDisplaySettings::DUnadvise(DWORD dwConnection) { return OLE_E_ADVISENOTSUPPORTED; }
STDMETHODIMP CDisplaySettings::EnumDAdvise(IEnumSTATDATA ** ppiesd) { ASSERT(ppiesd); *ppiesd = NULL; return OLE_E_ADVISENOTSUPPORTED; }
void CDisplaySettings::_InitClipboardFormats() { if (g_cfDisplayDevice == 0) g_cfDisplayDevice = RegisterClipboardFormat(DESKCPLEXT_DISPLAY_DEVICE);
if (g_cfDisplayDeviceID == 0) g_cfDisplayDeviceID = RegisterClipboardFormat(DESKCPLEXT_DISPLAY_ID); if (g_cfDisplayName == 0) g_cfDisplayName = RegisterClipboardFormat(DESKCPLEXT_DISPLAY_NAME);
if (g_cfMonitorDevice == 0) g_cfMonitorDevice = RegisterClipboardFormat(DESKCPLEXT_MONITOR_DEVICE);
if (g_cfMonitorDeviceID == 0) g_cfMonitorDeviceID = RegisterClipboardFormat(DESKCPLEXT_MONITOR_ID); if (g_cfMonitorName == 0) g_cfMonitorName = RegisterClipboardFormat(DESKCPLEXT_MONITOR_NAME);
if (g_cfExtensionInterface == 0) g_cfExtensionInterface = RegisterClipboardFormat(DESKCPLEXT_INTERFACE);
if (g_cfDisplayDeviceKey == 0) g_cfDisplayDeviceKey = RegisterClipboardFormat(DESKCPLEXT_DISPLAY_DEVICE_KEY);
if (g_cfDisplayStateFlags == 0) g_cfDisplayStateFlags = RegisterClipboardFormat(DESKCPLEXT_DISPLAY_STATE_FLAGS); if (g_cfDisplayPruningMode == 0) g_cfDisplayPruningMode = RegisterClipboardFormat(DESKCPLEXT_PRUNING_MODE); }
HRESULT CDisplaySettings::QueryInterface(REFIID riid, LPVOID * ppvObj) { static const QITAB qit[] = { QITABENT(CDisplaySettings, IDataObject), QITABENT(CDisplaySettings, IDisplaySettings), { 0 }, };
return QISearch(this, qit, riid, ppvObj); }
ULONG CDisplaySettings::AddRef() { return InterlockedIncrement(&_cRef); }
ULONG CDisplaySettings::Release() { ASSERT( 0 != _cRef ); ULONG cRef = InterlockedDecrement(&_cRef); if ( 0 == cRef ) { delete this; } return cRef; }
STDMETHODIMP_(LPDEVMODEW) CDisplaySettings::_lpfnEnumAllModes( LPVOID pContext, DWORD iMode) { DWORD cCount = 0; DWORD i;
CDisplaySettings *pSettings = (CDisplaySettings *) pContext;
for (i = 0; pSettings->_apdm && (i < pSettings->_cpdm); i++) { // Don't show invalid modes or raw modes if pruning is on;
if(!_IsModeVisible(pSettings, i)) { continue; }
if (cCount == iMode) { return (pSettings->_apdm + i)->lpdm; }
cCount++; }
return NULL; }
STDMETHODIMP_(BOOL) CDisplaySettings::_lpfnSetSelectedMode( LPVOID pContext, LPDEVMODEW lpdm) { CDisplaySettings *pSettings = (CDisplaySettings *) pContext;
return pSettings->_PerfectMatch(lpdm); }
STDMETHODIMP_(LPDEVMODEW) CDisplaySettings::_lpfnGetSelectedMode( LPVOID pContext ) { CDisplaySettings *pSettings = (CDisplaySettings *) pContext;
return pSettings->_pCurDevmode; }
STDMETHODIMP_(VOID) CDisplaySettings::_lpfnSetPruningMode( LPVOID pContext, BOOL bIsPruningOn) { CDisplaySettings *pSettings = (CDisplaySettings *) pContext; pSettings->SetPruningMode(bIsPruningOn); }
STDMETHODIMP_(VOID) CDisplaySettings::_lpfnGetPruningMode( LPVOID pContext, BOOL* pbCanBePruned, BOOL* pbIsPruningReadOnly, BOOL* pbIsPruningOn) { CDisplaySettings *pSettings = (CDisplaySettings *) pContext; pSettings->GetPruningMode(pbCanBePruned, pbIsPruningReadOnly, pbIsPruningOn); }
// If any attached device is at 640x480, we want to force small font
BOOL CDisplaySettings::IsSmallFontNecessary() { if (_fOrgAttached || _fCurAttached) { //
// Force Small fonts at 640x480
//
if (_CURXRES < 800 || _CURYRES < 600) return TRUE; } return FALSE; }
// Constructor for CDisplaySettings
//
// (gets called when ever a CDisplaySettings object is created)
//
CDisplaySettings::CDisplaySettings() : _cRef(1) , _cpdm(0) , _apdm(0) , _hPruningRegKey(NULL) , _bCanBePruned(FALSE) , _bIsPruningReadOnly(TRUE) , _bIsPruningOn(FALSE) , _pOrgDevmode(NULL) , _pCurDevmode(NULL) , _fOrgAttached(FALSE) , _fCurAttached(FALSE) , _bFilterOrientation(FALSE) , _bFilterFixedOutput(FALSE) { SetRectEmpty(&_rcPreview); }
//
// Destructor
//
CDisplaySettings::~CDisplaySettings() {
TraceMsg(TF_DISPLAYSETTINGS, "**** Destructing %s", _pDisplayDevice->DeviceName);
if (_apdm) { while(_cpdm--) { LocalFree((_apdm + _cpdm)->lpdm); } LocalFree(_apdm); _apdm = NULL; }
_cpdm = 0;
if(NULL != _hPruningRegKey) RegCloseKey(_hPruningRegKey); }
//
// InitSettings -- Enumerate the settings, and build the mode list when
//
BOOL CDisplaySettings::InitSettings(LPDISPLAY_DEVICE pDisplay) { BOOL fReturn = FALSE; LPDEVMODE pdevmode = (LPDEVMODE) LocalAlloc(LPTR, (sizeof(DEVMODE) + 0xFFFF));
if (pdevmode) { ULONG i = 0; BOOL bCurrent = FALSE; BOOL bRegistry = FALSE; BOOL bExact = FALSE;
fReturn = TRUE;
// Set the cached values for modes.
MAKEXYRES(&_ptCurPos, 0, 0); _fCurAttached = FALSE; _pCurDevmode = NULL;
// Save the display name
ASSERT(pDisplay);
_pDisplayDevice = pDisplay;
TraceMsg(TF_GENERAL, "Initializing CDisplaySettings for %s", _pDisplayDevice->DeviceName);
// Pruning Mode
_bCanBePruned = ((_pDisplayDevice->StateFlags & DISPLAY_DEVICE_MODESPRUNED) != 0); _bIsPruningReadOnly = TRUE; _bIsPruningOn = FALSE; if (_bCanBePruned) { _bIsPruningOn = TRUE; // if can be pruned, by default pruning is on
GetDeviceRegKey(_pDisplayDevice->DeviceKey, &_hPruningRegKey, &_bIsPruningReadOnly); if (_hPruningRegKey) { DWORD dwIsPruningOn = 1; DWORD cb = sizeof(dwIsPruningOn); RegQueryValueEx(_hPruningRegKey, SZ_PRUNNING_MODE, NULL, NULL, (LPBYTE)&dwIsPruningOn, &cb); _bIsPruningOn = (dwIsPruningOn != 0); } }
// See if we need to filter modes by orientation and/or stretched/centered
ZeroMemory(pdevmode,sizeof(DEVMODE)); pdevmode->dmSize = sizeof(DEVMODE);
if (EnumDisplaySettingsExWrap(_pDisplayDevice->DeviceName, ENUM_CURRENT_SETTINGS, pdevmode, 0)) { if (pdevmode->dmFields & DM_DISPLAYORIENTATION) { _bFilterOrientation = TRUE; _dwOrientation = pdevmode->dmDisplayOrientation; TraceMsg(TF_GENERAL, "Filtering modes on orientation %d", _dwOrientation); } if (pdevmode->dmFields & DM_DISPLAYFIXEDOUTPUT) { _bFilterFixedOutput = TRUE; _dwFixedOutput = pdevmode->dmDisplayFixedOutput; TraceMsg(TF_GENERAL, "Filtering modes on fixed output %d", _dwFixedOutput); } } // Lets generate a list with all the possible modes.
pdevmode->dmSize = sizeof(DEVMODE);
// Enum the raw list of modes
while (EnumDisplaySettingsExWrap(_pDisplayDevice->DeviceName, i++, pdevmode, EDS_RAWMODE)) { WORD dmsize = pdevmode->dmSize + pdevmode->dmDriverExtra; LPDEVMODE lpdm = (LPDEVMODE) LocalAlloc(LPTR, dmsize);
if (lpdm) { CopyMemory(lpdm, pdevmode, dmsize); _AddDevMode(lpdm); }
pdevmode->dmDriverExtra = 0; }
// Filter the list of modes
_FilterModes(); if(_bCanBePruned) { // Enum pruned list of modes
i = 0; _bCanBePruned = FALSE; while (EnumDisplaySettingsExWrap(_pDisplayDevice->DeviceName, i++, pdevmode, 0)) { if(_MarkMode(pdevmode)) _bCanBePruned = TRUE; // at least one non-raw mode
pdevmode->dmDriverExtra = 0; }
if(!_bCanBePruned) { _bIsPruningReadOnly = TRUE; _bIsPruningOn = FALSE; } }
#ifdef DEBUG
// Debug
_Dump_CDisplaySettings(TRUE); #endif
// Get the current mode
ZeroMemory(pdevmode,sizeof(*pdevmode)); pdevmode->dmSize = sizeof(*pdevmode);
bCurrent = EnumDisplaySettingsExWrap(_pDisplayDevice->DeviceName, ENUM_CURRENT_SETTINGS, pdevmode, 0);
if (!bCurrent) { TraceMsg(TF_DISPLAYSETTINGS, "InitSettings -- No Current Mode. Try to use registry settings."); ZeroMemory(pdevmode,sizeof(*pdevmode)); pdevmode->dmSize = sizeof(*pdevmode);
bRegistry = EnumDisplaySettingsExWrap(_pDisplayDevice->DeviceName, ENUM_REGISTRY_SETTINGS, pdevmode, 0); }
// Set the default values based on registry or current settings.
if (bCurrent || bRegistry) { #ifdef DEBUG
// Check if this DEVMODE is in the list
TraceMsg(TF_FUNC, "Devmode for Exact Matching"); _Dump_CDevmode(pdevmode); TraceMsg(TF_FUNC, ""); #endif
// If the current mode is not in the list of modes supported by
// the monitor, we want to show it anyway.
//
// Consider the following scenario: the user sets the display
// to 1024x768 and after that it goes to DevManager and selects
// a monitor type that can not do that mode. When the user
// reopens the applet the current mode will be pruned out.
// In such a case we want the current mode to be visible.
bExact = _ExactMatch(pdevmode, TRUE);
// Is attached?
if(bCurrent) { _fOrgAttached = _fCurAttached = ((pdevmode->dmFields & DM_POSITION) ? 1 : 0); } // Set the original values
if (bExact == TRUE) { MAKEXYRES(&_ptCurPos, pdevmode->dmPosition.x, pdevmode->dmPosition.y); ConfirmChangeSettings(); } }
// If we have no modes, return FALSE.
if (_cpdm == 0) { FmtMessageBox(ghwndPropSheet, MB_ICONEXCLAMATION, MSG_CONFIGURATION_PROBLEM, MSG_INVALID_OLD_DISPLAY_DRIVER);
fReturn = FALSE; } else { // If there were no current values, set some now
// But don't confirm them ...
if (bExact == FALSE) { TraceMsg(TF_DISPLAYSETTINGS, "InitSettings -- No Current OR Registry Mode");
i = 0; // Try setting any mode as the current.
while (_apdm && (_PerfectMatch((_apdm + i++)->lpdm) == FALSE)) { if (i > _cpdm) { FmtMessageBox(ghwndPropSheet, MB_ICONEXCLAMATION, MSG_CONFIGURATION_PROBLEM, MSG_INVALID_OLD_DISPLAY_DRIVER);
fReturn = FALSE; break; } } if (fReturn && _fCurAttached) { MAKEXYRES(&_ptCurPos, _pCurDevmode->dmPosition.x, _pCurDevmode->dmPosition.y); } }
if (fReturn) { // Export our interfaces for extended properly pages.
_InitClipboardFormats();
#ifdef DEBUG
// Final debug output
TraceMsg(TF_DUMP_CSETTINGS," InitSettings successful - current values :"); _Dump_CDisplaySettings(FALSE); #endif
} }
LocalFree(pdevmode); }
return TRUE; }
// SaveSettings
//
// Writes the new display parameters to the proper place in the
// registry.
int CDisplaySettings::SaveSettings(DWORD dwSet) { int iResult = 0;
if (_pCurDevmode) { // Make a copy of the current devmode
ULONG dmSize = _pCurDevmode->dmSize + _pCurDevmode->dmDriverExtra; PDEVMODE pdevmode = (LPDEVMODE) LocalAlloc(LPTR, dmSize);
if (pdevmode) { CopyMemory(pdevmode, _pCurDevmode, dmSize);
// Save all of the new values out to the registry
// Resolution color bits and frequency
//
// We always have to set DM_POSITION when calling the API.
// In order to remove a device from the desktop, what actually needs
// to be done is provide an empty rectangle.
pdevmode->dmFields |= DM_POSITION;
if (!_fCurAttached) { pdevmode->dmPelsWidth = 0; pdevmode->dmPelsHeight = 0; } else { pdevmode->dmPosition.x = _ptCurPos.x; pdevmode->dmPosition.y = _ptCurPos.y; }
TraceMsg(TF_GENERAL, "SaveSettings:: Display: %s", _pDisplayDevice->DeviceName);
#ifdef DEBUG
_Dump_CDevmode(pdevmode); #endif
// These calls have NORESET flag set so that it only goes to
// change the registry settings, it does not refresh the display
// If EnumDisplaySettings was called with EDS_RAWMODE, we need CDS_RAWMODE below.
// Otherwise, it's harmless.
iResult = ChangeDisplaySettingsEx(_pDisplayDevice->DeviceName, pdevmode, NULL, CDS_RAWMODE | dwSet | ( _fPrimary ? CDS_SET_PRIMARY : 0), NULL);
if (iResult < 0) { TraceMsg(TF_DISPLAYSETTINGS, "**** SaveSettings:: ChangeDisplaySettingsEx not successful on %s", _pDisplayDevice->DeviceName); }
LocalFree(pdevmode); } }
return iResult; }
void ConvertStrToToken(LPTSTR pszString, DWORD cchSize) { while (pszString[0]) { if (TEXT('\\') == pszString[0]) { pszString[0] = TEXT(':'); }
pszString++; } }
HRESULT CDisplaySettings::_GetRegKey(LPDEVMODE pDevmode, int * pnIndex, LPTSTR pszRegKey, DWORD cchSize, LPTSTR pszRegValue, DWORD cchValueSize) { HRESULT hr = E_FAIL; DISPLAY_DEVICE ddMonitor = {0};
ddMonitor.cb = sizeof(ddMonitor); if (pDevmode && pDevmode->dmDeviceName && _pDisplayDevice && EnumDisplayDevices(_pDisplayDevice->DeviceName, *pnIndex, &ddMonitor, 0)) { TCHAR szMonitor[MAX_PATH]; TCHAR szVideoAdapter[MAX_PATH];
StringCchCopy(szMonitor, ARRAYSIZE(szMonitor), ddMonitor.DeviceID); StringCchCopy(szVideoAdapter, ARRAYSIZE(szVideoAdapter), _pDisplayDevice->DeviceID); ConvertStrToToken(szMonitor, ARRAYSIZE(szMonitor)); ConvertStrToToken(szVideoAdapter, ARRAYSIZE(szVideoAdapter));
StringCchPrintf(pszRegKey, cchSize, TEXT("%s\\%s\\%s,%d\\%dx%d x %dHz"), SZ_CP_SETTINGS_VIDEO, szVideoAdapter, szMonitor, *pnIndex, pDevmode->dmPelsWidth, pDevmode->dmPelsHeight, pDevmode->dmDisplayFrequency);
StringCchPrintf(pszRegValue, cchValueSize, TEXT("%d bpp"), pDevmode->dmBitsPerPel); hr = S_OK; }
return hr; }
BOOL CDisplaySettings::ConfirmChangeSettings() { // Succeeded, so, reset the original settings
_ptOrgPos = _ptCurPos; _pOrgDevmode = _pCurDevmode; _fOrgAttached = _fCurAttached;
// Now write the results to the registry so we know this is safe and can use it later.
TCHAR szRegKey[2*MAX_PATH]; TCHAR szRegValue[20]; int nIndex = 0;
while (SUCCEEDED(_GetRegKey(_pCurDevmode, &nIndex, szRegKey, ARRAYSIZE(szRegKey), szRegValue, ARRAYSIZE(szRegValue)))) { HKEY hKey;
if (SUCCEEDED(HrRegCreateKeyEx(HKEY_LOCAL_MACHINE, szRegKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, NULL))) { RegCloseKey(hKey); } HrRegSetDWORD(HKEY_LOCAL_MACHINE, szRegKey, szRegValue, 1); nIndex++; }
return TRUE; }
BOOL CDisplaySettings::IsKnownSafe(void) { TCHAR szRegKey[2*MAX_PATH]; TCHAR szRegValue[20]; BOOL fIsSafe = FALSE; int nIndex = 0;
while (SUCCEEDED(_GetRegKey(_pCurDevmode, &nIndex, szRegKey, ARRAYSIZE(szRegKey), szRegValue, ARRAYSIZE(szRegValue)))) { fIsSafe = HrRegGetDWORD(HKEY_LOCAL_MACHINE, szRegKey, szRegValue, 0); if (!fIsSafe) { break; }
nIndex++; }
// TODO: In Longhorn, just return TRUE as long as we were able to prune the list. If we could prune the list,
// then the driver dudes were able to get PnP IDs from the video cards (adapters) and monitors, so the list of
// supported modes should be accurate. If not, the drivers guys (ErickS) will fix. -BryanSt
return fIsSafe; }
int CDisplaySettings::RestoreSettings() { //
// Test failed, so restore the old settings, only restore the color and resolution
// information, and do restore the monitor position and its attached status
// Although this function is currently only called when restoring resolution
// the user could have changed position, then resolution and then clicked 'Apply,'
// in which case we want to revert position as well.
//
int iResult = DISP_CHANGE_SUCCESSFUL; PDEVMODE pdevmode;
//
// If this display was originally turned off, don't bother
//
if ((_pOrgDevmode != NULL) && ((_pOrgDevmode != _pCurDevmode) || (_ptOrgPos.x != _ptCurPos.x) || (_ptOrgPos.y != _ptCurPos.y) )) { iResult = DISP_CHANGE_NOTUPDATED; // Make a copy of the original devmode
ULONG dmSize = _pOrgDevmode->dmSize + _pOrgDevmode->dmDriverExtra; pdevmode = (LPDEVMODE) LocalAlloc(LPTR, dmSize);
if (pdevmode) { CopyMemory(pdevmode, _pOrgDevmode, dmSize);
pdevmode->dmFields |= DM_POSITION; pdevmode->dmPosition.x = _ptOrgPos.x; pdevmode->dmPosition.y = _ptOrgPos.y; if (!_fOrgAttached) { pdevmode->dmPelsWidth = 0; pdevmode->dmPelsHeight = 0; } TraceMsg(TF_GENERAL, "RestoreSettings:: Display: %s", _pDisplayDevice->DeviceName);
#ifdef DEBUG
_Dump_CDevmode(pdevmode); #endif
// If EnumDisplaySettings was called with EDS_RAWMODE, we need CDS_RAWMODE below.
// Otherwise, it's harmless.
iResult = ChangeDisplaySettingsEx(_pDisplayDevice->DeviceName, pdevmode, NULL, CDS_RAWMODE | CDS_UPDATEREGISTRY | CDS_NORESET | ( _fPrimary ? CDS_SET_PRIMARY : 0), NULL); if (iResult < 0 ) { TraceMsg(TF_DISPLAYSETTINGS, "**** RestoreSettings:: ChangeDisplaySettingsEx not successful on %s", _pDisplayDevice->DeviceName); ASSERT(FALSE); LocalFree(pdevmode); return iResult; } else { // Succeeded, so, reset the original settings
_ptCurPos = _ptOrgPos; _pCurDevmode = _pOrgDevmode; _fCurAttached = _fOrgAttached; if(_bCanBePruned && !_bIsPruningReadOnly && _bIsPruningOn && _IsCurDevmodeRaw()) SetPruningMode(FALSE); }
LocalFree(pdevmode); } }
return iResult; }
BOOL CDisplaySettings::_IsModeVisible(int i) { return _IsModeVisible(this, i); }
BOOL CDisplaySettings::_IsModeVisible(CDisplaySettings* pSettings, int i) { ASSERT(pSettings);
if (!pSettings->_apdm) { return FALSE; }
// (the mode is valid) AND
// ((pruning mode is off) OR (mode is not raw))
return ((!((pSettings->_apdm + i)->dwFlags & MODE_INVALID)) && ((!pSettings->_bIsPruningOn) || (!((pSettings->_apdm + i)->dwFlags & MODE_RAW)) ) ); }
BOOL CDisplaySettings::_IsModePreferred(int i) { LPDEVMODE pDevMode = ((PMODEARRAY)(_apdm + i))->lpdm;
if (_pCurDevmode == pDevMode) return TRUE;
BOOL bLandscape = (pDevMode->dmPelsWidth >= pDevMode->dmPelsHeight);
TraceMsg(TF_DUMP_CSETTINGS, "_IsModePreferred: %d x %d - landscape mode: %d", pDevMode->dmPelsWidth, pDevMode->dmPelsHeight, bLandscape);
// (the mode is valid) AND
// ((pruning mode is off) OR (mode is not raw))
return (pDevMode->dmBitsPerPel >= 15 && ((bLandscape && pDevMode->dmPelsWidth >= 800 && pDevMode->dmPelsHeight >= 600) || (!bLandscape && pDevMode->dmPelsWidth >= 600 && pDevMode->dmPelsHeight >= 800))); }
BOOL CDisplaySettings::_MarkMode(LPDEVMODE lpdm) { LPDEVMODE pdm; ULONG i; BOOL bMark = FALSE;
for (i = 0; _apdm && (i < _cpdm); i++) { if (!((_apdm + i)->dwFlags & MODE_INVALID)) { pdm = (_apdm + i)->lpdm;
if ( ((lpdm->dmFields & DM_BITSPERPEL) && (pdm->dmBitsPerPel == lpdm->dmBitsPerPel))
&&
((lpdm->dmFields & DM_PELSWIDTH) && (pdm->dmPelsWidth == lpdm->dmPelsWidth))
&&
((lpdm->dmFields & DM_PELSHEIGHT) && (pdm->dmPelsHeight == lpdm->dmPelsHeight))
&&
((lpdm->dmFields & DM_DISPLAYFREQUENCY) && (pdm->dmDisplayFrequency == lpdm->dmDisplayFrequency)) ) { (_apdm + i)->dwFlags &= ~MODE_RAW; bMark = TRUE; } } }
return bMark; }
BOOL CDisplaySettings::_IsCurDevmodeRaw() { LPDEVMODE pdm; ULONG i; BOOL bCurrentAndPruned = FALSE;
for (i = 0; _apdm && (i < _cpdm); i++) { if (!((_apdm + i)->dwFlags & MODE_INVALID) && ((_apdm + i)->dwFlags & MODE_RAW)) { pdm = (_apdm + i)->lpdm;
if ( ((_pCurDevmode->dmFields & DM_BITSPERPEL) && (pdm->dmBitsPerPel == _pCurDevmode->dmBitsPerPel))
&&
((_pCurDevmode->dmFields & DM_PELSWIDTH) && (pdm->dmPelsWidth == _pCurDevmode->dmPelsWidth))
&&
((_pCurDevmode->dmFields & DM_PELSHEIGHT) && (pdm->dmPelsHeight == _pCurDevmode->dmPelsHeight))
&&
((_pCurDevmode->dmFields & DM_DISPLAYFREQUENCY) && (pdm->dmDisplayFrequency == _pCurDevmode->dmDisplayFrequency)) ) { bCurrentAndPruned = TRUE; break; } } }
return bCurrentAndPruned; }
DISPLAY_DEVICE dd;
HRESULT CDisplaySettings::SetMonitor(DWORD dwMonitor) { ZeroMemory(&dd, sizeof(dd)); dd.cb = sizeof(DISPLAY_DEVICE);
DWORD dwMon = 0; for (DWORD dwCount = 0; EnumDisplayDevices(NULL, dwCount, &dd, 0); dwCount++) { if (!(dd.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER)) { if (dwMon == dwMonitor) { InitSettings(&dd); _fPrimary = (dd.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE); return S_OK; } dwMon++; } }
return E_INVALIDARG; }
HRESULT CDisplaySettings::GetModeCount(DWORD* pdwCount, BOOL fOnlyPreferredModes) { DWORD cCount = 0;
for (DWORD i = 0; _apdm && (i < _cpdm); i++) { // Don't show invalid modes or raw modes if pruning is on;
if(!_IsModeVisible(i)) { continue; }
if(fOnlyPreferredModes && (!_IsModePreferred(i))) { continue; }
cCount++; }
*pdwCount = cCount;
return S_OK; }
HRESULT CDisplaySettings::GetMode(DWORD dwMode, BOOL fOnlyPreferredModes, DWORD* pdwWidth, DWORD* pdwHeight, DWORD* pdwColor) { DWORD cCount = 0;
for (DWORD i = 0; _apdm && (i < _cpdm); i++) { // Don't show invalid modes or raw modes if pruning is on;
if(!_IsModeVisible(i)) { continue; }
if(fOnlyPreferredModes && (!_IsModePreferred(i))) { continue; }
if (cCount == dwMode) { LPDEVMODE lpdm = (_apdm + i)->lpdm; *pdwWidth = lpdm->dmPelsWidth; *pdwHeight = lpdm->dmPelsHeight; *pdwColor = lpdm->dmBitsPerPel;
return S_OK; }
cCount++; }
return E_INVALIDARG; }
DEVMODE dm;
HRESULT CDisplaySettings::SetSelectedMode(HWND hwnd, DWORD dwWidth, DWORD dwHeight, DWORD dwColor, BOOL* pfApplied, DWORD dwFlags) { dm.dmBitsPerPel = dwColor; dm.dmPelsWidth = dwWidth; dm.dmPelsHeight = dwHeight; dm.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT; *pfApplied = FALSE; POINT res = {dwWidth, dwHeight}; PLONGLONG freq = NULL; int cFreq = GetFrequencyList(dwColor, &res, &freq); if (cFreq) { dm.dmFields |= DM_DISPLAYFREQUENCY; // Default to lowest frequency
dm.dmDisplayFrequency = (DWORD)freq[0];
// Try to find a good frequency
for (int i = cFreq - 1; i >= 0; i--) { if ((freq[i] >= 60) && (freq[i] <= 72)) { dm.dmDisplayFrequency = (DWORD)freq[i]; } } } LocalFree(freq);
ULONG dmSize = _pCurDevmode->dmSize + _pCurDevmode->dmDriverExtra; PDEVMODE pOldDevMode = (LPDEVMODE) LocalAlloc(LPTR, dmSize);
if (pOldDevMode) { CopyMemory(pOldDevMode, _pCurDevmode, dmSize);
if (_ExactMatch(&dm, FALSE)) { // Verify that the mode actually works
if (SaveSettings(CDS_TEST) == DISP_CHANGE_SUCCESSFUL) { // Update the registry to specify the new display settings
if (SaveSettings(CDS_UPDATEREGISTRY | CDS_NORESET) == DISP_CHANGE_SUCCESSFUL) { // Refresh the display info from the registry, if you update directly ChangeDisplaySettings will do weird things in the fringe cases
if (ChangeDisplaySettings(NULL, CDS_RAWMODE) == DISP_CHANGE_SUCCESSFUL) { if (IsKnownSafe()) { // No need to warn, this is known to be a good value.
*pfApplied = TRUE; } else { INT_PTR iRet = DialogBoxParam(HINST_THISDLL, MAKEINTRESOURCE((dwFlags & DS_BACKUPDISPLAYCPL) ? DLG_KEEPNEW2 : DLG_KEEPNEW3), hwnd, KeepNewDlgProc, (dwFlags & DS_BACKUPDISPLAYCPL) ? 15 : 30); if ((IDYES == iRet) || (IDOK == iRet)) { *pfApplied = TRUE; } else { if (_ExactMatch(pOldDevMode, FALSE)) { SaveSettings(CDS_UPDATEREGISTRY | CDS_NORESET); ChangeDisplaySettings(NULL, CDS_RAWMODE); } if (dwFlags & DS_BACKUPDISPLAYCPL) { TCHAR szDeskCPL[MAX_PATH]; SystemPathAppend(szDeskCPL, TEXT("desk.cpl")); // Use shellexecuteex to run the display CPL
SHELLEXECUTEINFO shexinfo = {0}; shexinfo.cbSize = sizeof (shexinfo); shexinfo.fMask = SEE_MASK_FLAG_NO_UI; shexinfo.nShow = SW_SHOWNORMAL; shexinfo.lpFile = szDeskCPL; ShellExecuteEx(&shexinfo); } } } } } } }
LocalFree(pOldDevMode); }
return S_OK; }
HRESULT CDisplaySettings::GetSelectedMode(DWORD* pdwWidth, DWORD* pdwHeight, DWORD* pdwColor) { if (pdwWidth && pdwHeight && pdwColor) { if (_pCurDevmode) { *pdwWidth = _pCurDevmode->dmPelsWidth; *pdwHeight = _pCurDevmode->dmPelsHeight; *pdwColor = _pCurDevmode->dmBitsPerPel; return S_OK; } else { return E_FAIL; } } else { return E_INVALIDARG; } }
HRESULT CDisplaySettings::GetAttached(BOOL* pfAttached) { if (pfAttached) { *pfAttached = _fCurAttached; return S_OK; } else return E_INVALIDARG; }
HRESULT CDisplaySettings::SetPruningMode(BOOL fIsPruningOn) { ASSERT (_bCanBePruned && !_bIsPruningReadOnly); if (_bCanBePruned && !_bIsPruningReadOnly && ((fIsPruningOn != 0) != _bIsPruningOn)) { _bIsPruningOn = (fIsPruningOn != 0);
DWORD dwIsPruningOn = (DWORD)_bIsPruningOn; RegSetValueEx(_hPruningRegKey, SZ_PRUNNING_MODE, NULL, REG_DWORD, (LPBYTE) &dwIsPruningOn, sizeof(dwIsPruningOn));
//
// handle the special case when we pruned out the current mode
//
if(_bIsPruningOn && _IsCurDevmodeRaw()) { //
// switch to the closest mode
//
_BestMatch(NULL, -1, TRUE); } }
return S_OK; }
HRESULT CDisplaySettings::GetPruningMode(BOOL* pfCanBePruned, BOOL* pfIsPruningReadOnly, BOOL* pfIsPruningOn) { if (pfCanBePruned && pfIsPruningReadOnly && pfIsPruningOn) { *pfCanBePruned = _bCanBePruned; *pfIsPruningReadOnly = _bIsPruningReadOnly; *pfIsPruningOn = _bIsPruningOn; return S_OK; } else { return E_INVALIDARG; } }
HRESULT CDisplaySettings_CreateInstance(IN IUnknown * punkOuter, IN REFIID riid, OUT LPVOID * ppvObj) { HRESULT hr = E_INVALIDARG;
if (!punkOuter && ppvObj) { CDisplaySettings * pThis = new CDisplaySettings();
*ppvObj = NULL; if (pThis) { hr = pThis->QueryInterface(riid, ppvObj); pThis->Release(); } else { hr = E_OUTOFMEMORY; } }
return hr; }
|