startmnu.cpp
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 21k
Category:

Windows Kernel

Development Platform:

Visual C++

  1. #include "cabinet.h"
  2. //#define CPP_FUNCTIONS
  3. #include <crtfree.h>
  4. #include "rcids.h"
  5. #include <shguidp.h>
  6. #include <fsmenu.h>
  7. #include "bandsite.h"
  8. #include "shellp.h"
  9. #include "shdguid.h"
  10. #include <regstr.h> 
  11. #include "startmnu.h"
  12. #include "trayp.h"      // for WMTRAY_*
  13. #include "apithk.h"
  14. //BUGBUG move this to a common location, it's currently in shdocvwmenubar.h
  15. #define  MBCID_GETSIDE   1
  16. #define MENUBAR_LEFT     ABE_LEFT
  17. #define MENUBAR_TOP      ABE_TOP
  18. #define MENUBAR_RIGHT    ABE_RIGHT
  19. #define MENUBAR_BOTTOM   ABE_BOTTOM
  20. #define REGSTR_PATH_ADVANCED REGSTR_PATH_EXPLORER TEXT("\Advanced")
  21. HMENU GetStaticStartMenu();
  22. //So much for trying to keep it self contained....
  23. extern "C" HMENU Menu_FindSubMenuByFirstID(HMENU hmenu, UINT id); //plucked out of tray.c
  24. // *** IUnknown methods ***
  25. STDMETHODIMP CStartMenuHost::QueryInterface (REFIID riid, LPVOID * ppvObj)
  26. {
  27.     if(IsEqualIID(riid, IID_IUnknown) ||
  28.         IsEqualIID(riid, IID_IOleWindow) ||
  29.         IsEqualIID(riid, IID_IDeskBarClient) ||
  30.         IsEqualIID(riid, IID_IMenuPopup))
  31.     {
  32.         *ppvObj = SAFECAST(this, IMenuPopup*);
  33.     }
  34.     else if(IsEqualIID(riid,IID_ITrayPriv))
  35.         *ppvObj = SAFECAST(this,ITrayPriv*);
  36.     else if(IsEqualIID(riid,IID_IShellService))
  37.         *ppvObj = SAFECAST(this,IShellService*);
  38.     else if(IsEqualIID(riid,IID_IServiceProvider))
  39.         *ppvObj = SAFECAST(this,IServiceProvider*);
  40.     else if(IsEqualIID(riid,IID_IOleCommandTarget))
  41.         *ppvObj = SAFECAST(this,IOleCommandTarget*);
  42.     else if(IsEqualIID(riid,IID_IWinEventHandler))
  43.         *ppvObj = SAFECAST(this,IWinEventHandler*);
  44.     else
  45.     {
  46.         *ppvObj = NULL;
  47.         return E_NOINTERFACE;
  48.     }
  49.     AddRef();
  50.     return NOERROR;
  51. }
  52. STDMETHODIMP_(ULONG) CStartMenuHost::AddRef ()
  53. {
  54.     return ++_cRef;
  55. }
  56. STDMETHODIMP_(ULONG) CStartMenuHost::Release()
  57. {
  58.     ASSERT(_cRef > 0);
  59.     _cRef--;
  60.     if( _cRef > 0)
  61.         return _cRef;
  62.     delete this;
  63.     return 0;
  64. }
  65. /*----------------------------------------------------------
  66. Purpose: ITrayPriv::ExecItem method
  67. */
  68. STDMETHODIMP CStartMenuHost::ExecItem (IShellFolder* psf, LPCITEMIDLIST pidl)
  69. {
  70.     HRESULT hres = SHInvokeDefaultCommand(v_hwndTray, psf, pidl);
  71.     // HACKHACK (reinerf) - since the proper hres is not returned from SHInvokeDefaultCommand and I dont want to risk changing
  72.     // the context menu code for win2k at this point, we use GetLastError to see if the user cancled the operation so that
  73.     // we can avoid showing our error dialog in the user-cancelled case (ShellExecuteEx will call SetLastError, thank god!)
  74.     if (FAILED(hres) && (GetLastError() != ERROR_CANCELLED))
  75.     {
  76.         TCHAR szLinkPath[MAX_PATH];
  77.         SHGetPathFromIDList(pidl, szLinkPath);
  78.         int iError = IDS_CANTFINDFILE;
  79.         if (szLinkPath[0] == TEXT(''))
  80.         {
  81.             iError = IDS_CANTRUN;
  82.         }
  83.         ShellMessageBox(hinstCabinet, v_hwndTray, MAKEINTRESOURCE(iError), 
  84.                         MAKEINTRESOURCE(IDS_CABINET), MB_ICONEXCLAMATION, szLinkPath);
  85.     }
  86.     return hres;
  87. }
  88. /*----------------------------------------------------------
  89. Purpose: ITrayPriv::GetFindCM method
  90. */
  91. STDMETHODIMP CStartMenuHost::GetFindCM(HMENU hmenu, UINT idFirst, UINT idLast, IContextMenu** ppcmFind)
  92. {
  93.     *ppcmFind = SHFind_InitMenuPopup(hmenu, v_hwndTray, TRAY_IDM_FINDFIRST, TRAY_IDM_FINDLAST);
  94.     if(*ppcmFind)
  95.         return NOERROR;
  96.     else
  97.         return E_FAIL;
  98. }
  99. /*----------------------------------------------------------
  100. Purpose: ITrayPriv::GetStaticStartMenu method
  101. */
  102. STDMETHODIMP CStartMenuHost::GetStaticStartMenu(HMENU* phmenu)
  103. {
  104.     *phmenu = ::GetStaticStartMenu();
  105.     if(*phmenu)
  106.         return NOERROR;
  107.     else
  108.         return E_FAIL;
  109. }
  110. // *** IServiceProvider ***
  111. STDMETHODIMP CStartMenuHost::QueryService (REFGUID guidService, REFIID riid, void ** ppvObject)
  112. {
  113.     if(IsEqualGUID(guidService,SID_SMenuPopup))
  114.         return QueryInterface(riid,ppvObject);
  115.     else
  116.         return E_NOINTERFACE;
  117. }
  118. // *** IShellService ***
  119. // BUGBUG (scotth): remove this if it's not being used
  120. STDMETHODIMP CStartMenuHost::SetOwner (struct IUnknown* punkOwner)
  121. {
  122.     return E_NOTIMPL;
  123. }
  124. // *** IOleWindow methods ***
  125. STDMETHODIMP CStartMenuHost::GetWindow(HWND * lphwnd)
  126. {
  127.     *lphwnd = v_hwndTray;
  128.     return NOERROR;
  129. }
  130. /*----------------------------------------------------------
  131. Purpose: IMenuPopup::Popup method
  132. */
  133. STDMETHODIMP CStartMenuHost::Popup(POINTL *ppt, RECTL *prcExclude, DWORD dwFlags)
  134. {
  135.     return E_NOTIMPL;
  136. }
  137. /*----------------------------------------------------------
  138. Purpose: IMenuPopup::OnSelect method
  139. */
  140. STDMETHODIMP CStartMenuHost::OnSelect(DWORD dwSelectType)
  141. {
  142.     return NOERROR;
  143. }
  144. /*----------------------------------------------------------
  145. Purpose: IMenuPopup::SetSubMenu method
  146. */
  147. extern "C" UINT g_uStartButtonAllowPopup;
  148. STDMETHODIMP CStartMenuHost::SetSubMenu(IMenuPopup* pmp, BOOL fSet)
  149. {
  150.     if (!fSet)
  151.     {
  152.         g_ts.bMainMenuInit = FALSE;
  153.         // Tell the Start Button that it's allowed to be in the up position now. This
  154.         // prevents the problem where the start menu is displayed but the button is
  155.         // in the up position... This happens when dialog boxes are displayed
  156.         SendMessage(g_ts.hwndStart, g_uStartButtonAllowPopup, 0, 0);
  157.         // Now tell it to be in the up position
  158.         _ForceStartButtonUp();
  159.     }
  160.     return NOERROR;
  161. }
  162. // *** IOleCommandTarget ***
  163. STDMETHODIMP  CStartMenuHost::QueryStatus (const GUID * pguidCmdGroup,
  164.     ULONG cCmds, OLECMD rgCmds[], OLECMDTEXT *pcmdtext)
  165. {
  166.     return E_NOTIMPL;
  167. }
  168. STDMETHODIMP  CStartMenuHost::Exec (const GUID * pguidCmdGroup,
  169.     DWORD nCmdID, DWORD nCmdexecopt, VARIANTARG *pvarargIn, VARIANTARG *pvarargOut)
  170. {
  171.     if (IsEqualGUID(CGID_MENUDESKBAR,*pguidCmdGroup))
  172.     {
  173.         switch (nCmdID)
  174.         {
  175.         case MBCID_GETSIDE:
  176.             pvarargOut->vt = VT_I4;
  177.             pvarargOut->lVal = MENUBAR_TOP;
  178.             break;
  179.         default:
  180.             break;
  181.         }
  182.     }
  183.     return NOERROR;
  184. }
  185. // *** IWinEventHandler ***
  186. STDMETHODIMP CStartMenuHost::OnWinEvent(HWND h, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *plres)
  187. {
  188.     //Forward events to the tray winproc?
  189.     return E_NOTIMPL;
  190. }
  191. STDMETHODIMP CStartMenuHost::IsWindowOwner(HWND hwnd)
  192. {
  193.     return E_NOTIMPL;
  194. }
  195. CStartMenuHost::CStartMenuHost() : _cRef(1)
  196. }
  197. HRESULT StartMenuHost_Create(IMenuPopup** ppmp, IMenuBand** ppmb)
  198. {
  199.     HRESULT hres = E_OUTOFMEMORY;
  200.     IMenuPopup * pmp = NULL;
  201.     IMenuBand * pmb = NULL;
  202.     CStartMenuHost *psmh = new CStartMenuHost();
  203.     if (psmh)
  204.     {
  205.         hres = CoCreateInstance(CLSID_StartMenuBar, NULL, CLSCTX_INPROC_SERVER, 
  206.                                 IID_IMenuPopup, (LPVOID*)&pmp);
  207.         if (SUCCEEDED(hres))
  208.         {
  209.             IObjectWithSite* pows;
  210.             hres = pmp->QueryInterface(IID_IObjectWithSite, (void**)&pows);
  211.             if(SUCCEEDED(hres))
  212.             {
  213.                 IInitializeObject* pio;
  214.                 pows->SetSite(SAFECAST(psmh, ITrayPriv*));
  215.                 hres = pmp->QueryInterface(IID_IInitializeObject, (void**)&pio);
  216.                 if(SUCCEEDED(hres))
  217.                 {
  218.                     hres = pio->Initialize();
  219.                     pio->Release();
  220.                 }
  221.                 if (SUCCEEDED(hres))
  222.                 {
  223.                     IUnknown* punk;
  224.                     hres = pmp->GetClient(&punk);
  225.                     if (SUCCEEDED(hres))
  226.                     {
  227.                         IBandSite* pbs;
  228.                         hres = punk->QueryInterface(IID_IBandSite, (void**)&pbs);
  229.                         if(SUCCEEDED(hres))
  230.                         {
  231.                             DWORD dwBandID;
  232.                             pbs->EnumBands(0, &dwBandID);
  233.                             hres = pbs->GetBandObject(dwBandID, IID_IMenuBand, (void**)&pmb);
  234.                             pbs->Release();
  235.                             // Don't release pmb
  236.                         }
  237.                         punk->Release();
  238.                     }
  239.                 }
  240.                 if (FAILED(hres))
  241.                     pows->SetSite(NULL);
  242.                 pows->Release();
  243.             }
  244.             // Don't release pmp
  245.         }
  246.         psmh->Release();
  247.     }
  248.     if (FAILED(hres))
  249.     {
  250.         ATOMICRELEASE(pmp);
  251.         ATOMICRELEASE(pmb);
  252.     }
  253.     *ppmp = pmp;
  254.     *ppmb = pmb;
  255.     return hres;
  256. }
  257. HRESULT IMenuPopup_SetIconSize(IMenuPopup* pmp,DWORD iIcon)
  258. {
  259.     IBanneredBar* pbb;
  260. if (pmp == NULL)
  261. return E_FAIL;
  262.     HRESULT hres = pmp->QueryInterface(IID_IBanneredBar,(void**)&pbb);
  263.     if (SUCCEEDED(hres))
  264.     {
  265.         pbb->SetIconSize(iIcon);
  266.         pbb->Release();
  267.     }
  268.     return hres;
  269. }
  270. BOOL _IsValidKey(HKEY hkeyRoot, LPCTSTR pszSubKey, LPCTSTR pszValue)
  271. {
  272.     TCHAR szPath[MAX_PATH];
  273.     TCHAR szPathExplorer[MAX_PATH];
  274.     DWORD cbSize = ARRAYSIZE(szPath);
  275.     DWORD dwType;
  276.     lstrcpy(szPathExplorer, REGSTR_PATH_EXPLORER);
  277.     PathCombine(szPathExplorer, szPathExplorer, pszSubKey);
  278.     if (ERROR_SUCCESS == SHGetValue(hkeyRoot, szPathExplorer, pszValue, 
  279.             &dwType, szPath, &cbSize))
  280.     {
  281.         // Zero in the DWORD case or NULL in the string case
  282.         // indicates that this item is not available.
  283.         if (dwType == REG_DWORD)
  284.             return *((DWORD*)szPath) != 0;
  285.         else
  286.             return (TCHAR)szPath[0] != TEXT('');    
  287.     }
  288.     return FALSE;
  289. }
  290. BOOL _IsRestricted(HKEY hkeyRoot, BOOL fRestrictedIfNotValid, RESTRICTIONS rest, LPCTSTR pszSubKey, LPCTSTR pszValue)
  291. {
  292.     // If it's shell restricted, remove
  293.     DWORD dwRest = SHRestricted(rest);
  294.     // A restiction of 0 means it's ok, to add, but check to see if some
  295.     // magic reg value is set. A restriction of 2 means, Do it all the time.
  296.     BOOL fValidKey = _IsValidKey(hkeyRoot, pszSubKey, pszValue);
  297.     if (dwRest == 1)
  298.         return TRUE;
  299.     if (dwRest == 2)
  300.         return FALSE;
  301.     return !(fValidKey ^ fRestrictedIfNotValid);  // If it's not a valid key, then it's fRestrictedIfNotValid
  302. }
  303. void HandleFirstTime()
  304. {
  305.     // If this key does not exist, then this is the first boot for this user.
  306.     BOOL fFirstTime = !_IsValidKey(HKEY_CURRENT_USER, TEXT("Advanced"), TEXT("StartMenuInit"));
  307.     if (fFirstTime)
  308.     {
  309.         // If this is the first boot of the shell for this user, then we need to see if it's an upgrade.
  310.         // If it is, then we need set the Logoff option.    PM Decision to have a different 
  311.         // look for upgraded machines...
  312.         TCHAR szPath[MAX_PATH];
  313.         TCHAR szPathExplorer[MAX_PATH];
  314.         DWORD cbSize = ARRAYSIZE(szPath);
  315.         DWORD dwType;
  316.         DWORD dwValue = 1;  // We can be confident that we are not blowing away previous flags.
  317.                             // Why? because we only do this if the key does not exist.
  318.         // Is this an upgrade (Does WindowsUpdateUpdateURL Exist?)
  319.         PathCombine(szPathExplorer, REGSTR_PATH_EXPLORER, TEXT("WindowsUpdate"));
  320.         if (ERROR_SUCCESS == SHGetValue(HKEY_LOCAL_MACHINE, szPathExplorer, TEXT("UpdateURL"), 
  321.                 &dwType, szPath, &cbSize) && 
  322.                 szPath[0] != TEXT(''))
  323.         {
  324.             // Yes; Then write the option out to the registry.
  325.             SHSetValue(HKEY_CURRENT_USER, REGSTR_PATH_ADVANCED, TEXT("StartMenuLogoff"), REG_DWORD, &dwValue, sizeof(DWORD));
  326.         }
  327.         // Mark this so that we know we've been launched once.
  328.         SHSetValue(HKEY_CURRENT_USER, REGSTR_PATH_ADVANCED, TEXT("StartMenuInit"), REG_DWORD, &dwValue, sizeof(DWORD));
  329.     }
  330. }
  331. // This code was obtained from ACPI land.
  332. BOOL CanShowEject()
  333. {
  334.     BOOL bResult = TRUE;
  335. #ifdef WINNT
  336.     HANDLE hToken = NULL;
  337.     PRIVILEGE_SET privilegeSet;
  338.     privilegeSet.PrivilegeCount = 1;
  339.     privilegeSet.Control = 0;
  340.     privilegeSet.Privilege[0].Attributes = 0;
  341.     if (!LookupPrivilegeValue(NULL, SE_UNDOCK_NAME, &privilegeSet.Privilege[0].Luid)) 
  342.     {
  343.     
  344.         //
  345.         // No such privilege?
  346.         //
  347.         ASSERT(0);
  348.         bResult = TRUE;
  349.     }
  350.     if (!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY | TOKEN_IMPERSONATE, TRUE, &hToken)) 
  351.     {
  352.         if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY | TOKEN_IMPERSONATE, &hToken))
  353.         {
  354.             //
  355.             // Error, can't get privileges.
  356.             //
  357.             bResult = FALSE;
  358.         }
  359.     }
  360.     if (hToken != NULL &&
  361.         !PrivilegeCheck(hToken, &privilegeSet, &bResult)) 
  362.     {
  363.     
  364.     //
  365.     // Unprivileged
  366.     // 
  367.         bResult = FALSE;
  368.     }
  369.     if (hToken)
  370.         CloseHandle(hToken);
  371. #endif
  372.     return bResult; 
  373. }
  374. BOOL GetLogonUserName(LPTSTR pszUsername, DWORD* pcchUsername)
  375. {
  376.     BOOL fSuccess = FALSE;
  377.     HKEY hkeyExplorer = NULL;
  378.     if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, REGSTR_PATH_EXPLORER, 0, KEY_QUERY_VALUE, &hkeyExplorer))
  379.     {
  380.         DWORD dwType;
  381.         DWORD dwSize = (*pcchUsername) * sizeof(TCHAR);
  382.         if (ERROR_SUCCESS == RegQueryValueEx(hkeyExplorer, TEXT("Logon User Name"), 0, &dwType,
  383.             (LPBYTE) pszUsername, &dwSize))
  384.         {
  385.             if ((REG_SZ == dwType) && (*pszUsername))
  386.             {
  387.                 fSuccess = TRUE;
  388.             }
  389.         }
  390.         RegCloseKey(hkeyExplorer);
  391.     }
  392.     // Fall back on GetUserName if the Logon User Name isn't set.
  393.     if (!fSuccess)
  394.     {
  395.         fSuccess = GetUserName(pszUsername, pcchUsername);
  396.         if (fSuccess)
  397.         {
  398.             CharUpperBuff(pszUsername, 1);
  399.         }
  400.     }
  401.     return fSuccess;
  402. }
  403. HMENU GetStaticStartMenu()
  404. {
  405. #ifdef WINNT // hydra adds two more items
  406. #define CITEMSMISSING 4
  407. #else
  408. #define CITEMSMISSING 3
  409. #endif
  410.     HMENU hStartMenu = LoadMenuPopup(MAKEINTRESOURCE(MENU_START));
  411.     HMENU hmenu;
  412.     UINT iSep2ItemsMissing = 0;
  413.     //
  414.     // Default to the Win95/NT4 version of the Settings menu.
  415.     //
  416.     // Restictions
  417.     if (SHRestricted(REST_NORUN))
  418.     {
  419.         DeleteMenu(hStartMenu, IDM_FILERUN, MF_BYCOMMAND);
  420.     }
  421.     if (SHRestricted(REST_NOCLOSE))     
  422.     {
  423.         DeleteMenu(hStartMenu, IDM_EXITWIN, MF_BYCOMMAND);
  424.         iSep2ItemsMissing++;     
  425.     }
  426.     if (_IsRestricted(HKEY_CURRENT_USER, TRUE, REST_NOSMHELP, TEXT("Advanced"), TEXT("NoStartMenuHelp")))
  427.     {
  428.         DeleteMenu(hStartMenu, IDM_HELPSEARCH, MF_BYCOMMAND);
  429.     }
  430.     if (_IsRestricted(HKEY_LOCAL_MACHINE, FALSE, REST_NOCSC, TEXT("Advanced"), TEXT("StartMenuSyncAll")))
  431.     {
  432.         DeleteMenu(hStartMenu, IDM_CSC, MF_BYCOMMAND);
  433.         iSep2ItemsMissing++;     
  434.     }
  435.     // We want the Logoff menu on the start menu if:
  436.     //  These MUST both be true
  437.     // 1) It's not restricted
  438.     // 2) We have Logged On.
  439.     //  Any of these three.
  440.     // 3) We've Upgraded from IE4 
  441.     // 4) The user has specified that it should be present
  442.     // 5) It's been "Restricted" On.
  443.     // Behavior also depends on whether we are a remote session or not (dsheldon):
  444.     // Remote session: Logoff brings up shutdown dialog
  445.     // Console session: Logoff directly does logoff
  446.     
  447.     DWORD dwRest = SHRestricted(REST_STARTMENULOGOFF);
  448.     // See if this is an upgrade, and set the user setting accordingly.
  449.     HandleFirstTime();
  450.     BOOL fUserWantsLogoff = _IsValidKey(HKEY_CURRENT_USER, TEXT("Advanced"), TEXT("StartMenuLogoff"));
  451.     BOOL fAdminWantsLogoff = (BOOL)(dwRest == 2) || SHRestricted(REST_FORCESTARTMENULOGOFF);
  452.     if ((dwRest != 1 && (GetSystemMetrics(SM_NETWORK) & RNC_LOGON) != 0) &&
  453.         ( fUserWantsLogoff || fAdminWantsLogoff))
  454.     {
  455.         UINT idMenuRenameToLogoff = IDM_LOGOFF;
  456.         TCHAR szUserName[200];
  457.         TCHAR szTemp[256];
  458.         TCHAR szMenuText[256];
  459.         DWORD dwSize = ARRAYSIZE(szUserName);
  460.         MENUITEMINFO mii;
  461.         mii.cbSize = sizeof(MENUITEMINFO);
  462.         mii.dwTypeData = szTemp;
  463.         mii.fMask = MIIM_TYPE | MIIM_ID | MIIM_SUBMENU | MIIM_STATE | MIIM_DATA;
  464.         mii.cch = ARRAYSIZE(szTemp);
  465.         mii.hSubMenu = NULL;
  466.         mii.fType = MFT_SEPARATOR;                // to avoid ramdom result.
  467.         mii.dwItemData = 0;
  468.         GetMenuItemInfo(hStartMenu,idMenuRenameToLogoff,MF_BYCOMMAND,&mii);
  469.         if (GetLogonUserName(szUserName, &dwSize))
  470.         {
  471.             wsprintf (szMenuText,szTemp, szUserName);
  472.         }
  473.         else if (!LoadString(hinstCabinet, IDS_LOGOFFNOUSER, 
  474.                                           szMenuText, ARRAYSIZE(szMenuText)))
  475.         {
  476.             // mem error, use the current string.
  477.             szUserName[0] = 0;
  478.             wsprintf(szMenuText, szTemp, szUserName);
  479.         }    
  480.         mii.dwTypeData = szMenuText;
  481.         mii.cch = ARRAYSIZE(szMenuText);
  482.         SetMenuItemInfo(hStartMenu,idMenuRenameToLogoff,MF_BYCOMMAND,&mii);
  483.     }
  484.     else
  485.     {
  486.         DeleteMenu(hStartMenu, IDM_LOGOFF, MF_BYCOMMAND);
  487.         iSep2ItemsMissing++;
  488.     }
  489.     if (iSep2ItemsMissing == CITEMSMISSING)
  490.     {
  491.         DeleteMenu(hStartMenu, IDM_SEP2, MF_BYCOMMAND);
  492.     }
  493.     // CanShowEject Queries the user's permission to eject,
  494.     // IsEjectAllowed queries the hardware.
  495.     if (!CanShowEject() || !IsEjectAllowed(FALSE))
  496.     {
  497.         DeleteMenu(hStartMenu, IDM_EJECTPC, MF_BYCOMMAND);
  498.     }
  499.     // Setting stuff.
  500.     hmenu = Menu_FindSubMenuByFirstID(hStartMenu, IDM_CONTROLS);
  501.     if (hmenu)
  502.     {
  503.         int iMissingSettings = 0;
  504. #ifdef WINNT // hydra menu items
  505.         #define CITEMS_SETTINGS     5   // Number of items in settings menu
  506. #else
  507.         #define CITEMS_SETTINGS     4   // Number of items in settings menu
  508. #endif
  509.         
  510.         if (SHRestricted(REST_NOSETTASKBAR))
  511.         {
  512.             DeleteMenu(hStartMenu, IDM_TRAYPROPERTIES, MF_BYCOMMAND);
  513.             iMissingSettings++;
  514.         }
  515.         if (SHRestricted(REST_NOSETFOLDERS) || SHRestricted(REST_NOCONTROLPANEL))
  516.         {
  517.             DeleteMenu(hStartMenu, IDM_CONTROLS, MF_BYCOMMAND);
  518.             // For the separator that now on top
  519.             DeleteMenu(hmenu, 0, MF_BYPOSITION);   
  520.             iMissingSettings++;
  521.         }
  522.         if (SHRestricted(REST_NOSETFOLDERS))
  523.         {
  524.             DeleteMenu(hStartMenu, IDM_PRINTERS, MF_BYCOMMAND);
  525.             iMissingSettings++;
  526.         }
  527.         if (SHRestricted(REST_NOSETFOLDERS) || SHRestricted(REST_NONETWORKCONNECTIONS))
  528.         {
  529.             DeleteMenu(hStartMenu, IDM_NETCONNECT, MF_BYCOMMAND);
  530.             iMissingSettings++;
  531.         }
  532. #ifdef WINNT // hydra menu items
  533.         if (!IsRemoteSession() || SHRestricted(REST_NOSECURITY))
  534.         {
  535.             DeleteMenu(hStartMenu, IDM_MU_SECURITY, MF_BYCOMMAND);
  536.             iMissingSettings++;     
  537.         }
  538. #endif
  539.         // Are all the items missing?
  540.         if (iMissingSettings == CITEMS_SETTINGS)
  541.         {
  542.             // Yes; don't bother showing the menu at all
  543.             DeleteMenu(hStartMenu, IDM_SETTINGS, MF_BYCOMMAND);
  544.         }
  545.     }
  546.     else
  547.     {
  548.         DebugMsg(DM_ERROR, TEXT("c.fm_rui: Settings menu couldn't be found. Restricted items may not have been removed."));
  549.     }
  550.     // Find menu.
  551.     if (SHRestricted(REST_NOFIND))
  552.     {
  553.         DeleteMenu(hStartMenu, IDM_MENU_FIND, MF_BYCOMMAND);
  554.     }
  555.     // Documents menu.
  556.     if (SHRestricted(REST_NORECENTDOCSMENU))
  557.     {
  558.         DeleteMenu(hStartMenu, IDM_RECENT, MF_BYCOMMAND);
  559.     }
  560.     // Favorites menu.
  561.     if (_IsRestricted(HKEY_CURRENT_USER, FALSE, REST_NOFAVORITESMENU, TEXT("Advanced"), TEXT("StartMenuFavorites")))
  562.     {
  563.         DeleteMenu(hStartMenu, IDM_FAVORITES, MF_BYCOMMAND);
  564.     }
  565.     return hStartMenu;
  566. }
  567. //
  568. //  CHotKey class
  569. //
  570. // constructor
  571. CHotKey::CHotKey() : _cRef(1)
  572. {
  573. }
  574. STDMETHODIMP CHotKey::QueryInterface(REFIID riid, LPVOID * ppvObj)
  575. {
  576.     if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IShellHotKey))
  577.     {
  578.         *ppvObj = SAFECAST(this, IShellHotKey *);
  579.     }
  580.     else
  581.     {
  582.         *ppvObj = NULL;
  583.         return E_NOINTERFACE;
  584.     }
  585.     AddRef();
  586.     return NOERROR;
  587. }
  588. STDMETHODIMP_(ULONG) CHotKey::AddRef()
  589. {
  590.     return ++_cRef;
  591. }
  592. STDMETHODIMP_(ULONG) CHotKey::Release()
  593. {
  594.     ASSERT(_cRef > 0);
  595.     _cRef--;
  596.     if( _cRef > 0)
  597.         return _cRef;
  598.     delete this;
  599.     return 0;
  600. }
  601. /*----------------------------------------------------------
  602. Purpose: IShellHotKey::RegisterHotKey method
  603. */
  604. STDMETHODIMP CHotKey::RegisterHotKey(IShellFolder * psf, LPCITEMIDLIST pidlParent, LPCITEMIDLIST pidl)
  605. {
  606.     WORD wHotkey;
  607.     wHotkey = _GetHotkeyFromFolderItem(psf, pidl);
  608.     if (wHotkey)
  609.     {
  610.         int i = HotkeyList_Add(wHotkey, (LPITEMIDLIST)pidlParent, (LPITEMIDLIST)pidl, TRUE);
  611.         if (i != -1)
  612.         {
  613.             // Register in the context of the tray's thread.
  614.             PostMessage(v_hwndTray, WMTRAY_REGISTERHOTKEY, i, 0);
  615.         }
  616.     }
  617.     return S_OK;
  618. }
  619. STDAPI CHotKey_Create(IShellHotKey ** ppshk)
  620. {
  621.     HRESULT hres = E_OUTOFMEMORY;
  622.     CHotKey * photkey = new CHotKey;
  623.     if (photkey)
  624.     {
  625.         hres = S_OK;
  626.     }
  627.     *ppshk = SAFECAST(photkey, IShellHotKey *);
  628.     return hres;
  629. }