|
|
#include "precomp.h"
#include "winuser.h"
#include <shdguid.h> // For CLSID_CDeskHtmlProp
#include <shlwapi.h>
#include <shlobj.h>
#include <shlobjp.h>
#include <shlwapip.h>
#include <regapi.h>
#include <ctxdef.h> // hydra stuff
#include <cowsite.h>
#include <theme.h>
#include "cplext.h"
#include "cplp.h"
HWND g_hDlg = NULL;
///////////////////////////////////////////////////////////////////////////////
// Array defining each page in the sheet
///////////////////////////////////////////////////////////////////////////////
typedef struct { int id; DLGPROC pfnDlgProc; RESTRICTIONS dwPolicy1; RESTRICTIONS dwPolicy2; long nExtensionID; // The page
} PAGEINFO;
PAGEINFO aPageInfo[] = { { 0, NULL, REST_NODISPLAYAPPEARANCEPAGE, REST_NOTHEMESTAB, PAGE_DISPLAY_THEMES}, // Theme page
{ DLG_BACKGROUND, BackgroundDlgProc, REST_NODISPBACKGROUND, (RESTRICTIONS)0, 0}, // Background page
{ DLG_SCREENSAVER, NULL, REST_NODISPSCREENSAVEPG, (RESTRICTIONS)0, 0}, // Screen Saver page
{ 0, NULL, REST_NODISPLAYAPPEARANCEPAGE, (RESTRICTIONS)0, PAGE_DISPLAY_APPEARANCE}, // Appearance page
{ 0, NULL, REST_NODISPSETTINGSPG, (RESTRICTIONS)0, PAGE_DISPLAY_SETTINGS}, // Settings page
};
#define C_PAGES_DESK ARRAYSIZE(aPageInfo)
#define IPI_SETTINGS (C_PAGES_DESK-1) // Index to "Settings" page
#define SZ_WALLPAPER L"Wallpaper"
#define EnableApplyButton(hdlg) PropSheet_Changed(GetParent(hdlg), hdlg)
IThemeUIPages * g_pThemeUI = NULL;
// Local Constant Declarations
static const TCHAR sc_szCoverClass[] = TEXT("DeskSaysNoPeekingItsASurprise"); LRESULT CALLBACK CoverWindowProc( HWND, UINT, WPARAM, LPARAM );
// These are actions that can be passed in the cmdline.
// FORMAT: "/Action:<ActionType>"
#define DESKACTION_NONE 0x00000000
#define DESKACTION_OPENTHEME 0x00000001
#define DESKACTION_OPENMSTHEM 0x00000002
///////////////////////////////////////////////////////////////////////////////
// Globals
///////////////////////////////////////////////////////////////////////////////
TCHAR gszDeskCaption[CCH_MAX_STRING];
TCHAR g_szNULL[] = TEXT(""); TCHAR g_szControlIni[] = TEXT("control.ini"); TCHAR g_szPatterns[] = TEXT("patterns") ; TCHAR g_szNone[CCH_NONE]; // this is the '(None)' string
TCHAR g_szSystemIni[] = TEXT("system.ini"); TCHAR g_szWindows[] = TEXT("Windows");
TCHAR szRegStr_Colors[] = REGSTR_PATH_COLORS;
HDC g_hdcMem = NULL; HBITMAP g_hbmDefault = NULL; BOOL g_bMirroredOS = FALSE;
///////////////////////////////////////////////////////////////////////////////
// Externs
///////////////////////////////////////////////////////////////////////////////
extern BOOL NEAR PASCAL GetStringFromReg(HKEY hKey, LPCTSTR lpszSubkey, LPCTSTR lpszValueName, LPCTSTR lpszDefault, LPTSTR lpszValue, DWORD cchSizeofValueBuff);
//============================================================================================================
// Class
//============================================================================================================
class CDisplayControlPanel : public CObjectWithSite { public: //////////////////////////////////////////////////////
// Public Interfaces
//////////////////////////////////////////////////////
// *** IUnknown ***
virtual STDMETHODIMP QueryInterface(REFIID riid, LPVOID * ppvObj); virtual STDMETHODIMP_(ULONG) AddRef(void); virtual STDMETHODIMP_(ULONG) Release(void);
void DisplayDialog(HINSTANCE hInst, HWND hwndParent, LPCTSTR pszCmdline);
CDisplayControlPanel(void); virtual ~CDisplayControlPanel(void);
private: // Private Member Variables
long m_cRef; HANDLE m_hBackgroundThreads;
void _ShowDialog(HINSTANCE hInst, HWND hwndParent, LPCTSTR pszCmdline); };
/*---------------------------------------------------------
** **---------------------------------------------------------*/ BOOL NEAR PASCAL CreateGlobals() { WNDCLASS wc; HBITMAP hbm; HDC hdc;
//
// Check if the mirroring APIs exist on the current
// platform.
//
g_bMirroredOS = IS_MIRRORING_ENABLED();
if( !GetClassInfo( hInstance, sc_szCoverClass, &wc ) ) { // if two pages put one up, share one dc
wc.style = CS_CLASSDC; wc.lpfnWndProc = CoverWindowProc; wc.cbClsExtra = wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = (HICON)( wc.hCursor = NULL ); // use a real brush since user will try to paint us when we're "hung"
wc.hbrBackground = (HBRUSH) GetStockObject( NULL_BRUSH ); wc.lpszMenuName = NULL; wc.lpszClassName = sc_szCoverClass;
if( !RegisterClass( &wc ) ) return FALSE; }
hdc = GetDC(NULL); g_hdcMem = CreateCompatibleDC(hdc); ReleaseDC(NULL, hdc);
if (!g_hdcMem) return FALSE;
hbm = CreateBitmap(1, 1, 1, 1, NULL); if (hbm) { g_hbmDefault = (HBITMAP) SelectObject(g_hdcMem, hbm); SelectObject(g_hdcMem, g_hbmDefault); DeleteObject(hbm); }
LoadString(hInstance, IDS_NONE, g_szNone, ARRAYSIZE(g_szNone));
return TRUE; }
int DisplaySaveSettings(PVOID pContext, HWND hwnd) { int iRet = 0;
if (g_pThemeUI) { g_pThemeUI->DisplaySaveSettings(pContext, hwnd, &iRet); } return iRet; }
///////////////////////////////////////////////////////////////////////////////
//
// InstallScreenSaver
//
// Provides a RUNDLL32-callable routine to install a screen saver
//
///////////////////////////////////////////////////////////////////////////////
//
// Windows NT:
//
// Thunk ANSI version to the Unicode function
//
void WINAPI InstallScreenSaverW( HWND wnd, HINSTANCE inst, LPWSTR cmd, int shw );
void WINAPI InstallScreenSaverA( HWND wnd, HINSTANCE inst, LPSTR cmd, int shw ) { LPWSTR pwszCmd; int cch;
cch = MultiByteToWideChar( CP_ACP, 0, cmd, -1, NULL, 0); if (cch == 0) return;
pwszCmd = (LPWSTR) LocalAlloc( LMEM_FIXED, cch * SIZEOF(TCHAR) ); if (pwszCmd == NULL) return;
if (0 != MultiByteToWideChar( CP_ACP, 0, cmd, -1, pwszCmd, cch)) { InstallScreenSaverW(wnd, inst, pwszCmd, shw); }
LocalFree(pwszCmd); }
#define REAL_INSTALL_SCREEN_SAVER InstallScreenSaverW
void WINAPI REAL_INSTALL_SCREEN_SAVER( HWND wnd, HINSTANCE inst, LPTSTR cmd, int shw ) { TCHAR buf[ MAX_PATH ]; int timeout;
StringCchCopy( buf, ARRAYSIZE(buf), cmd ); PathGetShortPath( buf ); // so msscenes doesn't die
WritePrivateProfileString( TEXT("boot"), TEXT("SCRNSAVE.EXE"), buf, TEXT("system.ini") );
SystemParametersInfo( SPI_SETSCREENSAVEACTIVE, TRUE, NULL, SPIF_UPDATEINIFILE );
// make sure the user has a reasonable timeout set
SystemParametersInfo( SPI_GETSCREENSAVETIMEOUT, 0, &timeout, 0 ); if( timeout <= 0 ) { // 15 minutes seems like a nice default
SystemParametersInfo( SPI_SETSCREENSAVETIMEOUT, 900, NULL, SPIF_UPDATEINIFILE ); }
// bring up the screen saver page on our rundll
Control_RunDLLW( wnd, inst, TEXT("DESK.CPL,,1"), shw ); }
/*****************************************************************************\
* * DeskInitCpl( void ) * \*****************************************************************************/
BOOL DeskInitCpl(void) { InitCommonControls();
CreateGlobals();
return TRUE; }
HRESULT OpenAdvancedDialog(HWND hDlg, const CLSID * pClsid) { HRESULT hr = E_FAIL; IEnumUnknown * pEnumUnknown;
hr = g_pThemeUI->GetBasePagesEnum(&pEnumUnknown); if (SUCCEEDED(hr)) { IUnknown * punk;
hr = IEnumUnknown_FindCLSID(pEnumUnknown, *pClsid, &punk); if (SUCCEEDED(hr)) { IBasePropPage * pBasePage;
hr = punk->QueryInterface(IID_PPV_ARG(IBasePropPage, &pBasePage)); if (SUCCEEDED(hr)) { IPropertyBag * pPropertyBag;
hr = punk->QueryInterface(IID_PPV_ARG(IPropertyBag, &pPropertyBag)); if (SUCCEEDED(hr)) { if (IsEqualCLSID(PPID_Background, *pClsid)) { // We are going to treat the Background tab differently. We tell it to open
// the advanced dialog. We do this so it can close the dialog if the user
// clicks to open the Gallery and we need the CPL to close.
hr = SHPropertyBag_WriteBOOL(pPropertyBag, SZ_PBPROP_OPENADVANCEDDLG, TRUE); } else { IAdvancedDialog * pAdvAppearDialog;
hr = pBasePage->GetAdvancedDialog(&pAdvAppearDialog); if (SUCCEEDED(hr)) { BOOL fEnableApply = FALSE;
hr = pAdvAppearDialog->DisplayAdvancedDialog(hDlg, pPropertyBag, &fEnableApply); if (SUCCEEDED(hr) && fEnableApply) { EnableApplyButton(hDlg); g_pThemeUI->UpdatePreview(0); // The Preview settings may have changed.
}
pAdvAppearDialog->Release(); } }
pPropertyBag->Release(); }
pBasePage->Release(); }
punk->Release(); }
pEnumUnknown->Release(); }
return hr; }
HRESULT SetAdvStartPage(LPTSTR pszStartPage, DWORD cchSize) { HRESULT hr = S_OK;
// Does the caller want us to open the advanced dialog to a certain tab?
if (g_pThemeUI) { // Yes, so open the dialog.
if (!StrCmpI(pszStartPage, TEXT("Theme Settings"))) { OpenAdvancedDialog(g_hDlg, &PPID_Theme); } else if (!StrCmpI(pszStartPage, TEXT("Appearance"))) { OpenAdvancedDialog(g_hDlg, &PPID_BaseAppearance); } else if (!StrCmpI(pszStartPage, TEXT("Web"))) { OpenAdvancedDialog(g_hDlg, &PPID_Background); StringCchCopy(pszStartPage, cchSize, L"Desktop"); } }
return hr; }
typedef struct { LPCTSTR pszCanonical; UINT nResourceID; } CANONICAL_TO_LOCALIZE_TABMAPPING;
CANONICAL_TO_LOCALIZE_TABMAPPING s_TabMapping[] = { {SZ_DISPLAYCPL_OPENTO_THEMES, IDS_TAB_THEMES}, {SZ_DISPLAYCPL_OPENTO_DESKTOP, IDS_TAB_DESKTOP}, {TEXT("Background"), IDS_TAB_DESKTOP}, // These are other names people may use
{TEXT("Screen Saver"), IDS_TAB_SCREENSAVER}, // These are other names people may use
{SZ_DISPLAYCPL_OPENTO_SCREENSAVER, IDS_TAB_SCREENSAVER}, {SZ_DISPLAYCPL_OPENTO_APPEARANCE, IDS_TAB_APPEARANCE}, {SZ_DISPLAYCPL_OPENTO_SETTINGS, IDS_TAB_SETTINGS}, };
HRESULT _TabCanonicalToLocalized(IN OUT LPTSTR pszStartPage, DWORD cchSize) { HRESULT hr = S_OK;
// pszStartPage is an in AND out param
for (int nIndex = 0; nIndex < ARRAYSIZE(s_TabMapping); nIndex++) { if (!StrCmpI(s_TabMapping[nIndex].pszCanonical, pszStartPage)) { if (0 == s_TabMapping[nIndex].nResourceID) { hr = E_FAIL; } else { LoadString(hInstance, s_TabMapping[nIndex].nResourceID, pszStartPage, cchSize); } break; } }
return hr; }
///////////////////////////////////////////////////////////////////////////////
// SetStartPage checks the command line for start page by name.
///////////////////////////////////////////////////////////////////////////////
#define SZ_ACTIONFLAG_THEME TEXT("/Action:OpenTheme")
#define SZ_ACTIONFLAG_MSTHEME TEXT("/Action:OpenMSTheme")
#define SZ_FILEFLAG TEXT("/File:\"")
void SetStartPage(PROPSHEETHEADER *ppsh, LPCTSTR pszCmdLine, DWORD * pdwAction, LPTSTR pszPath, DWORD cchPathSize, LPTSTR pszStartPage, DWORD cchSize) { pszPath[0] = L'\0'; pszStartPage[0] = L'\0';
if (pszCmdLine) { // Strip spaces
while (*pszCmdLine == TEXT(' ')) { pszCmdLine++; }
// Check for @ sign.
if (*pszCmdLine == TEXT('@')) { LPCTSTR pszBegin; BOOL fInQuote = FALSE; int cchLen;
pszCmdLine++;
// Skip past a quote
if (*pszCmdLine == TEXT('"')) { pszCmdLine++; fInQuote = TRUE; }
// Save the beginning of the name.
pszBegin = pszCmdLine;
// Find the end of the name.
while (pszCmdLine[0] && (fInQuote || (pszCmdLine[0] != TEXT(' '))) && (!fInQuote || (pszCmdLine[0] != TEXT('"')))) { pszCmdLine++; } cchLen = (int)(pszCmdLine - pszBegin);
TCHAR szStartPage[MAX_PATH];
StringCchCopy(szStartPage, cchLen+1, pszBegin); SetAdvStartPage(szStartPage, ARRAYSIZE(szStartPage));
// Store the name in the pStartPage field.
StringCchCopy(pszStartPage, cchSize, szStartPage);
if (StrStrIW(pszCmdLine, SZ_ACTIONFLAG_THEME) || StrStrW(pszCmdLine, SZ_ACTIONFLAG_MSTHEME)) { *pdwAction = (StrStrW(pszCmdLine, SZ_ACTIONFLAG_THEME) ? DESKACTION_OPENTHEME : DESKACTION_OPENMSTHEM);
pszCmdLine = StrStrIW(pszCmdLine, SZ_FILEFLAG); if (pszCmdLine) { pszCmdLine += (ARRAYSIZE(SZ_FILEFLAG) - 1); // Skip past flag
LPCWSTR pszEnd = StrStrIW(pszCmdLine, L"\""); if (pszEnd) { DWORD cchSize = (DWORD)((pszEnd - pszCmdLine) + 1); StringCchCopy(pszPath, min(cchPathSize, cchSize), pszCmdLine); } } }
if (SUCCEEDED(_TabCanonicalToLocalized(pszStartPage, cchSize))) // The caller passes a canonical name but the propsheet wants to localized name
{ ppsh->dwFlags |= PSH_USEPSTARTPAGE; ppsh->pStartPage = pszStartPage; } } } }
///////////////////////////////////////////////////////////////////////////////
// _AddDisplayPropSheetPage adds pages for outside callers...
///////////////////////////////////////////////////////////////////////////////
BOOL CALLBACK _AddDisplayPropSheetPage(HPROPSHEETPAGE hpage, LPARAM lParam) { PROPSHEETHEADER FAR * ppsh = (PROPSHEETHEADER FAR *) lParam;
if (ppsh) { if (hpage && (ppsh->nPages < MAX_PAGES)) { ppsh->phpage[ppsh->nPages++] = hpage; return TRUE; } }
return FALSE; }
static int GetClInt( const TCHAR *p ) { BOOL neg = FALSE; int v = 0;
while( *p == TEXT(' ') ) p++; // skip spaces
if( *p == TEXT('-') ) // is it negative?
{ neg = TRUE; // yes, remember that
p++; // skip '-' char
}
// parse the absolute portion
while( ( *p >= TEXT('0') ) && ( *p <= TEXT('9') ) ) // digits only
v = v * 10 + *p++ - TEXT('0'); // accumulate the value
return ( neg? -v : v ); // return the result
}
BOOL CheckRestrictionPage(const PAGEINFO * pPageInfo) { BOOL fRestricted = SHRestricted(pPageInfo->dwPolicy1);
if (!fRestricted && pPageInfo->dwPolicy2) { fRestricted = SHRestricted(pPageInfo->dwPolicy2); }
return fRestricted; }
///////////////////////////////////////////////////////////////////////////////
// CreateReplaceableHPSXA creates a new hpsxa that contains only the
// interfaces with valid ReplacePage methods.
// APPCOMPAT - EzDesk only implemented AddPages. ReplacePage is NULL for them.
///////////////////////////////////////////////////////////////////////////////
typedef struct { UINT count, alloc; IShellPropSheetExt *interfaces[0]; } PSXA;
HPSXA CreateReplaceableHPSXA(HPSXA hpsxa) { PSXA *psxa = (PSXA *)hpsxa; DWORD cb = SIZEOF(PSXA) + SIZEOF(IShellPropSheetExt *) * psxa->alloc; PSXA *psxaRet = (PSXA *)LocalAlloc(LPTR, cb);
if (psxaRet) { UINT i;
psxaRet->count = 0; psxaRet->alloc = psxa->alloc;
for (i=0; i<psxa->count; i++) { if (psxa->interfaces[i]) { psxaRet->interfaces[psxaRet->count++] = psxa->interfaces[i]; } } }
return (HPSXA)psxaRet; }
HRESULT AddPropSheetExtArrayToThemePageUI(IThemeUIPages * pThemeUI, HPSXA hpsxa) { HRESULT hr = E_INVALIDARG;
if (pThemeUI && hpsxa) { PSXA *psxa = (PSXA *)hpsxa; IShellPropSheetExt **spsx = psxa->interfaces; UINT nIndex;
for (nIndex = 0; nIndex < psxa->count; nIndex++) { if (psxa->interfaces[nIndex]) { IBasePropPage * pBasePropPage;
if (SUCCEEDED(psxa->interfaces[nIndex]->QueryInterface(IID_PPV_ARG(IBasePropPage, &pBasePropPage)))) { pThemeUI->AddBasePage(pBasePropPage); pBasePropPage->Release(); } } } }
return hr; }
/*****************************************************************************\
DESCRIPTION: If the caller gave the page index, we need to open to that page. The order of the pages has changed from Win2k to Whistler, so map the indexes.
Win2K: Index 0: Background Index 1: Screen Saver Index 2: Appearance None: Web None: Effects Index 3: Settings (Index 3)
Whistler: (Base Dlg) None: Themes Index 0: Background Index 1: Screen Saver Index 2: Appearance Index 3: Settings
Whistler: (Adv Dlg) None: Themes Settings None: Adv Appearance None: Web None: Effects \*****************************************************************************/ int UpgradeStartPageMappping(LPTSTR pszCmdLine, DWORD cchSize) { int nNewStartPage = GetClInt(pszCmdLine);
if (pszCmdLine) { switch (nNewStartPage) { case 0: // Background
StringCchCopy(pszCmdLine, cchSize, TEXT("@Desktop")); break; case 1: // Screen Saver
case 2: // Screen Saver
StringCchCopy(pszCmdLine, cchSize, TEXT("@ScreenSaver")); break; case 3: // Settings
StringCchCopy(pszCmdLine, cchSize, TEXT("@Settings")); break; default: return nNewStartPage; break; } } else { return nNewStartPage; }
return 0; }
#define DestroyReplaceableHPSXA(hpsxa) LocalFree((HLOCAL)hpsxa)
/*****************************************************************************\
* * DeskShowPropSheet( HWND hwndParent ) * \*****************************************************************************/ void DeskShowPropSheet(HINSTANCE hInst, HWND hwndParent, LPCTSTR pszCmdline) { CDisplayControlPanel displayCPL;
displayCPL.DisplayDialog(hInst, hwndParent, pszCmdline); }
//===========================
// *** IUnknown Interface ***
//===========================
ULONG CDisplayControlPanel::AddRef() { return InterlockedIncrement(&m_cRef); }
ULONG CDisplayControlPanel::Release() { ASSERT( 0 != m_cRef ); ULONG cRef = InterlockedDecrement(&m_cRef); if ( 0 == cRef ) { delete this; } else if ((1 == cRef) && m_hBackgroundThreads) { SetEvent(m_hBackgroundThreads); } return cRef; }
HRESULT CDisplayControlPanel::QueryInterface(REFIID riid, void **ppvObj) { HRESULT hr = E_NOINTERFACE;
static const QITAB qit[] = { QITABENT(CDisplayControlPanel, IObjectWithSite), { 0 }, };
return QISearch(this, qit, riid, ppvObj); }
CDisplayControlPanel::CDisplayControlPanel(void) : m_cRef(1) { m_hBackgroundThreads = NULL; }
CDisplayControlPanel::~CDisplayControlPanel(void) { if (m_hBackgroundThreads) { CloseHandle(m_hBackgroundThreads); m_hBackgroundThreads = NULL; } }
// Wait 30 seconds for hung apps to process our message before we give up.
// It would be nice to wait longer, but if the user tries to launch the Display
// Control Panel again, it will not launch because we are still running. The only
// thing that we will give up on doing after 30 seconds it notifying apps. In the worse
// case the user will need to log-off and back in to get apps to refresh.
#define MAX_WAITFORHUNGAPPS (30)
void CDisplayControlPanel::DisplayDialog(HINSTANCE hInst, HWND hwndParent, LPCTSTR pszCmdline) { if (SUCCEEDED(CoInitialize(NULL))) { SHSetInstanceExplorer(SAFECAST(this, IUnknown *)); _ShowDialog(hInst, hwndParent, pszCmdline);
// Wait until the background threads finish.
if (m_cRef > 1) { m_hBackgroundThreads = CreateEvent(NULL, FALSE, FALSE, NULL); if (m_hBackgroundThreads && (m_cRef > 1)) { DWORD dwResult = SHProcessMessagesUntilEvent(NULL, m_hBackgroundThreads, (MAX_WAITFORHUNGAPPS * 1000));
if (WAIT_TIMEOUT == dwResult) { TraceMsg(TF_GENERAL, "A thread hung and we needed to shutdown while it was still running."); } Sleep(100); } }
SHSetInstanceExplorer(NULL); CoUninitialize(); } }
void CDisplayControlPanel::_ShowDialog(HINSTANCE hInst, HWND hwndParent, LPCTSTR pszCmdline) { HPROPSHEETPAGE hpsp, ahPages[MAX_PAGES]; HPSXA hpsxa = NULL; PROPSHEETPAGE psp; PROPSHEETHEADER psh; int i; DWORD exitparam = 0UL; HRESULT hr = S_OK; TCHAR szCmdLine[MAX_PATH];
StringCchCopy(szCmdLine, ARRAYSIZE(szCmdLine), (pszCmdline ? pszCmdline : TEXT("")));
// check if whole sheet is locked out
if (SHRestricted(REST_NODISPLAYCPL)) { TCHAR szMessage[255],szTitle[255];
LoadString( hInst, IDS_DISPLAY_DISABLED, szMessage, ARRAYSIZE(szMessage) ); LoadString( hInst, IDS_DISPLAY_TITLE, szTitle, ARRAYSIZE(szTitle) );
MessageBox( hwndParent, szMessage, szTitle, MB_OK | MB_ICONINFORMATION ); return; }
// Create the property sheet
ZeroMemory(&psh, sizeof(psh));
psh.dwSize = sizeof(PROPSHEETHEADER); psh.dwFlags = (PSH_PROPTITLE | PSH_USECALLBACK);
psh.hwndParent = hwndParent; psh.hInstance = hInst;
psh.pszCaption = MAKEINTRESOURCE(IDS_DISPLAY_TITLE); psh.nPages = 0; psh.phpage = ahPages; psh.nStartPage = 0; psh.pfnCallback = NULL;
if (szCmdLine && szCmdLine[0] && (TEXT('@') != szCmdLine[0])) { psh.nStartPage = UpgradeStartPageMappping(szCmdLine, ARRAYSIZE(szCmdLine)); // We changed the order so do the mapping
}
ZeroMemory( &psp, sizeof(psp) );
psp.dwSize = sizeof(psp); psp.dwFlags = PSP_DEFAULT; psp.hInstance = hInst;
// Build the property sheet. If we are under setup, then just include
// the "settings" page, and no otheres
if (!g_pThemeUI) { // CoCreate Themes, Appearance, and Advanced Appearance tabs
hr = CoCreateInstance(CLSID_ThemeUIPages, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IThemeUIPages, &g_pThemeUI)); }
if (SUCCEEDED(hr)) { DWORD dwExecMode; if (g_pThemeUI && (SUCCEEDED(g_pThemeUI->GetExecMode(&dwExecMode))) && (dwExecMode == EM_NORMAL)) { if (!GetSystemMetrics(SM_CLEANBOOT)) { hpsxa = SHCreatePropSheetExtArray(HKEY_LOCAL_MACHINE, REGSTR_PATH_CONTROLSFOLDER TEXT("\\Desk"), 8); }
for (i = 0; i < C_PAGES_DESK; i++) { BOOL fHideThisPage = FALSE;
if (CheckRestrictionPage(&aPageInfo[i])) { // This page is locked out by admin, don't put it up
fHideThisPage = TRUE; }
if (-1 == aPageInfo[i].nExtensionID) { psp.pszTemplate = MAKEINTRESOURCE(aPageInfo[i].id); psp.pfnDlgProc = aPageInfo[i].pfnDlgProc; psp.dwFlags = PSP_DEFAULT; psp.lParam = 0L;
if (!fHideThisPage && (psp.pfnDlgProc == BackgroundDlgProc)) { // This page can be overridden by extensions
if( hpsxa ) { UINT cutoff = psh.nPages; UINT added = 0; HPSXA hpsxaReplace = CreateReplaceableHPSXA(hpsxa); if (hpsxaReplace) { added = SHReplaceFromPropSheetExtArray( hpsxaReplace, CPLPAGE_DISPLAY_BACKGROUND, _AddDisplayPropSheetPage, (LPARAM)&psh); DestroyReplaceableHPSXA(hpsxaReplace); }
if (added) { if (psh.nStartPage >= cutoff) psh.nStartPage += added-1; continue; } } }
if (!fHideThisPage && (hpsp = CreatePropertySheetPage(&psp))) { psh.phpage[psh.nPages++] = hpsp; } } else if (g_pThemeUI && !fHideThisPage) { IBasePropPage * pBasePage = NULL;
// add extensions from the registry
// CAUTION: Do not check for "fHideThisPage" here. We need to add the pages for
// property sheet extensions even if the "Settings" page is hidden.
if (i == IPI_SETTINGS && hpsxa) { UINT cutoff = psh.nPages; UINT added = SHAddFromPropSheetExtArray(hpsxa, _AddDisplayPropSheetPage, (LPARAM)&psh);
if (psh.nStartPage >= cutoff) psh.nStartPage += added; }
switch (aPageInfo[i].id) { case 0: hr = g_pThemeUI->AddPage(_AddDisplayPropSheetPage, (LPARAM)&psh, aPageInfo[i].nExtensionID); break; case DLG_SCREENSAVER: hr = CoCreateInstance(CLSID_ScreenSaverPage, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IBasePropPage, &pBasePage)); break; case DLG_BACKGROUND: hr = CoCreateInstance(CLSID_CDeskHtmlProp, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IBasePropPage, &pBasePage)); break; default: AssertMsg(0, TEXT("The value must be specified")); break; };
if (pBasePage) { IShellPropSheetExt * pspse = NULL;
// If they implement IShellPropSheetExt, then add their base pages.
if (SUCCEEDED(pBasePage->QueryInterface(IID_PPV_ARG(IShellPropSheetExt, &pspse)))) { hr = pspse->AddPages(_AddDisplayPropSheetPage, (LPARAM)&psh); pspse->Release(); }
hr = g_pThemeUI->AddBasePage(pBasePage); pBasePage->Release(); } } }
if (hpsxa) { // Have the dynamically added pages added to IThemeUIPages.
AddPropSheetExtArrayToThemePageUI(g_pThemeUI, hpsxa); }
// add a fake settings page to fool OEM extensions
// !!! this page must be last !!!
if (hpsxa) { g_pThemeUI->AddFakeSettingsPage((LPVOID)&psh); } } else { // For the SETUP case, only the display page should show up.
hr = g_pThemeUI->AddPage(_AddDisplayPropSheetPage, (LPARAM)&psh, aPageInfo[IPI_SETTINGS].nExtensionID); }
if (psh.nStartPage >= psh.nPages) psh.nStartPage = 0;
if (psh.nPages) { DWORD dwAction = DESKACTION_NONE; TCHAR szStartPage[MAX_PATH]; WCHAR szOpenPath[MAX_PATH]; IPropertyBag * pPropertyBag;
SetStartPage(&psh, szCmdLine, &dwAction, szOpenPath, ARRAYSIZE(szOpenPath), szStartPage, ARRAYSIZE(szStartPage));
hr = g_pThemeUI->QueryInterface(IID_PPV_ARG(IPropertyBag, &pPropertyBag)); if (SUCCEEDED(hr)) { VARIANT var;
if (DESKACTION_NONE != dwAction) { var.vt = VT_LPWSTR; var.bstrVal = szOpenPath; hr = pPropertyBag->Write(((DESKACTION_OPENTHEME == dwAction) ? SZ_PBPROP_THEME_LAUNCHTHEME : SZ_PBPROP_APPEARANCE_LAUNCHMSTHEME), &var); }
// The following SZ_PBPROP_PREOPEN call will save a "Custom.theme" so users can always go back to
// their settings if they don't like changes they make in the CPL.
pPropertyBag->Write(SZ_PBPROP_PREOPEN, NULL); pPropertyBag->Release(); }
if (PropertySheet(&psh) == ID_PSRESTARTWINDOWS) { exitparam = EWX_REBOOT; } }
if (g_pThemeUI) { IUnknown_SetSite(g_pThemeUI, NULL); // Tell him to break the ref-count cycle with his children.
g_pThemeUI->Release(); g_pThemeUI = NULL; }
// free any loaded extensions
if (hpsxa) { SHDestroyPropSheetExtArray(hpsxa); }
if (exitparam == EWX_REBOOT) { RestartDialogEx(hwndParent, NULL, exitparam, (SHTDN_REASON_MAJOR_SYSTEM | SHTDN_REASON_MINOR_RECONFIG)); } }
return; }
DWORD gdwCoverStyle = WS_EX_TOPMOST | WS_EX_TOOLWINDOW;
HWND FAR PASCAL CreateCoverWindow( DWORD flags ) { HWND hwndCover = CreateWindowEx( gdwCoverStyle, sc_szCoverClass, g_szNULL, WS_POPUP | WS_VISIBLE | flags, GetSystemMetrics( SM_XVIRTUALSCREEN ), GetSystemMetrics( SM_YVIRTUALSCREEN ), GetSystemMetrics( SM_CXVIRTUALSCREEN ), GetSystemMetrics( SM_CYVIRTUALSCREEN ), NULL, NULL, hInstance, NULL ); if( hwndCover ) { SetForegroundWindow( hwndCover ); if (flags & COVER_NOPAINT) SetCursor(LoadCursor(NULL, IDC_WAIT)); UpdateWindow( hwndCover); }
return hwndCover; }
///////////////////////////////////////////////////////////////////////////////
// CoverWndProc (see CreateCoverWindow)
///////////////////////////////////////////////////////////////////////////////
#define WM_PRIV_KILL_LATER (WM_APP + 100) //Private message to kill ourselves later.
LRESULT CALLBACK CoverWindowProc( HWND window, UINT message, WPARAM wparam, LPARAM lparam ) { switch( message ) { case WM_CREATE: SetTimer( window, ID_CVRWND_TIMER, CMSEC_COVER_WINDOW_TIMEOUT, NULL ); break;
case WM_TIMER: // Times up... Shut ourself down
if (wparam == ID_CVRWND_TIMER) DestroyWindow(window); break;
case WM_ERASEBKGND: // NOTE: assumes our class brush is the NULL_BRUSH stock object
if( !( GetWindowLong( window, GWL_STYLE ) & COVER_NOPAINT ) ) { HDC dc = (HDC)wparam; RECT rc;
if( GetClipBox( dc, (LPRECT)&rc ) != NULLREGION ) { FillRect( dc, (LPRECT)&rc, (HBRUSH) GetStockObject( BLACK_BRUSH ) );
// HACK: make sure fillrect is done before we return
// this is to better hide flicker during dynares-crap
GetPixel( dc, rc.left + 1, rc.top + 1 ); } } break;
// We post a private message to ourselves because:
// When WM_CLOSE is processed by this window, it calls DestroyWindow() which results in
// WM_ACTIVATE (WA_INACTIVE) message to be sent to this window. If this code calls
// DestroyWindow again, it causes a loop. So, instead of calling DestroyWindow immediately,
// we post ourselves a message and destroy us letter.
case WM_ACTIVATE: if( GET_WM_ACTIVATE_STATE( wparam, lparam ) == WA_INACTIVE ) { PostMessage( window, WM_PRIV_KILL_LATER, 0L, 0L ); return 1L; } break;
case WM_PRIV_KILL_LATER: DestroyWindow(window); break;
case WM_DESTROY: KillTimer(window, ID_CVRWND_TIMER); break; }
return DefWindowProc( window, message, wparam, lparam ); }
BOOL _FindCoverWindowCallback(HWND hwnd, LPARAM lParam) { TCHAR szClass[MAX_PATH]; HWND *phwnd = (HWND*)lParam;
if( !GetClassName(hwnd, szClass, ARRAYSIZE(szClass)) ) return TRUE;
if( StrCmp(szClass, sc_szCoverClass) == 0 ) { if( phwnd ) *phwnd = hwnd; return FALSE; } return TRUE; }
LONG APIENTRY CPlApplet( HWND hwnd, WORD message, LPARAM wParam, LPARAM lParam) { LPCPLINFO lpCPlInfo; LPNEWCPLINFO lpNCPlInfo; HWND hwndCover;
switch (message) { case CPL_INIT: // Is any one there ?
// Init the common controls
if (!DeskInitCpl()) return 0;
// Load ONE string for emergencies.
LoadString (hInstance, IDS_DISPLAY_TITLE, gszDeskCaption, ARRAYSIZE(gszDeskCaption)); return !0;
case CPL_GETCOUNT: // How many applets do you support ?
return 1;
case CPL_INQUIRE: // Fill CplInfo structure
lpCPlInfo = (LPCPLINFO)lParam;
lpCPlInfo->idIcon = IDI_DISPLAY; lpCPlInfo->idName = IDS_NAME; lpCPlInfo->idInfo = IDS_INFO; lpCPlInfo->lData = 0; break;
case CPL_NEWINQUIRE:
lpNCPlInfo = (LPNEWCPLINFO)lParam;
lpNCPlInfo->hIcon = LoadIcon(hInstance, (LPTSTR) MAKEINTRESOURCE(IDI_DISPLAY)); LoadString(hInstance, IDS_NAME, lpNCPlInfo->szName, ARRAYSIZE(lpNCPlInfo->szName));
if (!LoadString(hInstance, IDS_INFO, lpNCPlInfo->szInfo, ARRAYSIZE(lpNCPlInfo->szInfo))) lpNCPlInfo->szInfo[0] = (TCHAR) 0;
lpNCPlInfo->dwSize = sizeof( NEWCPLINFO ); lpNCPlInfo->lData = 0; lpNCPlInfo->dwHelpContext = 0; lpNCPlInfo->szHelpFile[0] = 0;
return TRUE;
case CPL_DBLCLK: // You have been chosen to run
/*
* One of your applets has been double-clicked. * wParam is an index from 0 to (NUM_APPLETS-1) * lParam is the lData value associated with the applet */ lParam = 0L; // fall through...
case CPL_STARTWPARMS: DeskShowPropSheet( hInstance, hwnd, (LPTSTR)lParam );
// ensure that any cover windows we've created have been destroyed
do { hwndCover = 0; EnumWindows( _FindCoverWindowCallback, (LPARAM)&hwndCover ); if( hwndCover ) { DestroyWindow( hwndCover ); } } while( hwndCover );
return TRUE; // Tell RunDLL.exe that I succeeded
case CPL_EXIT: // You must really die
if (g_hdcMem) { ReleaseDC(NULL, g_hdcMem); g_hdcMem = NULL; } // Fall thru...
case CPL_STOP: // You must die
if (g_pThemeUI) { IUnknown_SetSite(g_pThemeUI, NULL); // Tell him to break the ref-count cycle with his children.
g_pThemeUI->Release(); g_pThemeUI = NULL; } break;
case CPL_SELECT: // You have been selected
/*
* Sent once for each applet prior to the CPL_EXIT msg. * wParam is an index from 0 to (NUM_APPLETS-1) * lParam is the lData value associated with the applet */ break;
//
// Private message sent when this applet is running under "Setup"
//
case CPL_SETUP: if (g_pThemeUI) { g_pThemeUI->SetExecMode(EM_SETUP); } break;
// Private message used by userenv.dll to refresh the display colors
case CPL_POLICYREFRESH: if (g_pThemeUI) // If this object doesn't exist, then we don't need to refresh anything.
{ IPreviewSystemMetrics * ppsm;
if (SUCCEEDED(g_pThemeUI->QueryInterface(IID_PPV_ARG(IPreviewSystemMetrics, &ppsm)))) { ppsm->RefreshColors(); ppsm->Release(); } } SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, 0, FALSE); break; }
return 0L; }
BOOL WINAPI DeskSetCurrentSchemeW(IN LPCWSTR pwzSchemeName) { BOOL fSuccess = FALSE; IThemeUIPages * pThemeUI = NULL; HRESULT hr;
HRESULT hrOle = SHCoInitialize(); if (g_pThemeUI) { hr = g_pThemeUI->QueryInterface(IID_PPV_ARG(IThemeUIPages, &pThemeUI)); } else { hr = CoCreateInstance(CLSID_ThemeManager, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IThemeUIPages, &pThemeUI)); }
if (SUCCEEDED(hr)) { IPreviewSystemMetrics * ppsm;
hr = pThemeUI->QueryInterface(IID_PPV_ARG(IPreviewSystemMetrics, &ppsm)); if (SUCCEEDED(hr)) { hr = ppsm->DeskSetCurrentScheme(pwzSchemeName); ppsm->Release(); } fSuccess = SUCCEEDED(hr);
pThemeUI->Release(); }
SHCoUninitialize(hrOle); return fSuccess; }
//------------------------------------------------------------------------------------------------
// This function gets the current DPI, reads the last updated DPI from registry and compares
// these two. If these two are equal, it returns immediately.
// If these two DPI values are different, then it updates the size of UI fonts to reflect the
// change in the DPI values.
//
// This function is called from explorer sothat when DPI value is changed by admin and then every
// other user who logs-in gets this change.
//------------------------------------------------------------------------------------------------
void WINAPI UpdateUIfontsDueToDPIchange(int iOldDPI, int iNewDPI) { BOOL fSuccess = FALSE; IThemeManager * pThemeMgr = NULL; HRESULT hr;
HRESULT hrOle = SHCoInitialize(); if (g_pThemeUI) { hr = g_pThemeUI->QueryInterface(IID_PPV_ARG(IThemeManager, &pThemeMgr)); } else { hr = CoCreateInstance(CLSID_ThemeManager, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IThemeManager, &pThemeMgr)); }
if (SUCCEEDED(hr)) { IPropertyBag * pPropertyBag;
hr = GetPageByCLSID(pThemeMgr, &PPID_BaseAppearance, &pPropertyBag); if (SUCCEEDED(hr)) { hr = SHPropertyBag_WriteInt(pPropertyBag, SZ_PBPROP_DPI_APPLIED_VALUE, iOldDPI); // We are going to pretend we had the old DPI to force the scale to happen.
hr = SHPropertyBag_WriteInt(pPropertyBag, SZ_PBPROP_DPI_MODIFIED_VALUE, iNewDPI); if (SUCCEEDED(hr)) { hr = pThemeMgr->ApplyNow(); } pPropertyBag->Release(); } fSuccess = SUCCEEDED(hr);
pThemeMgr->Release(); }
SHCoUninitialize(hrOle); }
BOOL DeskSetCurrentSchemeA(IN LPCSTR pszSchemeName) { WCHAR wzSchemeName[MAX_PATH];
MultiByteToWideChar(CP_ACP, 0, pszSchemeName, -1, wzSchemeName, ARRAYSIZE(wzSchemeName)); return DeskSetCurrentSchemeW(wzSchemeName); }
STDAPI UpdateCharsetChanges(void) { BOOL fSuccess = FALSE; IThemeUIPages * pThemeUI = NULL; HRESULT hr;
HRESULT hrOle = SHCoInitialize(); if (g_pThemeUI) { hr = g_pThemeUI->QueryInterface(IID_PPV_ARG(IThemeUIPages, &pThemeUI)); } else { hr = CoCreateInstance(CLSID_ThemeUIPages, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IThemeUIPages, &pThemeUI)); }
if (SUCCEEDED(hr)) { IPreviewSystemMetrics * ppsm;
hr = pThemeUI->QueryInterface(IID_PPV_ARG(IPreviewSystemMetrics, &ppsm)); if (SUCCEEDED(hr)) { hr = ppsm->UpdateCharsetChanges(); ppsm->Release(); } pThemeUI->Release(); }
SHCoUninitialize(hrOle); return hr; }
|