You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
253 lines
8.9 KiB
253 lines
8.9 KiB
#include "priv.h"
|
|
#include <regstr.h>
|
|
#include <atlcom.h>
|
|
#include <shguidp.h>
|
|
#include <shlguid.h>
|
|
|
|
typedef struct
|
|
{
|
|
DWORD dwWidth;
|
|
DWORD dwHeight;
|
|
DWORD dwColor;
|
|
BOOL fAvailable;
|
|
} SCREENMODE;
|
|
|
|
class ATL_NO_VTABLE CScreenResFixer :
|
|
public CComObjectRootEx<CComSingleThreadModel>,
|
|
public CComCoClass<CScreenResFixer, &CLSID_ScreenResFixer>,
|
|
public IContextMenu,
|
|
public IScreenResFixer
|
|
{
|
|
public:
|
|
CScreenResFixer() {}
|
|
virtual ~CScreenResFixer() {}
|
|
|
|
DECLARE_NOT_AGGREGATABLE(CScreenResFixer)
|
|
|
|
BEGIN_COM_MAP(CScreenResFixer)
|
|
COM_INTERFACE_ENTRY_IID(IID_IContextMenu, IContextMenu)
|
|
COM_INTERFACE_ENTRY(IScreenResFixer)
|
|
END_COM_MAP()
|
|
|
|
// *** IContextMenu methods ***
|
|
STDMETHODIMP QueryContextMenu(HMENU hmenu, UINT iIndexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags) { return E_NOTIMPL; }
|
|
STDMETHODIMP InvokeCommand(LPCMINVOKECOMMANDINFO lpici);
|
|
STDMETHODIMP GetCommandString(UINT_PTR idCmd, UINT uType, UINT *pRes, LPSTR pszName, UINT cchMax) { return E_NOTIMPL; }
|
|
|
|
private:
|
|
int _PickScreenResolution(SCREENMODE* modes, int cModes);
|
|
HRESULT _FixScreenResolution(BOOL fShowDisplayCPL);
|
|
};
|
|
|
|
// *** IContextMenu methods ***
|
|
STDMETHODIMP CScreenResFixer::InvokeCommand(LPCMINVOKECOMMANDINFO lpici)
|
|
{
|
|
WCHAR szTitle[256];
|
|
HRESULT hr;
|
|
|
|
szTitle[0] = 0;
|
|
LoadString(HINST_THISDLL, IDS_SCREENRESFIXER_TITLE, szTitle, ARRAYSIZE(szTitle));
|
|
|
|
BOOL fOK = FALSE;
|
|
if (lpici)
|
|
{
|
|
WCHAR szText[512];
|
|
szText[0] = 0;
|
|
LoadString(HINST_THISDLL, IDS_SCREENRESFIXER_TEXT, szText, ARRAYSIZE(szText));
|
|
fOK = (IDYES == SHMessageBoxCheck(NULL, szText, szTitle, MB_YESNO, 0, TEXT("ScreenCheck")));
|
|
}
|
|
else
|
|
{
|
|
WCHAR szText[512];
|
|
szText[0] = 0;
|
|
LoadString(HINST_THISDLL, IDS_SCREENRESFIXER_ALTTEXT, szText, ARRAYSIZE(szText));
|
|
fOK = (IDOK == MessageBox(NULL, szText, szTitle, MB_OK));
|
|
}
|
|
|
|
if (fOK)
|
|
{
|
|
hr = _FixScreenResolution(!(lpici == NULL));
|
|
}
|
|
else
|
|
{
|
|
// If the user checked "Don't show me again" then force this setting into HKLM, so that it doesn't
|
|
// show up for any users
|
|
if (!SHRegGetBoolUSValue(REGSTR_PATH_EXPLORER TEXT("\\DontShowMeThisDialogAgain"), TEXT("ScreenCheck"), FALSE, TRUE))
|
|
{
|
|
SHRegSetUSValueW(REGSTR_PATH_EXPLORER TEXT("\\DontShowMeThisDialogAgain"), TEXT("ScreenCheck"), REG_SZ, L"no", sizeof(L"no"), SHREGSET_HKLM);
|
|
}
|
|
|
|
hr = S_OK;
|
|
}
|
|
|
|
// Now that the user finished with their screen resolution, tell the Start Menu
|
|
// it's okay to pop up.
|
|
HWND hwndTray = FindWindow(TEXT(WNDCLASS_TRAYNOTIFY), NULL);
|
|
if (hwndTray)
|
|
PostMessage(hwndTray, RegisterWindowMessage(TEXT("Welcome Finished")), 0, 0);
|
|
|
|
return hr;
|
|
}
|
|
|
|
int CScreenResFixer::_PickScreenResolution(SCREENMODE* modes, int cModes)
|
|
{
|
|
static const struct {
|
|
int iMinWidth;
|
|
int iMinHeight;
|
|
int iMaxWidth;
|
|
int iMaxHeight;
|
|
int iIdealColor;
|
|
}
|
|
picker[] =
|
|
{
|
|
{ 800, 600, 1024, 768, 32 },
|
|
{ 800, 600, 1024, 768, 24 },
|
|
{ 800, 600, 1024, 768, -1 },
|
|
{ 1024, 768, -1, -1, 32 },
|
|
{ 1024, 768, -1, -1, 24 },
|
|
{ 1024, 768, -1, -1, -1 },
|
|
};
|
|
|
|
for (int i = 0; i < ARRAYSIZE(picker); i++)
|
|
{
|
|
// Try for Ideal Color in given resolution range
|
|
for (int iMode = 0; iMode < cModes; iMode++)
|
|
{
|
|
|
|
if ((modes[iMode].fAvailable) &&
|
|
(modes[iMode].dwWidth >= (DWORD)picker[i].iMinWidth) &&
|
|
(modes[iMode].dwHeight >= (DWORD)picker[i].iMinHeight))
|
|
{
|
|
if ((picker[i].iMaxWidth == -1) ||
|
|
((modes[iMode].dwWidth < (DWORD)picker[i].iMaxWidth) &&
|
|
(modes[iMode].dwHeight < (DWORD)picker[i].iMaxHeight)))
|
|
{
|
|
if (((picker[i].iIdealColor == -1) && (modes[iMode].dwColor >= 15)) ||
|
|
(modes[iMode].dwColor == (DWORD)picker[i].iIdealColor))
|
|
{
|
|
return iMode;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
void UpdateRecycleBinInfo()
|
|
{
|
|
static const LPTSTR lpszSubkey = TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ScreenResFixer");
|
|
static const LPTSTR lpszValue = TEXT("AdjustRecycleBinPosition");
|
|
|
|
//Read if the we have done it once already.
|
|
DWORD dwAdjustPos = 0; //Assume that Recycle-bin has been already positioned.
|
|
DWORD dwSize = sizeof(dwAdjustPos);
|
|
|
|
SHRegGetUSValue(lpszSubkey, lpszValue, NULL, &dwAdjustPos, &dwSize, FALSE, &dwAdjustPos, dwSize);
|
|
// 0 => Recycle-bin hasn't been positioned because of resolution fixer.
|
|
// 1 => Recycle-bin needs to be repositioned. It has't happened yet!
|
|
// 2 => Recycle-bin has already been re-positioned. Nothing needs to be done here!
|
|
if(dwAdjustPos == 0)
|
|
{
|
|
// 0 => Recycle-bin hasn't been positioned because of resolution fixer.
|
|
// So, we need to change the settings sothat when desktop.cpp responds to res change,
|
|
// it will position the recycle-bin.
|
|
dwAdjustPos = 1;
|
|
SHRegSetUSValue(lpszSubkey, lpszValue, REG_DWORD, &dwAdjustPos, sizeof(dwAdjustPos), SHREGSET_HKCU | SHREGSET_FORCE_HKCU);
|
|
}
|
|
}
|
|
|
|
HRESULT CScreenResFixer::_FixScreenResolution(BOOL fShowDisplayCPL)
|
|
{
|
|
IDisplaySettings * pds;
|
|
|
|
HRESULT hr = CoCreateInstance(CLSID_DisplaySettings, NULL, CLSCTX_INPROC_SERVER,
|
|
IID_PPV_ARG(IDisplaySettings, &pds));
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
for (DWORD dwMon = 0; SUCCEEDED(pds->SetMonitor(dwMon)); dwMon++)
|
|
{
|
|
BOOL fAttached = FALSE;
|
|
hr = pds->GetAttached(&fAttached);
|
|
if (SUCCEEDED(hr) && fAttached)
|
|
{
|
|
DWORD dwWidth, dwHeight, dwColor;
|
|
hr = pds->GetSelectedMode(&dwWidth, &dwHeight, &dwColor);
|
|
if (SUCCEEDED(hr) && ((dwWidth < 800) || (dwHeight < 600) || (dwColor < 15)))
|
|
{
|
|
DWORD cModes = 0;
|
|
hr = pds->GetModeCount(&cModes, TRUE);
|
|
|
|
if (SUCCEEDED( hr ) && (cModes > 0))
|
|
{
|
|
SCREENMODE* modes = new SCREENMODE[cModes];
|
|
if (modes)
|
|
{
|
|
for (DWORD i = 0; i < cModes; i++)
|
|
{
|
|
hr = pds->GetMode(i, TRUE, &modes[i].dwWidth, &modes[i].dwHeight, &modes[i].dwColor);
|
|
modes[i].fAvailable = SUCCEEDED(hr) && ((i <= 0) ||
|
|
(modes[i].dwWidth != modes[i-1].dwWidth) ||
|
|
(modes[i].dwHeight != modes[i-1].dwHeight) ||
|
|
(modes[i].dwColor != modes[i-1].dwColor));
|
|
}
|
|
|
|
int iMode = _PickScreenResolution(modes, cModes);
|
|
if (iMode != -1)
|
|
{
|
|
static BOOL fRecycleBinInfoUpdated = FALSE; //to begin with!
|
|
//We are about to change the mode. Make a note in registry
|
|
if(!fRecycleBinInfoUpdated)
|
|
{
|
|
UpdateRecycleBinInfo();
|
|
fRecycleBinInfoUpdated = TRUE;
|
|
}
|
|
|
|
BOOL fApplied = FALSE;
|
|
pds->SetSelectedMode(NULL, modes[iMode].dwWidth, modes[iMode].dwHeight, modes[iMode].dwColor, &fApplied, fShowDisplayCPL ? DS_BACKUPDISPLAYCPL : 0);
|
|
if (!fApplied)
|
|
{
|
|
hr = E_FAIL;
|
|
}
|
|
}
|
|
|
|
delete [] modes;
|
|
modes = NULL;
|
|
}
|
|
else
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT CScreenResFixer_CreateInstance(IN IUnknown * punkOuter, IN REFIID riid, OUT LPVOID * ppvObj)
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
|
|
if (!punkOuter && ppvObj)
|
|
{
|
|
CComObject<CScreenResFixer> * pThis = new CComObject<CScreenResFixer>();
|
|
|
|
*ppvObj = NULL;
|
|
if (pThis)
|
|
{
|
|
hr = pThis->QueryInterface(riid, ppvObj);
|
|
}
|
|
else
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|