Leaked source code of windows server 2003
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.
 
 
 
 
 
 

1381 lines
43 KiB

#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;
}