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.
 
 
 
 
 
 

484 lines
13 KiB

#include "stdafx.h"
#include "sfthost.h"
#include "uemapp.h"
#include <desktray.h>
#include "tray.h"
#include "rcids.h"
#include "mfulist.h"
#define STRSAFE_NO_CB_FUNCTIONS
#define STRSAFE_NO_DEPRECATE
#include <strsafe.h>
//---------------------------------------------------------------------------
//
// Create the initial MFU.
//
// Due to the way sysprep works, we cannot do this work in
// per-user install because "reseal" copies the already-installed user
// to the default hive, so all new users will bypass per-user install
// since ActiveSetup thinks that they have already been installed...
//
//
// We need a parallel list of hard-coded English links so we can get
// the correct shortcut name on MUI systems.
//
#define MAX_MSMFUENTRIES 16
struct MFULIST {
UINT idsBase;
LPCTSTR rgpszEnglish[MAX_MSMFUENTRIES];
};
#define MAKEMFU(name) \
const MFULIST c_mfu##name = { IDS_MFU_##name##_00, { MFU_ENUMC(name) } };
#ifdef _WIN64
MAKEMFU(PRO64ALL)
MAKEMFU(SRV64ADM)
#define c_mfuPROALL c_mfuPRO64ALL
#define c_mfuSRVADM c_mfuSRV64ADM
#else
MAKEMFU(PRO32ALL)
MAKEMFU(SRV32ADM)
#define c_mfuPROALL c_mfuPRO32ALL
#define c_mfuSRVADM c_mfuSRV32ADM
#endif
//---------------------------------------------------------------------------
//
// _GetPinnedItemTarget
//
// Given a pidl, find the executable that will ultimately be launched.
//
// This tunnels through shortcuts and resolves the magical "Internet"
// and "Email" icons to the respective registered programs.
//
BOOL _GetPinnedItemTarget(LPCITEMIDLIST pidl, LPTSTR *ppszPath)
{
*ppszPath = NULL;
IShellFolder *psf;
LPCITEMIDLIST pidlChild;
if (SUCCEEDED(SHBindToIDListParent(pidl, IID_PPV_ARG(IShellFolder, &psf), &pidlChild)))
{
IShellLink *psl;
IExtractIcon *pxi;
if (SUCCEEDED(psf->GetUIObjectOf(NULL, 1, &pidlChild,
IID_PPV_ARG_NULL(IShellLink, &psl))))
{
TCHAR szPath[MAX_PATH];
TCHAR szPathExpanded[MAX_PATH];
if (psl->GetPath(szPath, ARRAYSIZE(szPath), 0, SLGP_RAWPATH) == S_OK &&
SHExpandEnvironmentStrings(szPath, szPathExpanded, ARRAYSIZE(szPathExpanded)))
{
SHStrDup(szPathExpanded, ppszPath);
}
psl->Release();
}
else if (SUCCEEDED(psf->GetUIObjectOf(NULL, 1, &pidlChild,
IID_PPV_ARG_NULL(IExtractIcon, &pxi))))
{
// There is no way to get the IAssociationElement directly, so
// we get the IExtractIcon and then ask him for the IAssociationElement.
IAssociationElement *pae;
if (SUCCEEDED(IUnknown_QueryService(pxi, IID_IAssociationElement, IID_PPV_ARG(IAssociationElement, &pae))))
{
pae->QueryString(AQVS_APPLICATION_PATH, L"open", ppszPath);
pae->Release();
}
pxi->Release();
}
psf->Release();
}
return *ppszPath != NULL;
}
//---------------------------------------------------------------------------
//
// MFUExclusion
//
// Keep track of apps that should be excluded from the MFU.
class MFUExclusion
{
public:
MFUExclusion();
~MFUExclusion();
BOOL IsExcluded(LPCITEMIDLIST pidl) const;
private:
// worst-case default pin list size
enum {MAX_EXCLUDED = 3 };
PWSTR _rgpszExclude[MAX_EXCLUDED];
int _cExcluded;
};
MFUExclusion::MFUExclusion() : _cExcluded(0)
{
IStartMenuPin *psmpin;
HRESULT hr;
hr = CoCreateInstance(CLSID_StartMenuPin, NULL, CLSCTX_INPROC_SERVER,
IID_PPV_ARG(IStartMenuPin, &psmpin));
if (SUCCEEDED(hr))
{
IEnumIDList *penum;
if (SUCCEEDED(psmpin->EnumObjects(&penum)))
{
LPITEMIDLIST pidl;
while (_cExcluded < ARRAYSIZE(_rgpszExclude) &&
penum->Next(1, &pidl, NULL) == S_OK)
{
if (_GetPinnedItemTarget(pidl, &_rgpszExclude[_cExcluded]))
{
_cExcluded++;
}
ILFree(pidl);
}
penum->Release();
}
psmpin->Release();
}
}
MFUExclusion::~MFUExclusion()
{
for (int i = 0; i < _cExcluded; i++)
{
SHFree(_rgpszExclude[i]);
}
}
BOOL MFUExclusion::IsExcluded(LPCITEMIDLIST pidl) const
{
BOOL fRc = FALSE;
LPTSTR pszTarget;
if (_GetPinnedItemTarget(pidl, &pszTarget))
{
for (int i = 0; i < _cExcluded; i++)
{
if (lstrcmpi(_rgpszExclude[i], pszTarget) == 0)
{
fRc = TRUE;
break;
}
}
SHFree(pszTarget);
}
return fRc;
}
extern "C" HKEY g_hkeyExplorer;
void ClearUEMData();
//---------------------------------------------------------------------------
//
// MFUEnumerator (and derived OEMMFUEnumerator, MSMFUEnumerator)
//
// Enumerate applications to be added to the default MFU.
#define MAX_OEMMFUENTRIES 4
class MFUEnumerator
{
public:
MFUEnumerator() : _dwIndex(0) { }
protected:
DWORD _dwIndex;
};
#define REGSTR_PATH_SMDEN TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\SMDEn")
class OEMMFUEnumerator : protected MFUEnumerator
{
public:
OEMMFUEnumerator() : _hk(NULL)
{
RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGSTR_PATH_SMDEN, 0, KEY_READ, &_hk);
}
~OEMMFUEnumerator()
{
if (_hk)
{
RegCloseKey(_hk);
}
}
LPITEMIDLIST Next(const MFUExclusion *pmex);
private:
HKEY _hk;
};
LPITEMIDLIST OEMMFUEnumerator::Next(const MFUExclusion *pmex)
{
if (!_hk)
{
return NULL; // No entries at all
}
restart:
if (_dwIndex >= MAX_OEMMFUENTRIES)
{
return NULL; // No more entries
}
TCHAR szKey[20];
DWORD dwCurrentIndex = _dwIndex++;
wnsprintf(szKey, ARRAYSIZE(szKey), TEXT("OEM%d"), dwCurrentIndex);
TCHAR szPath[MAX_PATH];
HRESULT hr = SHLoadRegUIStringW(_hk, szKey, szPath, ARRAYSIZE(szPath));
if (FAILED(hr))
{
goto restart;
}
TCHAR szPathExpanded[MAX_PATH];
SHExpandEnvironmentStrings(szPath, szPathExpanded, ARRAYSIZE(szPathExpanded));
LPITEMIDLIST pidl = ILCreateFromPath(szPathExpanded);
if (!pidl)
{
goto restart;
}
if (pmex->IsExcluded(pidl))
{
// Excluded - skip it
ILFree(pidl);
goto restart;
}
return pidl;
}
class MSMFUEnumerator : protected MFUEnumerator
{
public:
LPITEMIDLIST Next(const MFULIST *pmfu, const MFUExclusion *pmex);
};
LPITEMIDLIST MSMFUEnumerator::Next(const MFULIST *pmfu, const MFUExclusion *pmex)
{
restart:
if (_dwIndex >= MAX_MSMFUENTRIES)
{
return NULL; // No more entries
}
DWORD dwCurrentIndex = _dwIndex++;
//
// If this is excluded by policy, then skip it.
//
if (StrCmpC(pmfu->rgpszEnglish[dwCurrentIndex], TEXT(MFU_SETDEFAULTS)) == 0 &&
SHRestricted(REST_NOSMCONFIGUREPROGRAMS))
{
goto restart;
}
//
// If this entry is blank, then skip it.
//
TCHAR szPath[MAX_PATH];
if (!LoadString(_Module.GetModuleInstance(), pmfu->idsBase + dwCurrentIndex,
szPath, ARRAYSIZE(szPath)))
{
goto restart;
}
TCHAR szPathExpanded[MAX_PATH];
SHExpandEnvironmentStrings(szPath, szPathExpanded, ARRAYSIZE(szPathExpanded));
LPITEMIDLIST pidl = ILCreateFromPath(szPathExpanded);
if (!pidl)
{
// Doesn't exist under localized name; try the English name
SHExpandEnvironmentStrings(pmfu->rgpszEnglish[dwCurrentIndex], szPathExpanded, ARRAYSIZE(szPathExpanded));
pidl = ILCreateFromPath(szPathExpanded);
}
if (!pidl)
{
// Doesn't exist at all - skip it
goto restart;
}
if (pmex->IsExcluded(pidl))
{
// Excluded - skip it
ILFree(pidl);
goto restart;
}
return pidl;
}
#ifdef DEBUG
void ValidateMFUList(const MFULIST *pmfu)
{
for (int i = 0; i < MAX_MSMFUENTRIES; i++)
{
TCHAR szBuf[MAX_PATH];
LoadString(_Module.GetModuleInstance(), pmfu->idsBase + i, szBuf, ARRAYSIZE(szBuf));
ASSERT(StrCmpC(szBuf, pmfu->rgpszEnglish[i]) == 0);
}
}
void ValidateInitialMFUTables()
{
// If this is the English build, then validate that the resources match
// the hard-coded table.
if (GetUserDefaultUILanguage() == MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US))
{
ValidateMFUList(&c_mfuPROALL);
ValidateMFUList(&c_mfuSRVADM);
}
// The PRO list must contain a copy of MFU_SETDEFAULTS for the
// policy exclusion code to work.
BOOL fFound = FALSE;
for (int i = 0; i < MAX_MSMFUENTRIES; i++)
{
if (StrCmpC(c_mfuPROALL.rgpszEnglish[i], TEXT(MFU_SETDEFAULTS)) == 0)
{
fFound = TRUE;
break;
}
}
ASSERT(fFound);
}
#endif
void CreateInitialMFU(BOOL fReset)
{
#ifdef DEBUG
ValidateInitialMFUTables();
#endif
HRESULT hrInit = SHCoInitialize();
// Delete any dregs left over from "sysprep -reseal".
// This also prevents OEMs from spamming the pin list.
SHDeleteKey(g_hkeyExplorer, TEXT("StartPage"));
SHDeleteValue(g_hkeyExplorer, TEXT("Advanced"), TEXT("StartButtonBalloonTip"));
// Start with a clean slate if so requested
if (fReset)
{
ClearUEMData();
}
// Okay now build the default MFU
{
// nested scope so MFUExclusion gets destructed before we
// SHCoUninitialize()
MFUExclusion mex;
int iSlot;
LPITEMIDLIST rgpidlMFU[REGSTR_VAL_DV2_MINMFU_DEFAULT] = { 0 };
// Assert that the slots are evenly shared between MSFT and the OEM
COMPILETIME_ASSERT(ARRAYSIZE(rgpidlMFU) % 2 == 0);
// The OEM can provide up to four apps, and we will put as many
// as fit into into bottom half.
{
OEMMFUEnumerator mfuOEM;
for (iSlot = ARRAYSIZE(rgpidlMFU)/2; iSlot < ARRAYSIZE(rgpidlMFU); iSlot++)
{
rgpidlMFU[iSlot] = mfuOEM.Next(&mex);
}
}
// The top half (and any unused slots in the bottom half)
// go to MSFT (up to MAX_MSMFUENTRIES MSFT apps); which list
// we use depends on the SKU and whether we are an administrator.
const MFULIST *pmfu = NULL;
if (IsOS(OS_ANYSERVER))
{
// On Server SKUs, only administrators get a default MFU
// and they get the special server administrator MFU
if (IsOS(OS_SERVERADMINUI))
{
pmfu = &c_mfuSRVADM;
}
}
else
{
// On Workstation SKUs, everybody gets a default MFU.
pmfu = &c_mfuPROALL;
}
if (pmfu)
{
MSMFUEnumerator mfuMSFT;
for (iSlot = 0; iSlot < ARRAYSIZE(rgpidlMFU); iSlot++)
{
if (!rgpidlMFU[iSlot])
{
rgpidlMFU[iSlot] = mfuMSFT.Next(pmfu, &mex);
}
}
}
// Now build up the new MFU given this information
UEMINFO uei;
uei.cbSize = sizeof(uei);
uei.dwMask = UEIM_HIT | UEIM_FILETIME;
GetSystemTimeAsFileTime(&uei.ftExecute);
// All apps get the same timestamp of "now minus one UEM unit"
// 1 UEM unit = 1<<30 FILETIME units
DecrementFILETIME(&uei.ftExecute, 1 << 30);
for (iSlot = 0; iSlot < ARRAYSIZE(rgpidlMFU); iSlot++)
{
if (!rgpidlMFU[iSlot])
{
continue;
}
// Number of points decrease as you go down the list, with
// the bottom slot getting 14 points.
uei.cHit = 14 + ARRAYSIZE(rgpidlMFU) - 1 - iSlot;
// Shortcut points are read via UEME_RUNPIDL so that's
// how we have to set them.
IShellFolder *psf;
LPCITEMIDLIST pidlChild;
if (SUCCEEDED(SHBindToIDListParent(rgpidlMFU[iSlot], IID_PPV_ARG(IShellFolder, &psf), &pidlChild)))
{
_SetUEMPidlInfo(psf, pidlChild, &uei);
psf->Release();
}
}
// Clean up
for (iSlot = 0; iSlot < ARRAYSIZE(rgpidlMFU); iSlot++)
{
ILFree(rgpidlMFU[iSlot]);
}
// MFUExclusion destructor runs here
}
SHCoUninitialize(hrInit);
}