|
|
#include "cabinet.h"
#include "rcids.h"
#include <shguidp.h>
#include <lmcons.h>
#include "bandsite.h"
#include "shellp.h"
#include "shdguid.h"
#include <regstr.h>
#include "startmnu.h"
#include "trayp.h" // for WMTRAY_*
#include "tray.h"
#include "util.h"
#include <strsafe.h>
HMENU GetStaticStartMenu(BOOL fEdit);
// *** IUnknown methods ***
STDMETHODIMP CStartMenuHost::QueryInterface (REFIID riid, LPVOID * ppvObj) { static const QITAB qit[] = { QITABENTMULTI(CStartMenuHost, IOleWindow, IMenuPopup), QITABENTMULTI(CStartMenuHost, IDeskBarClient, IMenuPopup), QITABENT(CStartMenuHost, IMenuPopup), QITABENT(CStartMenuHost, ITrayPriv), QITABENT(CStartMenuHost, IShellService), QITABENT(CStartMenuHost, IServiceProvider), QITABENT(CStartMenuHost, IOleCommandTarget), QITABENT(CStartMenuHost, IWinEventHandler), { 0 }, };
return QISearch(this, qit, riid, ppvObj); }
STDMETHODIMP_(ULONG) CStartMenuHost::AddRef () { return ++_cRef; }
STDMETHODIMP_(ULONG) CStartMenuHost::Release() { ASSERT(_cRef > 0); _cRef--;
if( _cRef > 0) return _cRef;
delete this; return 0; }
/*----------------------------------------------------------
Purpose: ITrayPriv::ExecItem method
*/ STDMETHODIMP CStartMenuHost::ExecItem (IShellFolder* psf, LPCITEMIDLIST pidl) { // ShellExecute will display errors (if any). No need
// to show errors here.
return SHInvokeDefaultCommand(v_hwndTray, psf, pidl); }
/*----------------------------------------------------------
Purpose: ITrayPriv::GetFindCM method
*/ STDMETHODIMP CStartMenuHost::GetFindCM(HMENU hmenu, UINT idFirst, UINT idLast, IContextMenu** ppcmFind) { *ppcmFind = SHFind_InitMenuPopup(hmenu, v_hwndTray, TRAY_IDM_FINDFIRST, TRAY_IDM_FINDLAST); if(*ppcmFind) return NOERROR; else return E_FAIL; }
/*----------------------------------------------------------
Purpose: ITrayPriv::GetStaticStartMenu method
*/ STDMETHODIMP CStartMenuHost::GetStaticStartMenu(HMENU* phmenu) { *phmenu = ::GetStaticStartMenu(TRUE);
if(*phmenu) return NOERROR; else return E_FAIL; }
// *** IServiceProvider ***
STDMETHODIMP CStartMenuHost::QueryService (REFGUID guidService, REFIID riid, void ** ppvObject) { if(IsEqualGUID(guidService,SID_SMenuPopup)) return QueryInterface(riid,ppvObject); else return E_NOINTERFACE; }
// *** IShellService ***
STDMETHODIMP CStartMenuHost::SetOwner (struct IUnknown* punkOwner) { return E_NOTIMPL; }
// *** IOleWindow methods ***
STDMETHODIMP CStartMenuHost::GetWindow(HWND * lphwnd) { *lphwnd = v_hwndTray; return NOERROR; }
/*----------------------------------------------------------
Purpose: IMenuPopup::Popup method
*/ STDMETHODIMP CStartMenuHost::Popup(POINTL *ppt, RECTL *prcExclude, DWORD dwFlags) { return E_NOTIMPL; }
/*----------------------------------------------------------
Purpose: IMenuPopup::OnSelect method
*/ STDMETHODIMP CStartMenuHost::OnSelect(DWORD dwSelectType) { return NOERROR; }
/*----------------------------------------------------------
Purpose: IMenuPopup::SetSubMenu method
*/
STDMETHODIMP CStartMenuHost::SetSubMenu(IMenuPopup* pmp, BOOL fSet) { if (!fSet) { Tray_OnStartMenuDismissed(); } return NOERROR; }
// *** IOleCommandTarget ***
STDMETHODIMP CStartMenuHost::QueryStatus (const GUID * pguidCmdGroup, ULONG cCmds, OLECMD rgCmds[], OLECMDTEXT *pcmdtext) { return E_NOTIMPL; }
STDMETHODIMP CStartMenuHost::Exec (const GUID * pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANTARG *pvarargIn, VARIANTARG *pvarargOut) { if (IsEqualGUID(CGID_MENUDESKBAR,*pguidCmdGroup)) { switch (nCmdID) { case MBCID_GETSIDE: pvarargOut->vt = VT_I4; pvarargOut->lVal = MENUBAR_TOP; break; default: break; } }
return NOERROR; }
// *** IWinEventHandler ***
STDMETHODIMP CStartMenuHost::OnWinEvent(HWND h, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *plres) { //Forward events to the tray winproc?
return E_NOTIMPL; }
STDMETHODIMP CStartMenuHost::IsWindowOwner(HWND hwnd) { return E_NOTIMPL; }
CStartMenuHost::CStartMenuHost() : _cRef(1) { }
HRESULT StartMenuHost_Create(IMenuPopup** ppmp, IMenuBand** ppmb) { HRESULT hres = E_OUTOFMEMORY; IMenuPopup * pmp = NULL; IMenuBand * pmb = NULL;
CStartMenuHost *psmh = new CStartMenuHost(); if (psmh) { hres = CoCreateInstance(CLSID_StartMenuBar, NULL, CLSCTX_INPROC_SERVER, IID_IMenuPopup, (LPVOID*)&pmp); if (SUCCEEDED(hres)) { IObjectWithSite* pows;
hres = pmp->QueryInterface(IID_IObjectWithSite, (void**)&pows); if(SUCCEEDED(hres)) { IInitializeObject* pio;
pows->SetSite(SAFECAST(psmh, ITrayPriv*));
hres = pmp->QueryInterface(IID_IInitializeObject, (void**)&pio); if(SUCCEEDED(hres)) { hres = pio->Initialize(); pio->Release(); }
if (SUCCEEDED(hres)) { IUnknown* punk;
hres = pmp->GetClient(&punk); if (SUCCEEDED(hres)) { IBandSite* pbs;
hres = punk->QueryInterface(IID_IBandSite, (void**)&pbs); if(SUCCEEDED(hres)) { DWORD dwBandID;
pbs->EnumBands(0, &dwBandID); hres = pbs->GetBandObject(dwBandID, IID_IMenuBand, (void**)&pmb); pbs->Release(); // Don't release pmb
} punk->Release(); } }
if (FAILED(hres)) pows->SetSite(NULL);
pows->Release(); }
// Don't release pmp
} psmh->Release(); }
if (FAILED(hres)) { ATOMICRELEASE(pmp); ATOMICRELEASE(pmb); }
*ppmp = pmp; *ppmb = pmb;
return hres; }
HRESULT IMenuPopup_SetIconSize(IMenuPopup* pmp,DWORD iIcon) { IBanneredBar* pbb; if (pmp == NULL) return E_FAIL;
HRESULT hres = pmp->QueryInterface(IID_IBanneredBar,(void**)&pbb); if (SUCCEEDED(hres)) { pbb->SetIconSize(iIcon); pbb->Release(); } return hres; }
void CreateInitialMFU(BOOL fReset);
//
// "Delayed per-user install".
//
// StartMenuInit is the value that tells us what version of the shell
// this user has seen most recently.
//
// missing = has never run explorer before, or pre-IE4
// 1 = IE4 or later
// 2 = XP or later
//
void HandleFirstTime() { DWORD dwStartMenuInit = 0; DWORD cb = sizeof(dwStartMenuInit); SHGetValue(HKEY_CURRENT_USER, REGSTR_PATH_ADVANCED, TEXT("StartMenuInit"), NULL, &dwStartMenuInit, &cb);
if (dwStartMenuInit < 2) { DWORD dwValue; switch (dwStartMenuInit) { case 0: // Upgrade from 0 to latest
{ // If this is the first boot of the shell for this user, then we need to see if it's an upgrade.
// If it is, then we need set the Logoff option. PM Decision to have a different
// look for upgraded machines...
TCHAR szPath[MAX_PATH]; TCHAR szPathExplorer[MAX_PATH]; DWORD cbSize = ARRAYSIZE(szPath); DWORD dwType;
// Is this an upgrade (Does WindowsUpdate\UpdateURL Exist?)
PathCombine(szPathExplorer, REGSTR_PATH_EXPLORER, TEXT("WindowsUpdate")); if (ERROR_SUCCESS == SHGetValue(HKEY_LOCAL_MACHINE, szPathExplorer, TEXT("UpdateURL"), &dwType, szPath, &cbSize) && szPath[0] != TEXT('\0')) { // Yes; Then write the option out to the registry.
dwValue = 1; SHSetValue(HKEY_CURRENT_USER, REGSTR_PATH_ADVANCED, TEXT("StartMenuLogoff"), REG_DWORD, &dwValue, sizeof(DWORD)); } }
// FALL THROUGH
case 1: // Upgrade from 1 to latest
// User has never seen XP before.
// PMs in certain groups insist on getting free advertising
// even on upgrades, so we do it.
CreateInitialMFU(dwStartMenuInit == 0);
// FALL THROUGH
default: break; }
// If AuditInProgress is set; that means that we are in the
// OEM sysprep stage and not running as an end user, in which
// case don't set the flag saying "don't do this again" because
// we do want to do this again when the retail end user logs
// on for the first time.
//
// (We need to do all this work even in Audit mode so the OEM
// gets a warm fuzzy feeling.)
if (!SHRegGetBoolUSValue(TEXT("System\\Setup"), TEXT("AuditinProgress"), TRUE, FALSE)) { // Mark this so that we know we've been launched once.
dwValue = 2; SHSetValue(HKEY_CURRENT_USER, REGSTR_PATH_ADVANCED, TEXT("StartMenuInit"), REG_DWORD, &dwValue, sizeof(DWORD)); } } }
BOOL GetLogonUserName(LPTSTR pszUsername, DWORD* pcchUsername) { BOOL fSuccess = FALSE;
HKEY hkeyExplorer = NULL; if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, REGSTR_PATH_EXPLORER, 0, KEY_QUERY_VALUE, &hkeyExplorer)) { DWORD dwType; DWORD dwSize = (*pcchUsername) * sizeof(TCHAR);
if (ERROR_SUCCESS == RegQueryValueEx(hkeyExplorer, TEXT("Logon User Name"), 0, &dwType, (LPBYTE) pszUsername, &dwSize)) { if ((REG_SZ == dwType) && (*pszUsername)) { fSuccess = TRUE; } }
RegCloseKey(hkeyExplorer); }
// Fall back on GetUserName if the Logon User Name isn't set.
if (!fSuccess) { fSuccess = GetUserName(pszUsername, pcchUsername);
if (fSuccess) { CharUpperBuff(pszUsername, 1); } }
return fSuccess; }
BOOL _ShowStartMenuLogoff() { // We want the Logoff menu on the start menu if:
// These MUST both be true
// 1) It's not restricted
// 2) We have Logged On.
// Any of these three.
// 3) We've Upgraded from IE4
// 4) The user has specified that it should be present
// 5) It's been "Restricted" On.
// Behavior also depends on whether we are a remote session or not (dsheldon):
// Remote session: Logoff brings up shutdown dialog
// Console session: Logoff directly does logoff
DWORD dwRest = SHRestricted(REST_STARTMENULOGOFF); SHELLSTATE ss = {0};
SHGetSetSettings(&ss, SSF_STARTPANELON, FALSE); // if the new start menu is on, always show logoff
BOOL fUserWantsLogoff = ss.fStartPanelOn || GetExplorerUserSetting(HKEY_CURRENT_USER, TEXT("Advanced"), TEXT("StartMenuLogoff")) > 0; BOOL fAdminWantsLogoff = (BOOL)(dwRest == 2) || SHRestricted(REST_FORCESTARTMENULOGOFF); BOOL fIsFriendlyUIActive = IsOS(OS_FRIENDLYLOGONUI); BOOL fIsTS = GetSystemMetrics(SM_REMOTESESSION);
if ((dwRest != 1 && (GetSystemMetrics(SM_NETWORK) & RNC_LOGON) != 0) && ( fUserWantsLogoff || fAdminWantsLogoff || fIsFriendlyUIActive || fIsTS)) { return TRUE; } else { return FALSE; } }
BOOL _ShowStartMenuEject() { if(SHRestricted(REST_NOSMEJECTPC)) //Is there a policy restriction?
return FALSE; // CanShowEject Queries the user's permission to eject,
// IsEjectAllowed queries the hardware.
return SHTestTokenPrivilege(NULL, SE_UNDOCK_NAME) && IsEjectAllowed(FALSE) && !GetSystemMetrics(SM_REMOTESESSION); }
BOOL _ShowStartMenuRun() { return !IsRestrictedOrUserSetting(HKEY_CURRENT_USER, REST_NORUN, TEXT("Advanced"), TEXT("StartMenuRun"), ROUS_KEYALLOWS | ROUS_DEFAULTALLOW); }
BOOL _ShowStartMenuHelp() { return !IsRestrictedOrUserSetting(HKEY_CURRENT_USER, REST_NOSMHELP, TEXT("Advanced"), TEXT("NoStartMenuHelp"), ROUS_KEYRESTRICTS | ROUS_DEFAULTALLOW); }
BOOL _ShowStartMenuShutdown() { return !SHRestricted(REST_NOCLOSE) && (IsOS(OS_ANYSERVER) || (!GetSystemMetrics(SM_REMOTESESSION) && (!IsOS(OS_FRIENDLYLOGONUI) || SHTestTokenPrivilege(NULL, SE_SHUTDOWN_NAME)))); // if friendly logon is active, then don't show shutdown unless they have privileges, since shutdown "only" shuts you down.
// if they're not using friendly logon ui, then shutdown also contains options to log you off/hibernate, so show it...
}
// If remote and not disabled by administrator then show "Disconnect".
// Don't show on Server SKUs because they already have Turn Off Computer.
BOOL _ShowStartMenuDisconnect() { return GetSystemMetrics(SM_REMOTESESSION) && !SHRestricted(REST_NODISCONNECT) && !IsOS(OS_ANYSERVER); }
BOOL _ShowStartMenuSearch() { return !SHRestricted(REST_NOFIND); }
HMENU GetStaticStartMenu(BOOL fEdit) { #define CITEMSMISSING 4
HMENU hStartMenu = LoadMenuPopup(MAKEINTRESOURCE(MENU_START));
// If no editing requested, then we're done, lickity-split
if (!fEdit) return hStartMenu;
HMENU hmenu; UINT iSep2ItemsMissing = 0;
//
// Default to the Win95/NT4 version of the Settings menu.
//
// Restictions
if (!_ShowStartMenuRun()) { DeleteMenu(hStartMenu, IDM_FILERUN, MF_BYCOMMAND); }
if (!_ShowStartMenuHelp()) { DeleteMenu(hStartMenu, IDM_HELPSEARCH, MF_BYCOMMAND); }
if (IsRestrictedOrUserSetting(HKEY_LOCAL_MACHINE, REST_NOCSC, TEXT("Advanced"), TEXT("StartMenuSyncAll"), ROUS_KEYALLOWS | ROUS_DEFAULTRESTRICT)) { DeleteMenu(hStartMenu, IDM_CSC, MF_BYCOMMAND); iSep2ItemsMissing++; }
BOOL fIsFriendlyUIActive = IsOS(OS_FRIENDLYLOGONUI);
if (_ShowStartMenuLogoff()) { UINT idMenuRenameToLogoff = IDM_LOGOFF;
TCHAR szUserName[200]; TCHAR szTemp[256]; TCHAR szMenuText[256]; DWORD dwSize = ARRAYSIZE(szUserName); MENUITEMINFO mii;
mii.cbSize = sizeof(MENUITEMINFO); mii.dwTypeData = szTemp; mii.fMask = MIIM_TYPE | MIIM_ID | MIIM_SUBMENU | MIIM_STATE | MIIM_DATA; mii.cch = ARRAYSIZE(szTemp); mii.hSubMenu = NULL; mii.fType = MFT_SEPARATOR; // to avoid ramdom result.
mii.dwItemData = 0;
GetMenuItemInfo(hStartMenu,idMenuRenameToLogoff,MF_BYCOMMAND,&mii);
if (GetLogonUserName(szUserName, &dwSize)) { if (fIsFriendlyUIActive) { dwSize = ARRAYSIZE(szUserName);
if (FAILED(SHGetUserDisplayName(szUserName, &dwSize))) { dwSize = ARRAYSIZE(szUserName); GetLogonUserName(szUserName, &dwSize); } } StringCchPrintf(szMenuText,ARRAYSIZE(szMenuText), szTemp, szUserName); } else if (!LoadString(hinstCabinet, IDS_LOGOFFNOUSER, szMenuText, ARRAYSIZE(szMenuText))) { // mem error, use the current string.
szUserName[0] = 0; StringCchPrintf(szMenuText, ARRAYSIZE(szMenuText), szTemp, szUserName); }
mii.dwTypeData = szMenuText; mii.cch = ARRAYSIZE(szMenuText); SetMenuItemInfo(hStartMenu,idMenuRenameToLogoff,MF_BYCOMMAND,&mii); } else { DeleteMenu(hStartMenu, IDM_LOGOFF, MF_BYCOMMAND); iSep2ItemsMissing++; }
// If restricted, then user cannot shut down at all.
// If friendly UI is active change "Shut Down..." to "Turn Off Computer..."
if (!_ShowStartMenuShutdown()) { DeleteMenu(hStartMenu, IDM_EXITWIN, MF_BYCOMMAND); iSep2ItemsMissing++; } else if (fIsFriendlyUIActive) {
// If the user has the SE_SHUTDOWN_NAME privilege
// then rename the menu item.
if (SHTestTokenPrivilege(NULL, SE_SHUTDOWN_NAME) && !GetSystemMetrics(SM_REMOTESESSION)) { MENUITEMINFO mii; TCHAR szMenuText[256];
(int)LoadString(hinstCabinet, IDS_TURNOFFCOMPUTER, szMenuText, ARRAYSIZE(szMenuText)); ZeroMemory(&mii, sizeof(mii)); mii.cbSize = sizeof(mii); mii.fMask = MIIM_TYPE; mii.fType = MFT_STRING; mii.dwTypeData = szMenuText; mii.cch = ARRAYSIZE(szMenuText); TBOOL(SetMenuItemInfo(hStartMenu, IDM_EXITWIN, FALSE, &mii)); }
// Otherwise delete the menu item.
else { DeleteMenu(hStartMenu, IDM_EXITWIN, MF_BYCOMMAND); iSep2ItemsMissing++; } }
if (!_ShowStartMenuDisconnect()) { DeleteMenu(hStartMenu, IDM_MU_DISCONNECT, MF_BYCOMMAND); iSep2ItemsMissing++; }
if (iSep2ItemsMissing == CITEMSMISSING) { DeleteMenu(hStartMenu, IDM_SEP2, MF_BYCOMMAND); }
if (!_ShowStartMenuEject()) { DeleteMenu(hStartMenu, IDM_EJECTPC, MF_BYCOMMAND); }
// Setting stuff.
hmenu = SHGetMenuFromID(hStartMenu, IDM_SETTINGS); if (hmenu) { int iMissingSettings = 0;
#define CITEMS_SETTINGS 5 // Number of items in settings menu
if (SHRestricted(REST_NOSETTASKBAR)) { DeleteMenu(hStartMenu, IDM_TRAYPROPERTIES, MF_BYCOMMAND); iMissingSettings++; }
if (SHRestricted(REST_NOSETFOLDERS) || SHRestricted(REST_NOCONTROLPANEL)) { DeleteMenu(hStartMenu, IDM_CONTROLS, MF_BYCOMMAND);
// For the separator that now on top
DeleteMenu(hmenu, 0, MF_BYPOSITION); iMissingSettings++; }
if (SHRestricted(REST_NOSETFOLDERS)) { DeleteMenu(hStartMenu, IDM_PRINTERS, MF_BYCOMMAND); iMissingSettings++; }
if (SHRestricted(REST_NOSETFOLDERS) || SHRestricted(REST_NONETWORKCONNECTIONS) ) { DeleteMenu(hStartMenu, IDM_NETCONNECT, MF_BYCOMMAND); iMissingSettings++; }
if (!SHGetMachineInfo(GMI_TSCLIENT) || SHRestricted(REST_NOSECURITY)) { DeleteMenu(hStartMenu, IDM_MU_SECURITY, MF_BYCOMMAND); iMissingSettings++; }
// Are all the items missing?
if (iMissingSettings == CITEMS_SETTINGS) { // Yes; don't bother showing the menu at all
DeleteMenu(hStartMenu, IDM_SETTINGS, MF_BYCOMMAND); } } else { DebugMsg(DM_ERROR, TEXT("c.fm_rui: Settings menu couldn't be found. Restricted items may not have been removed.")); }
// Find menu.
if (!_ShowStartMenuSearch()) { DeleteMenu(hStartMenu, IDM_MENU_FIND, MF_BYCOMMAND); }
// Documents menu.
if (SHRestricted(REST_NORECENTDOCSMENU)) { DeleteMenu(hStartMenu, IDM_RECENT, MF_BYCOMMAND); }
// Favorites menu.
if (IsRestrictedOrUserSetting(HKEY_CURRENT_USER, REST_NOFAVORITESMENU, TEXT("Advanced"), TEXT("StartMenuFavorites"), ROUS_KEYALLOWS | ROUS_DEFAULTRESTRICT)) { DeleteMenu(hStartMenu, IDM_FAVORITES, MF_BYCOMMAND); }
return hStartMenu; }
//
// CHotKey class
//
// constructor
CHotKey::CHotKey() : _cRef(1) { }
STDMETHODIMP CHotKey::QueryInterface(REFIID riid, LPVOID * ppvObj) { if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IShellHotKey)) { *ppvObj = SAFECAST(this, IShellHotKey *); } else { *ppvObj = NULL; return E_NOINTERFACE; }
AddRef(); return NOERROR; }
STDMETHODIMP_(ULONG) CHotKey::AddRef() { return ++_cRef; }
STDMETHODIMP_(ULONG) CHotKey::Release() { ASSERT(_cRef > 0); _cRef--;
if( _cRef > 0) return _cRef;
delete this; return 0; }
HRESULT Tray_RegisterHotKey(WORD wHotkey, LPCITEMIDLIST pidlParent, LPCITEMIDLIST pidl) { if (wHotkey) { int i = c_tray.HotkeyAdd(wHotkey, (LPITEMIDLIST)pidlParent, (LPITEMIDLIST)pidl, TRUE); if (i != -1) { // Register in the context of the tray's thread.
PostMessage(v_hwndTray, WMTRAY_REGISTERHOTKEY, i, 0); } } return S_OK; }
/*----------------------------------------------------------
Purpose: IShellHotKey::RegisterHotKey method
*/ STDMETHODIMP CHotKey::RegisterHotKey(IShellFolder * psf, LPCITEMIDLIST pidlParent, LPCITEMIDLIST pidl) { WORD wHotkey; HRESULT hr = S_OK;
wHotkey = _GetHotkeyFromFolderItem(psf, pidl); if (wHotkey) { hr = ::Tray_RegisterHotKey(wHotkey, pidlParent, pidl); } return hr; }
STDAPI CHotKey_Create(IShellHotKey ** ppshk) { HRESULT hres = E_OUTOFMEMORY; CHotKey * photkey = new CHotKey;
if (photkey) { hres = S_OK; }
*ppshk = SAFECAST(photkey, IShellHotKey *); return hres; }
|