#include "priv.h" #include "apithk.h" #include "sccls.h" #include "shbrows2.h" #include "commonsb.h" #include "resource.h" #include "explore2.h" #include #include "desktop.h" #include #include "bands.h" #include "browbar.h" #include "itbdrop.h" #include "theater.h" #include "itbar.h" #include "idispids.h" #include "bsmenu.h" #include "legacy.h" #include "mshtmcid.h" #include // IDeskTray #include "commonsb.h" #include "onetree.h" #include "cnctnpt.h" #include "comcatex.h" #include "util.h" #include "uemapp.h" #include #include #include "trayp.h" #include "oleacc.h" // (lamadio): Conflicts with one defined in winuserp.h #undef WINEVENT_VALID //It's tripping on this... #include "winable.h" #include #include #include "idhidden.h" #include "mediautil.h" #include "mluisupp.h" #define CWM_THEATERMODE (WM_USER + 400) #define CWM_UPDATEBACKFORWARDSTATE (WM_USER + 401) #define SUPERCLASS CCommonBrowser #define PERF_LOGGING 1 HRESULT IUnknown_GetClientDB(IUnknown *punk, IUnknown **ppdbc); // Timer IDs #define SHBTIMER_MENUSELECT 100 #define MENUSELECT_TIME 500 // .5 seconds for the menuselect delay // Command group for private communication with CITBar // 67077B95-4F9D-11D0-B884-00AA00B60104 const GUID CGID_PrivCITCommands = { 0x67077B95L, 0x4F9D, 0x11D0, 0xB8, 0x84, 0x00, 0xAA, 0x00, 0xB6, 0x01, 0x04 }; // Guid of Office's discussion band // {BDEADE7F-C265-11d0-BCED-00A0C90AB50F} EXTERN_C const GUID CLSID_DiscussionBand = { 0xbdeade7fL, 0xc265, 0x11d0, 0xbc, 0xed, 0x00, 0xa0, 0xc9, 0x0a, 0xb5, 0x0f }; // Guid of the Tip of the Day //{4D5C8C25-D075-11d0-B416-00C04FB90376} const GUID CLSID_TipOfTheDay = { 0x4d5c8c25L, 0xd075, 0x11d0, 0xb4, 0x16, 0x00, 0xc0, 0x4f, 0xb9, 0x03, 0x76 }; // Used to see if the discussion band is registered for the CATID_CommBand const LPCTSTR c_szDiscussionBandReg = TEXT("CLSID\\{BDEADE7F-C265-11d0-BCED-00A0C90AB50F}\\Implemented Categories\\{00021494-0000-0000-C000-000000000046}"); // FEATURE: Way back from 1997, ralphw thinks we should remove >iedefault from the following string const TCHAR c_szHtmlHelpFile[] = TEXT("%SYSTEMROOT%\\Help\\iexplore.chm>iedefault"); // Increment this when the saved structure changes const WORD c_wVersion = 0x8002; // This value will be initialized to 0 only when we are under IExplorer.exe UINT g_tidParking = 0; #define MAX_NUM_ZONES_ICONS 12 #define MAX_ZONE_DISPLAYNAME 260 UINT_PTR g_sysmenuTimer = 0; void ITBar_ShowDW(IDockingWindow * pdw, BOOL fTools, BOOL fAddress, BOOL fLinks); void RestrictItbarViewMenu(HMENU hmenu, IUnknown *punkBar); BOOL IsExplorerWindow(HWND hwnd); void _SetWindowIcon(HWND hwnd, HICON hIcon, BOOL bLarge); // // A named mutex is being used to determine if a critical operation exist, such as a file download. // When we detect this we can prevent things like going offline while a download is in progress. // To start the operation Create the named mutex. When the op is complete, close the handle. // To see if any pending operations are in progress, Open the named mutex. Success/fail will indicate // if any pending operations exist. This mechanism is being used to determine if a file download is // in progress when the user attempts to go offline. If so, we prompt them to let them know that going // offline will cancel the download(s). // // Note: (SECURITY) // If a malicious app squats on the "CritOpMutex" named mutex, there are two // potential ways this would impact us: // 1) If they squat as an object other than a mutex, then all our calls to // IsCriticalOperationPending() will return FALSE. The impact of this // is negligable, and means that if the user is downloading a file and // they attempt to switch to "offline" mode we will not prompt the user // that switching to "offline" mode will cancel any/all file transfers // in progress (which we normally do) and simply silently end them. // 2) If they squat as a mutex object, then basically the opposite is true. // All our calls to IsCriticalOperationPending() will return TRUE. The // impact of this is again negligable, and means that if a user attempts // to switch to "offline" mode, regardless of whether or not they may be // downloading a file they will be prompted to cancel any/all file // transfers in progress. HANDLE g_hCritOpMutex = NULL; const LPCSTR c_szCritOpMutexName = "CritOpMutex"; #define StartCriticalOperation() ((g_hCritOpMutex = CreateMutexA(NULL, TRUE, c_szCritOpMutexName)) != (HANDLE)NULL) #define EndCriticalOperation() (CloseHandle(g_hCritOpMutex)) #define IsCriticalOperationPending() (((g_hCritOpMutex = OpenMutexA(MUTEX_ALL_ACCESS, TRUE, c_szCritOpMutexName)) != (HANDLE)NULL) && CloseHandle(g_hCritOpMutex)) #define REG_PATH_ZONEMAP TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\ZoneMap") #define REG_VAL_HARDEN TEXT("IEHarden") #define MAX_FILECONTEXT_STRING (40) #define VALIDATEPENDINGSTATE() ASSERT((_pbbd->_psvPending && _pbbd->_psfPending) || (!_pbbd->_psvPending && !_pbbd->_psfPending)) #define DM_NAV TF_SHDNAVIGATE #define DM_ZONE TF_SHDNAVIGATE #define DM_IEDDE TF_SHDAUTO #define DM_CANCELMODE 0 #define DM_UIWINDOW 0 #define DM_ENABLEMODELESS 0 #define DM_EXPLORERMENU 0 #define DM_BACKFORWARD 0 #define DM_PROTOCOL 0 #define DM_ITBAR 0 #define DM_STARTUP 0 #define DM_AUTOLIFE 0 #define DM_PALETTE 0 #define DM_SESSIONCOUNT 0 #define DM_FOCUS 0 #define DM_PREMERGEDMENU DM_TRACE #define DM_ONSIZE DM_TRACE #define DM_SSL 0 #define DM_SHUTDOWN DM_TRACE #define DM_MISC 0 // misc/tmp extern IDeskTray * g_pdtray; #define ISRECT_EQUAL(rc1, rc2) (((rc1).top == (rc2).top) && ((rc1).bottom == (rc2).bottom) && ((rc1).left == (rc2).left) && ((rc1).right == (rc2).right)) BOOL ViewIDFromViewMode(UINT uViewMode, SHELLVIEWID *pvid); typedef struct _NAVREQUEST { int cbNavData; BYTE *lpNavData; struct _NAVREQUEST *pnext; } NAVREQUEST; // copied from explore/cabwnd.h #define MH_POPUP 0x0010 #define MH_TOOLBAR 0x0020 #define TBOFFSET_NONE 50 #define TBOFFSET_STD 0 #define TBOFFSET_HIST 1 #define TBOFFSET_VIEW 2 extern DWORD g_dwStopWatchMode; // Shell performance mode // Suite Apps Registry keys duplicated from dochost.cpp #define NEW_MAIL_DEF_KEY TEXT("Mail") #define NEW_NEWS_DEF_KEY TEXT("News") #define NEW_CONTACTS_DEF_KEY TEXT("Contacts") #define NEW_CALL_DEF_KEY TEXT("Internet Call") #define NEW_APPOINTMENT_DEF_KEY TEXT("Appointment") #define NEW_MEETING_DEF_KEY TEXT("Meeting") #define NEW_TASK_DEF_KEY TEXT("Task") #define NEW_TASKREQUEST_DEF_KEY TEXT("Task Request") #define NEW_JOURNAL_DEF_KEY TEXT("Journal") #define NEW_NOTE_DEF_KEY TEXT("Note") #define SHELLBROWSER_FSNOTIFY_FLAGS (SHCNE_DRIVEADDGUI | SHCNE_SERVERDISCONNECT | \ SHCNE_MEDIAREMOVED | SHCNE_RMDIR | SHCNE_DELETE | \ SHCNE_UPDATEDIR | SHCNE_NETUNSHARE | \ SHCNE_DRIVEREMOVED | SHCNE_UPDATEITEM | \ SHCNE_RENAMEFOLDER | SHCNE_UPDATEIMAGE | \ SHCNE_MEDIAINSERTED | SHCNE_DRIVEADD) #define FAV_FSNOTIFY_FLAGS (SHCNE_DISKEVENTS | SHCNE_UPDATEIMAGE) #define GOMENU_RECENT_ITEMS 15 // // Prototypes for "reset web settings" code // extern "C" HRESULT ResetWebSettings(HWND hwnd, BOOL *pfHomePageChanged); extern "C" BOOL IsResetWebSettingsRequired(void); const TCHAR c_szMenuItemCust[] = TEXT("Software\\Policies\\Microsoft\\Internet Explorer"); const TCHAR c_szWindowUpdateName[] = TEXT("Windows Update Menu Text"); #pragma warning(disable:4355) // using 'this' in constructor void CShellBrowser2::_PruneGoSubmenu(HMENU hmenu) { // get by position since SHGetMenuFromID does a DFS and we are interested // in the one that is a direct child of hmenu and not some random menu // elsewhere in the hierarchy who might happen to have the same ID. int iPos = SHMenuIndexFromID(hmenu, FCIDM_MENU_EXPLORE); MENUITEMINFO mii; mii.cbSize = sizeof(mii); mii.fMask = MIIM_SUBMENU; if (iPos >= 0 && GetMenuItemInfo(hmenu, iPos, TRUE, &mii) && mii.hSubMenu) { HMENU hmenuGo = mii.hSubMenu; // Remove everything after the first separator MENUITEMINFO mii; int iItem = 0; while (TRUE) { TCHAR szTmp[100]; mii.cbSize = sizeof(mii); mii.fMask = MIIM_TYPE; mii.dwTypeData = szTmp; mii.cch = ARRAYSIZE(szTmp); if (!GetMenuItemInfoWrap(hmenuGo, iItem++, TRUE, &mii)) break; if (mii.fType == MFT_SEPARATOR) { // we must have hit the first seperator, delete the rest of the menu... for (int iDel = GetMenuItemCount(hmenuGo) - 1; iDel >= iItem; iDel--) RemoveMenu(hmenuGo, iDel, MF_BYPOSITION); break; } } } } // // Okay, menus are weird because of the fifteen bazillion scenarios we // need to support. // // There are several functions involved in menu editing. _MenuTemplate, // and all the _OnXxxMenuPopup functions. // // The job of _MenuTemplate is to do global menu munging. These munges // once performed are permanent, so don't munge anything that changes // based on some random ambient condition. The job of the _OnXxxMenuPopup // functions is to do per-instance last-minute munging. // // Also, _MenuTemplate is the only place you can add or remove top-level // menu items. // // fShell = TRUE means that this menu will be used for shell objects. // fShell = FALSE means that this menu will be used for web objects. // // Now the rules... // // NT5: // Tools present. // Shell: "Folder Options" on Tools (not View). // Web: "Internet Options" on Tools (not View). // FTP: "Internet Options" & "Folder Options" on Tools (not View). // Go under View (not top-level). // // Non-NT5, fShell = TRUE, IsCShellBrowser() = TRUE (Single-pane) // Tools removed. // Shell: "Folder Options" on View (not Tools). // Web: "Internet Options" on View (not Tools). // FTP: "Internet Options" & "Folder Options" on View (not Tools). // Go on top-level (not under View). // // Non-NT5, fShell = TRUE, IsCShellBrowser() = FALSE (Dual-pane) // Tools present. // Shell: "Folder Options" on View (not Tools). // Web: "Internet Options" on View (not Tools). // FTP: "Internet Options" & "Folder Options" on View (not Tools). // Go on top-level (not under View). // // Non-NT5, fShell = FALSE, viewing web page: // Tools present. // Shell: "Folder Options" on Tools (not View). // Web: "Internet Options" on Tools (not View). // FTP: "Internet Options" & "Folder Options" on Tools (not View). // Go under View (not top-level). // // Bonus details: // Restrictions. // Shell Options disabled if browser-only. // HMENU CShellBrowser2::_MenuTemplate(int id, BOOL fShell) { HMENU hmenu = LoadMenu(MLGetHinst(), MAKEINTRESOURCE(id)); if (hmenu) { // // According to the chart, there is only one scenario where // we need to nuke the Tools menu: Non-NT5 shell single-pane // if (IsCShellBrowser2() && fShell && GetUIVersion() < 5) DeleteMenu(hmenu, FCIDM_MENU_TOOLS, MF_BYCOMMAND); // // According to the chart, Go vanishes from top-level on NT5 // and on non-shell scenarios. It also vanishes if restricted. // if (GetUIVersion() >= 5 || !fShell || SHRestricted(REST_CLASSICSHELL)) { // get by position since DeleteMenu does a DFS & there are dup FCIDM_MENU_EXPLORE's int iPos = SHMenuIndexFromID(hmenu, FCIDM_MENU_EXPLORE); if (iPos >= 0) DeleteMenu(hmenu, iPos, MF_BYPOSITION); } // Nuke file menu if restricted if (SHRestricted(REST_NOFILEMENU)) DeleteMenu(hmenu, FCIDM_MENU_FILE, MF_BYCOMMAND); // Nuke favorites menu if a rooted explorer or shell menu and classic shell is set // or if restricted if ((fShell && SHRestricted(REST_CLASSICSHELL)) || SHRestricted2(REST_NoFavorites, NULL, 0)) DeleteMenu(hmenu, FCIDM_MENU_FAVORITES, MF_BYCOMMAND); HMENU hmenuView = SHGetMenuFromID(hmenu, FCIDM_MENU_VIEW); if (hmenuView) { // Go appears in only one place, so this test is just // the reverse of the one that decided if Go stays // at top-level. if (fShell && GetUIVersion() < 5) { DeleteMenu(hmenuView, FCIDM_MENU_EXPLORE, MF_BYCOMMAND); } } // Folder Options requires integrated shell if (fShell && WhichPlatform() != PLATFORM_INTEGRATED) { if (hmenuView) { _EnableMenuItem(hmenuView, FCIDM_BROWSEROPTIONS, FALSE); } HMENU hmenuTools = SHGetMenuFromID(hmenu, FCIDM_MENU_TOOLS); if (hmenuTools) { _EnableMenuItem(hmenuTools, FCIDM_BROWSEROPTIONS, FALSE); } } } return hmenu; } // Determine if we need to add the Fortezza menu // For perf reasons, do not call this function unless user is // browsing outside the local machine--- it will load WININET bool NeedFortezzaMenu() { static bool fChecked = false, fNeed = false; // Never show the Fortezza option when offline if (SHIsGlobalOffline()) return false; else if (fChecked) return fNeed; else { fChecked = true; DWORD fStatus = 0; BOOL fQuery = InternetQueryFortezzaStatus(&fStatus, 0); return (fNeed = fQuery && (fStatus&FORTSTAT_INSTALLED)); } } // Create and return the Fortezza menu HMENU FortezzaMenu() { HMENU hfm = NULL; static TCHAR szLogInItem[32] = TEXT(""), // Initialize to empty strings szLogOutItem[32] = TEXT(""), szChangeItem[32] = TEXT(""); static bool fInit = false; if (!fInit) // Load the strings only once { MLLoadString(IDS_FORTEZZA_LOGIN, szLogInItem, ARRAYSIZE(szLogInItem)-1); MLLoadString(IDS_FORTEZZA_LOGOUT, szLogOutItem, ARRAYSIZE(szLogOutItem)-1); MLLoadString(IDS_FORTEZZA_CHANGE, szChangeItem, ARRAYSIZE(szChangeItem)-1); fInit = true; } if (hfm = CreatePopupMenu()) { AppendMenu(hfm, MF_STRING, FCIDM_FORTEZZA_LOGIN, szLogInItem); AppendMenu(hfm, MF_STRING, FCIDM_FORTEZZA_LOGOUT, szLogOutItem); AppendMenu(hfm, MF_STRING, FCIDM_FORTEZZA_CHANGE, szChangeItem); } return hfm; } // Configure the menu depending on card state // This function is called only if Fortezza has been detected void SetFortezzaMenu(HMENU hfm) { if (hfm==NULL) return; DWORD fStatus = 0; if (InternetQueryFortezzaStatus(&fStatus, 0)) { // If the query succeeds, the items are enabled depending // on whether the user is logged in to Fortezza. _EnableMenuItem(hfm, FCIDM_FORTEZZA_CHANGE, (fStatus&FORTSTAT_LOGGEDON) ? TRUE : FALSE); _EnableMenuItem(hfm, FCIDM_FORTEZZA_LOGIN, (fStatus&FORTSTAT_LOGGEDON) ? FALSE : TRUE); _EnableMenuItem(hfm, FCIDM_FORTEZZA_LOGOUT, (fStatus&FORTSTAT_LOGGEDON) ? TRUE : FALSE); } else { // If the query fails, all items are grayed out. _EnableMenuItem(hfm, FCIDM_FORTEZZA_CHANGE, FALSE); _EnableMenuItem(hfm, FCIDM_FORTEZZA_LOGIN, FALSE); _EnableMenuItem(hfm, FCIDM_FORTEZZA_LOGOUT, FALSE); } return; } DWORD DoNetConnect(HWND hwnd) { return (DWORD)SHStartNetConnectionDialog(NULL, NULL, RESOURCETYPE_DISK); } DWORD DoNetDisconnect(HWND hwnd) { DWORD ret = WNetDisconnectDialog(NULL, RESOURCETYPE_DISK); SHChangeNotifyHandleEvents(); // flush any drive notifications TraceMsg(DM_TRACE, "shell:CNet - TRACE: DisconnectDialog returned (%lx)", ret); if (ret == WN_EXTENDED_ERROR) { // FEATURE: is this still needed // There has been a bug with this returning this but then still // doing the disconnect. For now lets bring up a message and then // still do the notify to have the shell attempt to cleanup. TCHAR szErrorMsg[MAX_PATH]; // should be big enough TCHAR szName[80]; // The name better not be any bigger. DWORD dwError; WNetGetLastError(&dwError, szErrorMsg, ARRAYSIZE(szErrorMsg), szName, ARRAYSIZE(szName)); MLShellMessageBox(NULL, MAKEINTRESOURCE(IDS_NETERROR), MAKEINTRESOURCE(IDS_DISCONNECTERROR), MB_ICONHAND | MB_OK, dwError, szName, szErrorMsg); } // FEATURE: deal with error, perhaps open a window on this drive return ret; } CShellBrowser2::CShellBrowser2() : #ifdef NO_MARSHALLING _fDelayedClose(FALSE), _fOnIEThread(TRUE), #endif _fStatusBar(TRUE), _fShowMenu(TRUE), _fValidComCatCache(FALSE), _fShowSynchronize(TRUE), _iSynchronizePos(-1), CSBSUPERCLASS(NULL) { // warning: can't call SUPERCLASS until _Initialize has been called // (since that's what does the aggregation) ASSERT(IsEqualCLSID(_clsidThis, CLSID_NULL)); ASSERT(_hwndDummyTB == NULL); } #pragma warning(default:4355) // using 'this' in constructor HRESULT CShellBrowser2::_Initialize(HWND hwnd, IUnknown *pauto) { HRESULT hr; SHELLSTATE ss = {0}; hr = SUPERCLASS::_Initialize(hwnd, pauto); if (SUCCEEDED(hr)) { SetTopBrowser(); int i = _AllocToolbarItem(); ASSERT(i == ITB_ITBAR); _GetToolbarItem(ITB_ITBAR)->fShow = TRUE; _put_itbLastFocus(ITB_VIEW); InitializeDownloadManager(); _nTBTextRows = -1; SHGetSetSettings(&ss, SSF_MAPNETDRVBUTTON, FALSE); _fShowNetworkButtons = ss.fMapNetDrvBtn; // Initialize the base class transition site pointer. InitializeTransitionSite(); // Invalidate icon cache in case non-IE browser took over .htm icons. IEInvalidateImageList(); _UpdateRegFlags(); _nMBIgnoreNextDeselect = RegisterWindowMessage(TEXT("CMBIgnoreNextDeselect")); _fShowFortezza = FALSE; _hfm = NULL; } return hr; } HRESULT CShellBrowser2_CreateInstance(HWND hwnd, void **ppsb) { CShellBrowser2 *psb = new CShellBrowser2(); if (psb) { HRESULT hr = psb->_Initialize(hwnd, NULL); // aggregation, etc. if (FAILED(hr)) { ASSERT(0); // shouldn't happen ATOMICRELEASE(psb); } *ppsb = (void *)psb; return hr; } return E_OUTOFMEMORY; } CShellBrowser2::~CShellBrowser2() { _TheaterMode(FALSE, FALSE); if (IsWindow(_hwndDummyTB)) DestroyWindow(_hwndDummyTB); // If automation was enabled, kill it now ATOMICRELEASE(_pbsmInfo); ATOMICRELEASE(_poctNsc); ATOMICRELEASE(_pcmNsc); ATOMICRELEASE(_pism); ATOMICRELEASE(_pizm); ATOMICRELEASE(_pcmSearch); ASSERT(0 == _punkMsgLoop); ILFree(_pidlLastHist); if (_hmenuPreMerged) DestroyMenu(_hmenuPreMerged); if (_hmenuTemplate) DestroyMenu(_hmenuTemplate); if (_hmenuFull) DestroyMenu(_hmenuFull); if (_hfm) DestroyMenu(_hfm); if (_lpPendingButtons) LocalFree(_lpPendingButtons); if (_lpButtons) LocalFree(_lpButtons); if (_hZoneIcon) DestroyIcon(_hZoneIcon); Str_SetPtr(&_pszSynchronizeText, NULL); if (_hEventComCat) CloseHandle(_hEventComCat); TraceMsg(TF_SHDLIFE, "dtor CShellBrowser2 %x", this); } void CShellBrowser2::v_FillCabStateHeader(CABSH* pcabsh, FOLDERSETTINGS* pfs) { WINDOWPLACEMENT wp; OLECMD rgCmds[3] = {0}; LPTOOLBARITEM ptbi = _GetToolbarItem(ITB_ITBAR); if (ptbi) { rgCmds[0].cmdID = CITIDM_VIEWTOOLS; rgCmds[1].cmdID = CITIDM_VIEWADDRESS; rgCmds[2].cmdID = CITIDM_VIEWLINKS; IUnknown_QueryStatus(ptbi->ptbar, &CGID_PrivCITCommands, ARRAYSIZE(rgCmds), rgCmds, NULL); } pcabsh->wv.bStdButtons = BOOLIFY(rgCmds[0].cmdf); pcabsh->wv.bAddress = BOOLIFY(rgCmds[1].cmdf); pcabsh->wv.bLinks = BOOLIFY(rgCmds[2].cmdf); pcabsh->wv.bStatusBar = _fStatusBar; wp.length = sizeof(WINDOWPLACEMENT); GetWindowPlacement(_pbbd->_hwnd, &wp); pcabsh->dwHotkey = (UINT)SendMessage(_pbbd->_hwnd, WM_GETHOTKEY, 0, 0); // // Now Lets convert all of this common stuff into a // non 16/32 bit dependant data structure, such that both // can us it. // pcabsh->dwSize = sizeof(*pcabsh); pcabsh->flags = wp.flags; // 99/05/26 #345915 vtan: Don't mess with this. It's BY DESIGN. // #169839 caused #345915. When a window is minimized and closed // it should NEVER be opened minimized. The code that was here // has now caused a one month period where persistence of window // placement can be with SW_SHOWMINIMIZED which will cause the // window to restore minimized. This will go away when the window // is next closed. if ((wp.showCmd == SW_SHOWMINIMIZED) || (wp.showCmd == SW_MINIMIZE)) pcabsh->showCmd = SW_SHOWNORMAL; else pcabsh->showCmd = wp.showCmd; pcabsh->ptMinPosition.x = wp.ptMinPosition.x; pcabsh->ptMinPosition.y = wp.ptMinPosition.y; pcabsh->ptMaxPosition.x = wp.ptMaxPosition.x; pcabsh->ptMaxPosition.y = wp.ptMaxPosition.y; pcabsh->rcNormalPosition = *((RECTL*)&wp.rcNormalPosition); // Now the folder settings pcabsh->ViewMode = pfs->ViewMode; // NB Don't ever preserve the best-fit flag or the nosubfolders flag. pcabsh->fFlags = pfs->fFlags & ~FWF_NOSUBFOLDERS & ~FWF_BESTFITWINDOW; pcabsh->fMask = CABSHM_VERSION; pcabsh->dwVersionId = CABSH_VER; } BOOL CShellBrowser2::_GetVID(SHELLVIEWID *pvid) { BOOL bGotVID = FALSE; if (_pbbd->_psv && pvid) { IShellView2 *psv2; if (SUCCEEDED(_pbbd->_psv->QueryInterface(IID_PPV_ARG(IShellView2, &psv2)))) { if (S_OK == psv2->GetView(pvid, SV2GV_CURRENTVIEW)) { bGotVID = TRUE; } psv2->Release(); } } return bGotVID; } HRESULT CShellBrowser2::SetAsDefFolderSettings() { HRESULT hres; if (_pbbd->_psv) { SHELLVIEWID vid; BOOL bGotVID = _GetVID(&vid); FOLDERSETTINGS fs; _pbbd->_psv->GetCurrentInfo(&fs); CABINETSTATE cs; GetCabState(&cs); if (cs.fNewWindowMode) g_dfs.bDefToolBarMulti = FALSE; else g_dfs.bDefToolBarSingle = FALSE; g_dfs.fFlags = fs.fFlags & (FWF_AUTOARRANGE); // choose the ones we case about g_dfs.uDefViewMode = fs.ViewMode; g_dfs.bDefStatusBar = _fStatusBar; g_dfs.bUseVID = bGotVID; if (bGotVID) { g_dfs.vid = vid; } else { ViewIDFromViewMode(g_dfs.uDefViewMode, &g_dfs.vid); } g_dfs.dwViewPriority = VIEW_PRIORITY_USEASDEFAULT; SaveDefaultFolderSettings(GFSS_SETASDEFAULT); // 99/02/10 #226140 vtan: Get DefView to set default view IUnknown_Exec(_pbbd->_psv, &CGID_DefView, DVID_SETASDEFAULT, OLECMDEXECOPT_DODEFAULT, NULL, NULL); hres = S_OK; } else { hres = E_FAIL; } return hres; } //--------------------------------------------------------------------------- // Closing a cabinet window. // // save it's local view info in the directory it is looking at // // NOTE: this will fail on read only media like net or cdrom // // REVIEW: we may not want to save this info on removable media // (but if we don't allow a switch to force this!) // void CShellBrowser2::_SaveState() { CABINETSTATE cs; GetCabState(&cs); // Don't save any state info if restrictions are in place. // We are trying to give a way for automation scripts to run that do not // update the view state. To handle this we say if the window is not visible // (the script can set or unset visibility) than do not save the state (unless // falways add...) // Notwithstanding the above comments, suppress updating view state if UI // was set by automation if (_fUISetByAutomation || !cs.fSaveLocalView || SHRestricted(REST_NOSAVESET) || !IsWindowVisible(_pbbd->_hwnd) || _ptheater) return; if (_pbbd->_psv) { // Only save state if we close the browser in the same mode (either IE or Explorer) // that we started in. if (BOOLIFY(_IsPageInternet(_GetPidl())) == BOOLIFY(_fInternetStart)) { if (IsOS(OS_WHISTLERORGREATER)) { _PropertyBagSaveState(); } else { _OldSaveState(); } } } } void CShellBrowser2::_PropertyBagSaveState() { FOLDERSETTINGS fs; _pbbd->_psv->GetCurrentInfo(&fs); CABSH cabsh; v_FillCabStateHeader(&cabsh, &fs); IPropertyBag* ppb; if (SUCCEEDED(GetPropertyBag(SHGVSPB_FOLDER, IID_PPV_ARG(IPropertyBag, &ppb)))) { SHPropertyBag_WritePOINTLScreenRes(ppb, VS_PROPSTR_MINPOS, &cabsh.ptMinPosition); SHPropertyBag_WritePOINTLScreenRes(ppb, VS_PROPSTR_MAXPOS, &cabsh.ptMaxPosition); SHPropertyBag_WriteRECTLScreenRes(ppb, VS_PROPSTR_POS, &cabsh.rcNormalPosition); SHPropertyBag_WriteDWORD(ppb, VS_PROPSTR_REV, _dwRevCount); SHPropertyBag_WriteDWORD(ppb, VS_PROPSTR_WPFLAGS, cabsh.flags); SHPropertyBag_WriteDWORD(ppb, VS_PROPSTR_SHOW, cabsh.showCmd); SHPropertyBag_WriteDWORD(ppb, VS_PROPSTR_FFLAGS, cabsh.fFlags); SHPropertyBag_WriteDWORD(ppb, VS_PROPSTR_HOTKEY, cabsh.dwHotkey); SHPropertyBag_WriteBOOL(ppb, VS_PROPSTR_BUTTONS, cabsh.wv.bStdButtons); SHPropertyBag_WriteBOOL(ppb, VS_PROPSTR_STATUS, cabsh.wv.bStatusBar); SHPropertyBag_WriteBOOL(ppb, VS_PROPSTR_LINKS, cabsh.wv.bLinks); SHPropertyBag_WriteBOOL(ppb, VS_PROPSTR_ADDRESS, cabsh.wv.bAddress); SHELLVIEWID vid; if (_GetVID(&vid)) { SHPropertyBag_WriteGUID(ppb, VS_PROPSTR_VID, &vid); } else { SHPropertyBag_Delete(ppb, VS_PROPSTR_VID); } ppb->Release(); } } void CShellBrowser2::_OldSaveState() { WINDOWPLACEMENT currentWindowPlacement; WINVIEW winView; currentWindowPlacement.length = 0; // if these keys are down, save the current states if (IsCShellBrowser2() && GetAsyncKeyState(VK_CONTROL) < 0) { SetAsDefFolderSettings(); } // Now get the view information FOLDERSETTINGS fs; _pbbd->_psv->GetCurrentInfo(&fs); IStream* pstm = NULL; // 99/05/07 #291358 vtan: Temporary solution to a problem dating back to IE4 days. // Here's where the window frame state if saved. This also saves the FOLDERSETTINGS // view information. Ideally it's best to separate the two but it seems reasonable // to only save frame state if this is the initial navigation. Once navigated away // only save view information and preserve the current frame state by reading what's // there and copying it. If there's no frame state then use what the current frame // state is. It could be possible to write out an empty frame state but if this // state is roamed to a down-level platform it may cause unexpected results. if (_fSBWSaved) { IStream *pIStream; CABSH cabinetStateHeader; pIStream = v_GetViewStream(_pbbd->_pidlCur, STGM_READ, L"CabView"); if (pIStream != NULL) { if (SUCCEEDED(_FillCabinetStateHeader(pIStream, &cabinetStateHeader))) { // If an old frame state exists then save it and mark it as valid. currentWindowPlacement.length = sizeof(currentWindowPlacement); currentWindowPlacement.flags = cabinetStateHeader.flags; currentWindowPlacement.showCmd = cabinetStateHeader.showCmd; currentWindowPlacement.ptMinPosition = *(reinterpret_cast(&cabinetStateHeader.ptMinPosition)); currentWindowPlacement.ptMaxPosition = *(reinterpret_cast(&cabinetStateHeader.ptMaxPosition)); currentWindowPlacement.rcNormalPosition = *(reinterpret_cast(&cabinetStateHeader.rcNormalPosition)); winView = cabinetStateHeader.wv; } pIStream->Release(); } } if (!(_fSBWSaved && _fWin95ViewState)) { pstm = v_GetViewStream(_pbbd->_pidlCur, STGM_CREATE | STGM_WRITE, L"CabView"); _fSBWSaved = TRUE; } if (pstm) { CABSH cabsh; SHELLVIEWID vid; BOOL bGotVID = _GetVID(&vid); v_FillCabStateHeader(&cabsh, &fs); if (currentWindowPlacement.length == sizeof(currentWindowPlacement)) { // If an old frame state exists then put it back over the current frame state. cabsh.flags = currentWindowPlacement.flags; cabsh.showCmd = currentWindowPlacement.showCmd; cabsh.ptMinPosition = *(reinterpret_cast(¤tWindowPlacement.ptMinPosition)); cabsh.ptMaxPosition = *(reinterpret_cast(¤tWindowPlacement.ptMaxPosition)); cabsh.rcNormalPosition = *(reinterpret_cast(¤tWindowPlacement.rcNormalPosition)); cabsh.wv = winView; } if (bGotVID) { cabsh.vid = vid; cabsh.fMask |= CABSHM_VIEWID; } cabsh.fMask |= CABSHM_REVCOUNT; cabsh.dwRevCount = _dwRevCount; // save out the rev count of when we were opened // // First output the common non view specific information // pstm->Write(&cabsh, sizeof(cabsh), NULL); // And release it, which will commit it to disk.. pstm->Release(); // NOTE (toddb): The DefView view state is saved by the base class so we don't need // to explicitly save it here. If you do it gets called twice which is wasted time. // Do not call _pbbd->_psv->SaveViewState(); from this function. } #ifdef DEBUG if (g_dwPrototype & 0x00000010) { // // Save toolbars // pstm = v_GetViewStream(_pbbd->_pidlCur, STGM_CREATE | STGM_WRITE, L"Toolbars"); if (pstm) { _SaveToolbars(pstm); pstm->Release(); } } #endif } STDAPI_(LPITEMIDLIST) IEGetInternetRootID(void); IStream *CShellBrowser2::v_GetViewStream(LPCITEMIDLIST pidl, DWORD grfMode, LPCWSTR pwszName) { IStream *pstm = NULL; LPITEMIDLIST pidlToFree = NULL; BOOL bCabView = (0 == StrCmpIW(pwszName, L"CabView")); if (((NULL == pidl) && IsEqualCLSID(_clsidThis, CLSID_InternetExplorer)) || IsBrowserFrameOptionsPidlSet(pidl, BFO_BROWSER_PERSIST_SETTINGS)) { // If this is a child of the URL or we're looking at an unititialized IE frame, // then save all in the IE stream pidlToFree = IEGetInternetRootID(); pidl = pidlToFree; } else if (bCabView && _fNilViewStream) { // if we loaded cabview settings from the 'unknown pidl' view stream, // we've got to stick with it, whether or not we now have a pidl. pidl = NULL; } if (pidl) { pstm = SHGetViewStream(pidl, grfMode, pwszName, REGSTR_KEY_STREAMMRU, REGVALUE_STREAMS); } else if (bCabView) { // So we don't have a pidl for which to grab a stream, so we'll just // make up a stream to cover the situation. A hack no doubt, but before we // were handling this case by always loading from the IE stream. (doh!) // Actually, the whole thing is busted because we're // creating the window (and trying to restore the windowpos) as part of // CoCreateInstance(), before the client can navigate the browser. pstm = OpenRegStream(HKEY_CURRENT_USER, REGSTR_PATH_EXPLORER TEXT("\\Streams\\"), TEXT("CabView"), grfMode); _fNilViewStream = TRUE; // cabview settings initialized from the 'unknown pidl' view stream. } ILFree(pidlToFree); return pstm; } HRESULT CShellBrowser2::_FillCabinetStateHeader (IStream *pIStream, CABSH *cabsh) { HRESULT hResult; // Now read in the state from the stream file. // read the old header first. hResult = IStream_Read(pIStream, cabsh, sizeof(CABSHOLD)); // Sanity test to make the structure is sane if (FAILED(hResult) || (cabsh->dwSize < sizeof(CABSHOLD))) hResult = E_OUTOFMEMORY; // bogus but good enough // Read the remainder of the structure if we can. If not, then // set the mask equal to zero so we don't get confused later. if (cabsh->dwSize < sizeof(CABSH) || FAILED(IStream_Read(pIStream, ((LPBYTE)cabsh) + sizeof(CABSHOLD), sizeof(CABSH) - sizeof(CABSHOLD)))) { cabsh->fMask = 0; } return(hResult); } BOOL CShellBrowser2::_ReadSettingsFromPropertyBag(IPropertyBag* ppb, IETHREADPARAM *piei) { BOOL fRet; CABSH cabsh = {0}; cabsh.dwSize = sizeof(cabsh); cabsh.fMask = CABSHM_VERSION; cabsh.dwVersionId = CABSH_VER; if (SUCCEEDED(SHPropertyBag_ReadDWORD(ppb, VS_PROPSTR_WPFLAGS, &cabsh.flags))) { if (FAILED(SHPropertyBag_ReadPOINTLScreenRes(ppb, VS_PROPSTR_MINPOS, &cabsh.ptMinPosition))) { cabsh.ptMinPosition.x = cabsh.ptMinPosition.y = -1; } if (FAILED(SHPropertyBag_ReadPOINTLScreenRes(ppb, VS_PROPSTR_MAXPOS, &cabsh.ptMaxPosition))) { cabsh.ptMaxPosition.x = cabsh.ptMaxPosition.y = -1; } if (FAILED(SHPropertyBag_ReadRECTLScreenRes(ppb, VS_PROPSTR_POS, &cabsh.rcNormalPosition))) { cabsh.rcNormalPosition.left = cabsh.rcNormalPosition.top = cabsh.rcNormalPosition.right = cabsh.rcNormalPosition.bottom = CW_USEDEFAULT; } SHPropertyBag_ReadDWORDDef(ppb, VS_PROPSTR_MODE, &cabsh.ViewMode, FVM_TILE); SHPropertyBag_ReadDWORDDef(ppb, VS_PROPSTR_SHOW, &cabsh.showCmd, 0); SHPropertyBag_ReadDWORDDef(ppb, VS_PROPSTR_FFLAGS, &cabsh.fFlags, FWF_BESTFITWINDOW | g_dfs.fFlags); SHPropertyBag_ReadDWORDDef(ppb, VS_PROPSTR_HOTKEY, &cabsh.dwHotkey, 0); cabsh.wv.bStdButtons = SHPropertyBag_ReadBOOLDefRet(ppb, VS_PROPSTR_BUTTONS, TRUE); cabsh.wv.bStatusBar = SHPropertyBag_ReadBOOLDefRet(ppb, VS_PROPSTR_STATUS, TRUE); cabsh.wv.bLinks = SHPropertyBag_ReadBOOLDefRet(ppb, VS_PROPSTR_LINKS, TRUE); cabsh.wv.bAddress = SHPropertyBag_ReadBOOLDefRet(ppb, VS_PROPSTR_ADDRESS, TRUE); cabsh.fMask |= CABSHM_REVCOUNT; SHPropertyBag_ReadDWORDDef(ppb, VS_PROPSTR_REV, &cabsh.dwRevCount, g_dfs.dwDefRevCount); if (SUCCEEDED(SHPropertyBag_ReadGUID(ppb, VS_PROPSTR_VID, &cabsh.vid))) { cabsh.fMask |= CABSHM_VIEWID; } fRet = _FillIEThreadParamFromCabsh(&cabsh, piei); } else { fRet = FALSE; } return fRet; } BOOL CShellBrowser2::_FillIEThreadParamFromCabsh(CABSH* pcabsh, IETHREADPARAM *piei) { BOOL fUpgradeToWebView = FALSE; bool bInvalidWindowPlacement; // Now extract the data and put it into appropriate structures // first the window placement info piei->wp.length = sizeof(piei->wp); piei->wp.flags = (UINT)pcabsh->flags; piei->wp.showCmd = (UINT)pcabsh->showCmd; ASSERT(sizeof(piei->wp.ptMinPosition) == sizeof(pcabsh->ptMinPosition)); piei->wp.ptMinPosition = *((LPPOINT)&pcabsh->ptMinPosition); piei->wp.ptMaxPosition = *((LPPOINT)&pcabsh->ptMaxPosition); ASSERT(sizeof(piei->wp.rcNormalPosition) == sizeof(pcabsh->rcNormalPosition)); piei->wp.rcNormalPosition = *((RECT*)&pcabsh->rcNormalPosition); // Do some simple sanity checks to make sure that the returned // information appears to be reasonable and not random garbage // We want the Show command to be normal or minimize or maximize. // Only need one test as they are consectutive and start at zero // DON'T try to validate too much of the WINDOWPLACEMENT-- // SetWindowPlacement does a much better job, especially in // multiple-monitor scenarios... // 99/03/09 #303300 vtan: Sanity check for zero/negative width or // height. SetWindowPlacement doesn't sanity check for this - // only for whether the rectangle left and top are in the visible // screen area. If this condition is detected then reset to default // and force DefView to best fit the window. { LONG lWidth, lHeight; lWidth = piei->wp.rcNormalPosition.right - piei->wp.rcNormalPosition.left; lHeight = piei->wp.rcNormalPosition.bottom - piei->wp.rcNormalPosition.top; bInvalidWindowPlacement = ((lWidth <= 0) || (lHeight <= 0)); if (bInvalidWindowPlacement) piei->wp.length = 0; } if (piei->wp.showCmd > SW_MAX) return FALSE; piei->fs.ViewMode = (UINT)pcabsh->ViewMode; piei->fs.fFlags = (UINT)pcabsh->fFlags; if (pcabsh->fMask & CABSHM_VIEWID) { // There was code here to revert to large icon mode if fWin95Classic // mode was turned on. This is completely busted because fWin95Classic // just affects the DEFAULT view, not any PERSISTED view. piei->m_vidRestore = pcabsh->vid; piei->m_dwViewPriority = VIEW_PRIORITY_CACHEHIT; // we have a cache hit! } // If there was a revcount, check if we've been overridden by // a subsequent "use these settings as the default for all future // windows". if (pcabsh->fMask & CABSHM_REVCOUNT) { if (g_dfs.dwDefRevCount != pcabsh->dwRevCount) { if (g_dfs.bUseVID) { piei->m_vidRestore = g_dfs.vid; } else { ViewIDFromViewMode(g_dfs.uDefViewMode, &(piei->m_vidRestore)); } piei->fs.ViewMode = g_dfs.uDefViewMode; piei->fs.fFlags = g_dfs.fFlags; piei->m_dwViewPriority = g_dfs.dwViewPriority; } } _dwRevCount = g_dfs.dwDefRevCount; // save this with the browser so we can save it out later if (!(pcabsh->fMask & CABSHM_VERSION) || (pcabsh->dwVersionId < CABSH_VER)) { SHELLSTATE ss = {0}; // old version of stream.... SHGetSetSettings(&ss, SSF_WIN95CLASSIC, FALSE); // we have either a cache miss (or an older dwVersionId), or we are restricting to win95 mode, // so set the priority accordingly. piei->m_dwViewPriority = ss.fWin95Classic ? VIEW_PRIORITY_RESTRICTED : VIEW_PRIORITY_CACHEMISS; if (ss.fWin95Classic) { // Hey, it's a Win95 CABSH structure and we're in Win95 mode, // so don't change the defaults! ViewIDFromViewMode(pcabsh->ViewMode, &(piei->m_vidRestore)); } else { // Upgrade scenario: // My Computer in List should wind up in Web View/List // C:\ in List should wind up in List // If this fails (C:\ winds up in Large Icon), we can try // to comment out this code altogether. Hopefully defview's // default view stuff will realize Web View should be // selected and My Computer will go to Web View instead // of staying in List. // piei->m_vidRestore = DFS_VID_Default; // Note: if we upgrade to web view, we better let the // view recalc window space or the window will be TOO SMALL fUpgradeToWebView = TRUE; } if (pcabsh->wv.bStdButtons) // win95 called this bToolbar { // Win95 called bStdButtons bToolbar. IE4 separates this // into bAddress and bStdButtons. Set bAddress for upgrade. pcabsh->wv.bAddress = TRUE; #define RECT_YADJUST 18 // bump up the rect slightly to account for new toolbar size.... // 18 is an approximately random number which assumes that the default // configuration is a single height toolbar which is approx twice as high as the // old toobar.... // // NOTE: old browser streams are always for the primary monitor, so we just // check to see if we are going to fit on the screen. If not, then don't bother. // // NOTE: when we rev the version number, we'll want to do this // rect adjustment for the CABSH_WIN95_VER version... // int iMaxYSize = GetSystemMetrics(SM_CYFULLSCREEN); if (piei->wp.rcNormalPosition.bottom + piei->wp.rcNormalPosition.top + RECT_YADJUST < iMaxYSize) { piei->wp.rcNormalPosition.bottom += RECT_YADJUST; } #undef RECT_YADJUST } } // After all that upgrade work, check the classic shell restriction if (SHRestricted(REST_CLASSICSHELL)) { // It doesn't matter what vid was specified, use the ViewMode ViewIDFromViewMode(pcabsh->ViewMode, &(piei->m_vidRestore)); piei->m_dwViewPriority = VIEW_PRIORITY_RESTRICTED; // use highest priority because of the restriction. // Oops, we can't upgrade... fUpgradeToWebView = FALSE; } // And the Hotkey piei->wHotkey = (UINT)pcabsh->dwHotkey; piei->wv = pcabsh->wv; // if we upgraded to web view, then any persisted window sizes will // probably be too small -- let them get resized by the view... if (fUpgradeToWebView || bInvalidWindowPlacement) piei->fs.fFlags |= FWF_BESTFITWINDOW; else piei->fs.fFlags &= ~FWF_BESTFITWINDOW; return TRUE; } BOOL CShellBrowser2::_ReadSettingsFromStream(IStream *pstm, IETHREADPARAM *piei) { BOOL fRet; CABSH cabsh; if (SUCCEEDED(_FillCabinetStateHeader(pstm, &cabsh))) { fRet = _FillIEThreadParamFromCabsh(&cabsh, piei); } else { fRet = FALSE; } return fRet; } void CShellBrowser2::_FillIEThreadParam(LPCITEMIDLIST pidl, IETHREADPARAM *piei) { BOOL fSettingsLoaded = FALSE; if (0 == GetSystemMetrics(SM_CLEANBOOT)) { if (IsOS(OS_WHISTLERORGREATER)) { IPropertyBag* ppb; if (SUCCEEDED(_GetPropertyBag(pidl, SHGVSPB_FOLDER, IID_PPV_ARG(IPropertyBag, &ppb)))) { fSettingsLoaded = _ReadSettingsFromPropertyBag(ppb, piei); ppb->Release(); } } else { IStream* pstm = v_GetViewStream(pidl, STGM_READ, L"CabView"); if (pstm) { fSettingsLoaded = _ReadSettingsFromStream(pstm, piei); pstm->Release(); } } } if (!fSettingsLoaded) v_GetDefaultSettings(piei); } void CShellBrowser2::_UpdateFolderSettings(LPCITEMIDLIST pidl) { if (!_fWin95ViewState) { IETHREADPARAM iei = { 0 }; _FillIEThreadParam(pidl, &iei); _fsd._vidRestore = iei.m_vidRestore; _fsd._dwViewPriority = iei.m_dwViewPriority; _fsd._fs = iei.fs; } else if (_pbbd->_psv) { IShellView2 *pISV2; // 99/04/16 #323726 vtan: Make sure that both the FOLDERSETTINGS (in _fsd._fs) // and the VID (in _fsd.vidRestore) is set up properly for shdocvw to make a // decision. This fixes Win95 browse in single window mode inheriting the view // from the source of navigation. _pbbd->_psv->GetCurrentInfo(&_fsd._fs); if (SUCCEEDED(_pbbd->_psv->QueryInterface(IID_PPV_ARG(IShellView2, &pISV2)))) { if (SUCCEEDED(pISV2->GetView(&_fsd._vidRestore, SV2GV_CURRENTVIEW))) _fsd._dwViewPriority = VIEW_PRIORITY_INHERIT; else _fsd._dwViewPriority = VIEW_PRIORITY_DESPERATE; pISV2->Release(); } } } void CShellBrowser2::_LoadBrowserWindowSettings(IETHREADPARAM *piei, LPCITEMIDLIST pidl) { _FillIEThreadParam(pidl, piei); //Copy the two restore settings from piei to ShellBrowser. _fsd._vidRestore = piei->m_vidRestore; _fsd._dwViewPriority = piei->m_dwViewPriority; _fsd._fs = piei->fs; // Now that the ITBar has the menu on it, it must always be shown. We turn // on/off bands individually now... LPTOOLBARITEM ptbi = _GetToolbarItem(ITB_ITBAR); ptbi->fShow = TRUE; _fStatusBar = piei->wv.bStatusBar; // never allow VK_MENU to be our hot key if (piei->wHotkey != VK_MENU) SendMessage(_pbbd->_hwnd, WM_SETHOTKEY, piei->wHotkey, 0); #ifdef DEBUG if (g_dwPrototype & 0x00000010) { // // Load toolbars // IStream* pstm = v_GetViewStream(pidl, STGM_READ, L"Toolbars"); if (pstm) { _LoadToolbars(pstm); pstm->Release(); } } #endif } void CShellBrowser2::_UpdateChildWindowSize(void) { if (!_fKioskMode) { if (_hwndStatus && _fStatusBar) { SendMessage(_hwndStatus, WM_SIZE, 0, 0L); } } } /*---------------------------------------------------------- Purpose: Helper function to do ShowDW on the internet toolbar. We can show all the bands in the toolbar, but we must never accidentally hide the menuband. CShellBrowser2 should call this function rather than IDockingWindow::ShowDW directly if there is any chance fShow would be FALSE. */ void ITBar_ShowDW(IDockingWindow * pdw, BOOL fTools, BOOL fAddress, BOOL fLinks) { IUnknown_Exec(pdw, &CGID_PrivCITCommands, CITIDM_SHOWTOOLS, fTools, NULL, NULL); IUnknown_Exec(pdw, &CGID_PrivCITCommands, CITIDM_SHOWADDRESS, fAddress, NULL, NULL); IUnknown_Exec(pdw, &CGID_PrivCITCommands, CITIDM_SHOWLINKS, fLinks, NULL, NULL); } void CShellBrowser2::_HideToolbar(LPUNKNOWN punk) { for (UINT itb=0; itb < (UINT)_GetToolbarCount(); itb++) { LPTOOLBARITEM ptbi = _GetToolbarItem(itb); if (ptbi->ptbar && SHIsSameObject(ptbi->ptbar, punk)) { if (ITB_ITBAR == itb) ITBar_ShowDW(ptbi->ptbar, FALSE, FALSE, FALSE); else ptbi->ptbar->ShowDW(FALSE); } } } HRESULT CShellBrowser2::v_ShowHideChildWindows(BOOL fChildOnly) { // (scotth): _hwndStatus is bogus when closing a window if (_hwndStatus && IS_VALID_HANDLE(_hwndStatus, WND)) ShowWindow(_hwndStatus, (!_fKioskMode && _fStatusBar) ? SW_SHOW : SW_HIDE); Exec(NULL, OLECMDID_UPDATECOMMANDS, 0, NULL, NULL); _UpdateChildWindowSize(); SUPERCLASS::v_ShowHideChildWindows(fChildOnly); // We should call _UpdateBackForwardState after the parent show/hide // toolbars. UpdateBackForwardState(); return S_OK; } #define MAX_BROWSER_WINDOW_TEMPLATE (MAX_BROWSER_WINDOW_TITLE - 20) void CShellBrowser2::v_GetAppTitleTemplate(LPTSTR pszBuffer, size_t cchBuffer, LPTSTR pszTitle) { if (_fAppendIEToCaptionBar) { TCHAR szBuffer[MAX_BROWSER_WINDOW_TEMPLATE]; _GetAppTitle(szBuffer, ARRAYSIZE(szBuffer)); StringCchPrintf(pszBuffer, cchBuffer, TEXT("%%s - %s"), szBuffer); } else { // don't tack on "intenet explorer" if we didn't start there StringCchCopy(pszBuffer, cchBuffer, TEXT("%s")); } } /*---------------------------------------------------------- Purpose: Intercept messages for menuband. Menuband messages must be intercepted at two points: 1) the main message pump (IsMenuMessage method) 2) the wndproc of a window that has a menuband (TranslateMenuMessage method) The reason is sometimes a message will be received by the wndproc which did not pass thru the apps main message pump, but must be dealt with. There are other messages which must be handled in the main message pump, before TranslateMessage or DispatchMessage. Returns: TRUE if the message was handled */ HRESULT CShellBrowser2::v_MayTranslateAccelerator(MSG* pmsg) { HRESULT hres = S_FALSE; // (scotth): for some unknown reason (aka ActiveX init), we are // receiving a null hwnd with WM_DESTROY when the user scrolls a page // that causes the ticker control to appear. Check the pmsg->hwnd here // so we don't mistake a rogue WM_DESTROY msg for the real thing. IMenuBand* pmb = _GetMenuBand(_pbbd->_hwnd == pmsg->hwnd && WM_DESTROY == pmsg->message); if (pmb && _fActivated) { hres = pmb->IsMenuMessage(pmsg); // don't need to release pmb } if (hres != S_OK) { // REARCHITECT cleanup -- move menuband stuff & this check to v_MayTranslateAccelerator's caller if (WM_KEYFIRST <= pmsg->message && pmsg->message <= WM_KEYLAST) { hres = SUPERCLASS::v_MayTranslateAccelerator(pmsg); if (hres != S_OK) { // // Our SUPERCLASS didn't handle it. // if (_ShouldTranslateAccelerator(pmsg)) { // // Okay, it's one of ours. Let the toolbars have a crack at // translating it. // for (UINT itb=0; (itb < (UINT)_GetToolbarCount()) && (hres != S_OK); itb++) { LPTOOLBARITEM ptbi = _GetToolbarItem(itb); if (ptbi->fShow && (NULL != ptbi->ptbar)) { IUnknown *pUnk; if (SUCCEEDED(IUnknown_GetClientDB(ptbi->ptbar, &pUnk))) { ASSERT(NULL != pUnk); hres = IUnknown_TranslateAcceleratorIO(pUnk, pmsg); pUnk->Release(); } } } } } } } return hres; } /*---------------------------------------------------------- Purpose: Take a whack at translating any messages. CShellBrowser2 uses this to translate messages needed for menu bands. Returns: TRUE if we handled it */ BOOL CShellBrowser2::_TranslateMenuMessage(HWND hwnd, UINT uMsg, WPARAM * pwParam, LPARAM * plParam, LRESULT * plRet) { BOOL bRet = FALSE; IMenuBand* pmb = _GetMenuBand(WM_DESTROY == uMsg); if (pmb) { MSG msg; msg.hwnd = hwnd; msg.message = uMsg; msg.wParam = *pwParam; msg.lParam = *plParam; bRet = (S_OK == pmb->TranslateMenuMessage(&msg, plRet)); *pwParam = msg.wParam; *plParam = msg.lParam; // don't need to release pmb } return bRet; } static TCHAR g_szWorkingOffline[MAX_BROWSER_WINDOW_TEMPLATE]=TEXT(""); static TCHAR g_szWorkingOfflineTip[MAX_BROWSER_WINDOW_TEMPLATE]=TEXT(""); static TCHAR g_szAppName[MAX_BROWSER_WINDOW_TEMPLATE]=TEXT(""); void InitTitleStrings() { if (!g_szWorkingOffline[0]) { DWORD dwAppNameSize = sizeof(g_szAppName); // Load this stuff only once per process for perf. if (SHGetValue(HKEY_CURRENT_USER, REGSTR_PATH_MAIN, TEXT("Window Title"), NULL, g_szAppName, &dwAppNameSize) != ERROR_SUCCESS) MLLoadString(IDS_TITLE, g_szAppName, ARRAYSIZE(g_szAppName)); MLLoadString(IDS_WORKINGOFFLINETIP, g_szWorkingOfflineTip, ARRAYSIZE(g_szWorkingOfflineTip)); MLLoadString(IDS_WORKINGOFFLINE, g_szWorkingOffline, ARRAYSIZE(g_szWorkingOffline)); SHTruncateString(g_szWorkingOffline, ARRAYSIZE(g_szWorkingOffline) - (lstrlen(g_szAppName) + 4)); // give room for separator & EOL } } void CShellBrowser2::_ReloadTitle() { g_szWorkingOffline[0] = 0; _fTitleSet = FALSE; _SetTitle(NULL); } HICON OfflineIcon() { static HICON s_hiconOffline = NULL; if (!s_hiconOffline) { s_hiconOffline = (HICON)LoadImage(HinstShdocvw(), MAKEINTRESOURCE(IDI_OFFLINE), IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 0); } return s_hiconOffline; } void CShellBrowser2::_ReloadStatusbarIcon() { BOOL fIsOffline; VARIANTARG var = {0}; var.vt = VT_I4; if (_pbbd && SUCCEEDED(IUnknown_Exec(_pbbd->_psv, &CGID_Explorer, SBCMDID_GETPANE, PANE_OFFLINE, NULL, &var)) && (var.lVal != PANE_NONE)) { if (_pbbd->_pidlCur && IsBrowserFrameOptionsSet(_pbbd->_psf, BFO_USE_IE_OFFLINE_SUPPORT)) fIsOffline = SHIsGlobalOffline(); else fIsOffline = FALSE; SendControlMsg(FCW_STATUS, SB_SETICON, var.lVal, fIsOffline ? (LPARAM) OfflineIcon() : NULL, NULL); if (fIsOffline) { InitTitleStrings(); SendControlMsg(FCW_STATUS, SB_SETTIPTEXT, var.lVal, (LPARAM)g_szWorkingOfflineTip, NULL); } } } void CShellBrowser2::_GetAppTitle(LPTSTR pszBuffer, DWORD cchSize) { BOOL fOffline = SHIsGlobalOffline(); pszBuffer[0] = 0; InitTitleStrings(); if (fOffline) { StringCchPrintf(pszBuffer, cchSize, TEXT("%s - %s"), g_szAppName, g_szWorkingOffline); } else { #ifdef DEBUG #ifdef UNICODE #define DLLNAME TEXT("(BrowseUI UNI)") #else #define DLLNAME TEXT("(BrowseUI)") #endif StringCchPrintf(pszBuffer, cchSize, TEXT("%s - %s"), g_szAppName, DLLNAME); #else StringCchCopy(pszBuffer, cchSize, g_szAppName); #endif } } HWND CShellBrowser2::_GetCaptionWindow() { return _pbbd->_hwnd; } /*---------------------------------------------------------- Purpose: Gets the cached menu band. If the menu band hasn't been acquired yet, attempt to get it. If bDestroy is TRUE, the menu band will be released. This does not AddRef because an AddRef/Release for each message is not necessary -- as long as callers beware! */ IMenuBand* CShellBrowser2::_GetMenuBand(BOOL bDestroy) { // Don't bother to create it if we're about to go away. if (_fReceivedDestroy) { ASSERT(NULL == _pmb); } else if (bDestroy) { ATOMICRELEASE(_pmb); // Make it so we don't re-create the _pmb after the WM_DESTROY _fReceivedDestroy = TRUE; } // The menuband is created sometime after WM_CREATE is sent. Keep // trying to get the menuband interface until we get it. else if (!_pmb) { IBandSite *pbs; if (SUCCEEDED(IUnknown_QueryService(_GetITBar(), IID_IBandSite, IID_PPV_ARG(IBandSite, &pbs)))) { IDeskBand *pdbMenu; pbs->QueryBand(CBIDX_MENU, &pdbMenu, NULL, NULL, 0); if (pdbMenu) { pdbMenu->QueryInterface(IID_PPV_ARG(IMenuBand, &_pmb)); // Cache _pmb, so don't release it here pdbMenu->Release(); } pbs->Release(); } } return _pmb; } void CShellBrowser2::_SetMenu(HMENU hmenu) { // Create a top-level menuband given this hmenu. Add it to // the bandsite. if (!_pmb) { _GetMenuBand(FALSE); // this does not AddRef if (!_pmb) return; } IShellMenu* psm; if (SUCCEEDED(_pmb->QueryInterface(IID_PPV_ARG(IShellMenu, &psm)))) { HMENU hCurMenu = NULL; psm->GetMenu(&hCurMenu, NULL, NULL); // only call setmenu if we know it is not the menu we have currently or it is not one of our precached standards... if ((hmenu != hCurMenu) || (hmenu != _hmenuFull && hmenu != _hmenuTemplate && hmenu != _hmenuPreMerged)) { psm->SetMenu(hmenu, NULL, SMSET_DONTOWN | SMSET_MERGE); } psm->Release(); } } STDAPI SHFlushClipboard(void); HRESULT CShellBrowser2::OnDestroy() { SUPERCLASS::OnDestroy(); SHFlushClipboard(); if (_uFSNotify) SHChangeNotifyDeregister(_uFSNotify); if (_fAutomation) IECleanUpAutomationObject(); _DecrNetSessionCount(); return S_OK; } BOOL CShellBrowser2::_CreateToolbar() { return TRUE; } void CShellBrowser2::v_InitMembers() { _hmenuTemplate = _MenuTemplate(MENU_TEMPLATE, TRUE); _hmenuFull = _MenuTemplate(MENU_FULL, TRUE); _hmenuPreMerged = _MenuTemplate(MENU_PREMERGED, FALSE); if (_fRunningInIexploreExe) _hmenuCur = _hmenuPreMerged; else _hmenuCur = _hmenuTemplate; } // REVIEW UNDONE - Stuff in programs defaults to save positions ??? void CShellBrowser2::v_GetDefaultSettings(IETHREADPARAM *piei) { // set the flags // Best fit window means get the window to size according to the // contents of the view so that windows without existing settings // come up looking OK. piei->fs.fFlags = FWF_BESTFITWINDOW | g_dfs.fFlags; if (!_fRunningInIexploreExe) { piei->wv.bStatusBar = g_dfs.bDefStatusBar; } else { piei->wv.bStatusBar = TRUE; //status bar is on by default in IE. } CABINETSTATE cs; GetCabState(&cs); if (cs.fSimpleDefault && cs.fNewWindowMode) { piei->wv.bStdButtons = piei->wv.bAddress = g_dfs.bDefToolBarMulti; } else { piei->wv.bStdButtons = piei->wv.bAddress = g_dfs.bDefToolBarSingle; } // For Win95 classic view, ITBar should be hidden by default. SHELLSTATE ss = {0}; SHGetSetSettings(&ss, SSF_WIN95CLASSIC, FALSE); // SHGetSetSettings checks SHRestricted(REST_CLASSICSHELL) for us if (ss.fWin95Classic) { piei->fs.ViewMode = FVM_ICON; piei->m_vidRestore = VID_LargeIcons; piei->m_dwViewPriority = VIEW_PRIORITY_RESTRICTED; // use highest priority because of the restriction. } else { piei->fs.ViewMode = g_dfs.uDefViewMode; piei->m_vidRestore = g_dfs.vid; piei->m_dwViewPriority = g_dfs.dwViewPriority; } _dwRevCount = g_dfs.dwDefRevCount; // save this with the browser so we can save it out later ASSERT(piei->wp.length == 0); } void CShellBrowser2::_DecrNetSessionCount() { TraceMsg(DM_SESSIONCOUNT, "_DecrNetSessionCount"); if (_fVisitedNet) { SetQueryNetSessionCount(SESSION_DECREMENT); _fVisitedNet = FALSE; } } void CShellBrowser2::_IncrNetSessionCount() { TraceMsg(DM_SESSIONCOUNT, "_IncrNetSessionCount"); if (!_fVisitedNet) { BOOL fDontDoDefaultCheck = (BOOLIFY(_fAutomation) || (!(BOOLIFY(_fAddDialUpRef)))); if (!SetQueryNetSessionCount(fDontDoDefaultCheck ? SESSION_INCREMENT_NODEFAULTBROWSERCHECK : SESSION_INCREMENT)) { g_szWorkingOffline[0] = 0; #ifdef NO_MARSHALLING if (!_fOnIEThread) SetQueryNetSessionCount(fDontDoDefaultCheck ? SESSION_INCREMENT_NODEFAULTBROWSERCHECK : SESSION_INCREMENT); #endif } _fVisitedNet = TRUE; } } // Initialize the Internet Toolbar. Create a dummy class to trap all the Messages that // are sent to the old toolbar BOOL CShellBrowser2::_PrepareInternetToolbar(IETHREADPARAM* piei) { HRESULT hr = S_OK; if (!_GetITBar()) { DWORD dwServerType = CLSCTX_INPROC_SERVER; #ifdef FULL_DEBUG if (!(g_dwPrototype & PF_NOBROWSEUI)) /// this will cause us to use OLE's co-create intance and not short circuit it. dwServerType = CLSCTX_INPROC; #endif hr = CoCreateInstance(CLSID_InternetToolbar, NULL, dwServerType, IID_PPV_ARG(IDockingWindow, &_GetToolbarItem(ITB_ITBAR)->ptbar)); TraceMsg(DM_ITBAR|DM_STARTUP, "CSB::_PrepareInternetToolbar CoCreate(CLS_ITBAR) returned %x", hr); if (SUCCEEDED(hr)) { IUnknown_SetSite(_GetITBar(), SAFECAST(this, IShellBrowser*)); // Look at the type of folder using "pidlInitial" and // see if we have a stream for this type. // If so, open it and call IPersistStreamInit::Load(pstm); // else, call IPersistStreamInit::InitNew(void); IPersistStreamInit *pITbarPSI; //Get the pointer to if (SUCCEEDED(_GetITBar()->QueryInterface(IID_PPV_ARG(IPersistStreamInit, &pITbarPSI)))) { // The initial toolbar needs to be the Web toolbar IUnknown_Exec(pITbarPSI, &CGID_PrivCITCommands, CITIDM_ONINTERNET, (_fUseIEToolbar ? CITE_INTERNET : CITE_SHELL), NULL, NULL); IStream *pstm = _GetITBarStream(_fUseIEToolbar, STGM_READ); if (pstm) { //Stream exists. Let's load it from there. hr = pITbarPSI->Load(pstm); pstm->Release(); } else { //No stream already exists. Initialize from the old location! pITbarPSI->InitNew(); } pITbarPSI->Release(); } SUPERCLASS::v_ShowHideChildWindows(TRUE); if (!_hwndDummyTB) { _hwndDummyTB = SHCreateWorkerWindow(DummyTBWndProc, _pbbd->_hwnd, 0, WS_CHILD, (HMENU)9999, this); } } } if (SUCCEEDED(hr) && !_pxtb) hr = QueryService(SID_SExplorerToolbar, IID_PPV_ARG(IExplorerToolbar, &_pxtb)); return SUCCEEDED(hr); } BOOL LoadWindowPlacement(WINDOWPLACEMENT * pwndpl) { BOOL fRetVal = FALSE; if (pwndpl) { DWORD dwSize = sizeof(WINDOWPLACEMENT); if (SHGetValueGoodBoot(HKEY_CURRENT_USER, TEXT("Software\\Microsoft\\Internet Explorer\\Main"), TEXT("Window_Placement"), NULL, (PBYTE)pwndpl, &dwSize) == ERROR_SUCCESS) { fRetVal = TRUE; // Is the default value invalid? if ((pwndpl->rcNormalPosition.left >= pwndpl->rcNormalPosition.right) || (pwndpl->rcNormalPosition.top >= pwndpl->rcNormalPosition.bottom)) { // Yes, so fix it. We worry about the normal size being zero or negative. // This fixes the munged case. ASSERT(0); // the stream is corrupted. fRetVal = FALSE; } } } return fRetVal; } BOOL StoreWindowPlacement(WINDOWPLACEMENT *pwndpl) { if (pwndpl) { // Don't store us as minimized - that isn't what the user intended. // I.E. right click on minimized IE 3.0 in tray, pick close. Since // we are minmized in that scenario we want to force normal // instead so we at least show up. if (pwndpl->showCmd == SW_SHOWMINIMIZED || pwndpl->showCmd == SW_MINIMIZE) pwndpl->showCmd = SW_SHOWNORMAL; // Are about to save a corrupted window size? if ((pwndpl->rcNormalPosition.left >= pwndpl->rcNormalPosition.right) || (pwndpl->rcNormalPosition.top >= pwndpl->rcNormalPosition.bottom)) { // Yes, so fix it. ASSERT(0); // the size is invalid or corrupted. } else { return SHSetValue(HKEY_CURRENT_USER, TEXT("Software\\Microsoft\\Internet Explorer\\Main"), TEXT("Window_Placement"), REG_BINARY, (const BYTE *)pwndpl, sizeof(WINDOWPLACEMENT)) == ERROR_SUCCESS; } } return FALSE; } BOOL StorePlacementOfWindow(HWND hwnd) { WINDOWPLACEMENT wndpl; wndpl.length = sizeof(WINDOWPLACEMENT); if (GetWindowPlacement(hwnd, &wndpl)) { return StoreWindowPlacement(&wndpl); } return FALSE; } // forward declaration void EnsureWindowIsCompletelyOnScreen (RECT *prc); // The rect will be offset slightly below and to the right of its current position. // If this would cause it to move partly off the nearest monitor, then it is // instead placed at the top left of the same monitor. void CascadeWindowRect(RECT *pRect) { int delta = GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CYSIZEFRAME) - 1; OffsetRect(pRect, delta, delta); // test if the new rect will end up getting moved later on RECT rc = *pRect; EnsureWindowIsCompletelyOnScreen(&rc); if (!EqualRect(pRect, &rc)) { // rc had to be moved, so we'll restart the cascade using the best monitor MONITORINFO minfo; minfo.cbSize = sizeof(minfo); if (GetMonitorInfo(MonitorFromRect(&rc, MONITOR_DEFAULTTONEAREST), &minfo)) { // And we do mean rcMonitor, not rcWork. For example, if the taskbar is // at the top, then using rcMonitor with top-left = (0,0) will place it on // the edge of the taskbar. Using rcWork with top-left = (0,y) will put // it y pixels below the taskbar's bottom edge, which is wrong. if (rc.bottom < pRect->bottom && rc.left == pRect->left) { // Too tall to cascade further down, but we can keep the X and just // reset the Y. This fixes the bug of having a tall windows piling up // on the top left corner -- instead they will be offset to the right OffsetRect(pRect, 0, minfo.rcMonitor.top - pRect->top); } else { // we've really run out of room, so restart cascade at top left OffsetRect(pRect, minfo.rcMonitor.left - pRect->left, minfo.rcMonitor.top - pRect->top); } } } } void CalcWindowPlacement(BOOL fInternetStart, HWND hwnd, IETHREADPARAM *piei, WINDOWPLACEMENT *pwndpl) { static RECT s_rcExplorer = {-1, -1, -1, -1}; // We don't load the window placement for shell windows if (!fInternetStart || LoadWindowPlacement(pwndpl)) { // If the show command specifies a normal show or default (i.e., our initial // display setting is not being overridden by the command line or // CreateProcess setting) then use the saved window state show command. // Otherwise, use the show command passed in to us. if (fInternetStart && ((piei->nCmdShow == SW_SHOWNORMAL) || (piei->nCmdShow == SW_SHOWDEFAULT))) piei->nCmdShow = pwndpl->showCmd; // Cascade if there is window of the same kind directly under us. HWND hwndT = NULL; ATOM atomClass = (ATOM) GetClassWord(hwnd, GCW_ATOM); while (hwndT = FindWindowEx(NULL, hwndT, (LPCTSTR) atomClass, NULL)) { // Don't use GetWindowRect here because we load window placements // from the registry and they use the workspace coordinate system WINDOWPLACEMENT wp; wp.length = sizeof(wp); GetWindowPlacement(hwndT, &wp); if (wp.rcNormalPosition.left == pwndpl->rcNormalPosition.left && wp.rcNormalPosition.top == pwndpl->rcNormalPosition.top) { if ((piei->uFlags & COF_EXPLORE) && (s_rcExplorer.left != -1) && (s_rcExplorer.top != -1)) { // An explorer window is trying to appear on top of // another one. We'll use our stored rect's top-left // to make it cascade like IE windows. OffsetRect(&pwndpl->rcNormalPosition, s_rcExplorer.left - pwndpl->rcNormalPosition.left, s_rcExplorer.top - pwndpl->rcNormalPosition.top); } // do the cascade for all windows CascadeWindowRect(&pwndpl->rcNormalPosition); } } // for IE and explorer, save the current location if (piei->uFlags & COF_EXPLORE) s_rcExplorer = pwndpl->rcNormalPosition; else if (fInternetStart) StoreWindowPlacement(pwndpl); } else { pwndpl->length = 0; } } class CRGN { public: CRGN (void) { mRgn = CreateRectRgn(0, 0, 0, 0); } CRGN (const RECT& rc) { mRgn = CreateRectRgnIndirect(&rc); } ~CRGN (void) { if (mRgn) TBOOL(DeleteObject(mRgn)); } operator HRGN (void) const { return(mRgn); } void SetRegion (const RECT& rc) { TBOOL(SetRectRgn(mRgn, rc.left, rc.top, rc.right, rc.bottom)); } private: HRGN mRgn; }; BOOL CALLBACK GetDesktopRegionEnumProc (HMONITOR hMonitor, HDC hdcMonitor, RECT* prc, LPARAM lpUserData) { MONITORINFO monitorInfo; monitorInfo.cbSize = sizeof(monitorInfo); if (GetMonitorInfo(hMonitor, &monitorInfo) != 0) { HRGN hRgnDesktop; CRGN rgnMonitorWork(monitorInfo.rcWork); hRgnDesktop = *reinterpret_cast(lpUserData); if ((HRGN)rgnMonitorWork) TINT(CombineRgn(hRgnDesktop, hRgnDesktop, rgnMonitorWork, RGN_OR)); } return(TRUE); } void EnsureWindowIsCompletelyOnScreen (RECT *prc) // 99/04/13 #321962 vtan: This function exists because user32 only determines // whether ANY part of the window is visible on the screen. It's possible to // place a window without an accessible title. Pretty useless when using the // mouse and forces the user to use the VERY un-intuitive alt-space. { HMONITOR hMonitor; MONITORINFO monitorInfo; // First find the monitor that the window resides on using GDI. hMonitor = MonitorFromRect(prc, MONITOR_DEFAULTTONEAREST); ASSERT(hMonitor); // get vtan - GDI should always return a result monitorInfo.cbSize = sizeof(monitorInfo); if (GetMonitorInfo(hMonitor, &monitorInfo) != 0) { LONG lOffsetX, lOffsetY; RECT *prcWorkArea, rcIntersect; CRGN rgnDesktop, rgnIntersect, rgnWindow; // Because the WINDOWPLACEMENT rcNormalPosition field is in WORKAREA // co-ordinates this causes a displacement problem. If the taskbar is // at the left or top of the primary monitor the RECT passed even though // at (0, 0) may be at (100, 0) on the primary monitor in GDI co-ordinates // and GetMonitorInfo() will return a MONITORINFO in GDI co-ordinates. // The safest generic algorithm is to offset the WORKAREA RECT into GDI // co-ordinates and apply the algorithm in that system. Then offset the // WORKAREA RECT back into WORKAREA co-ordinates. prcWorkArea = &monitorInfo.rcWork; if (EqualRect(&monitorInfo.rcMonitor, &monitorInfo.rcWork) == 0) { // Taskbar is on this monitor - offset required. lOffsetX = prcWorkArea->left - monitorInfo.rcMonitor.left; lOffsetY = prcWorkArea->top - monitorInfo.rcMonitor.top; } else { // Taskbar is NOT on this monitor - no offset required. lOffsetX = lOffsetY = 0; } TBOOL(OffsetRect(prc, lOffsetX, lOffsetY)); // WORKAREA RECT is in GDI co-ordinates. Apply the algorithm. // Check to see if this window already fits the current visible screen // area. This is a direct region comparison. // This enumeration may cause a performance problem. In the event that // a cheap and simple solution is required it would be best to do a // RECT intersection with the monitor and the window before resorting // to the more expensive region comparison. Get vtan if necessary. TBOOL(EnumDisplayMonitors(NULL, NULL, GetDesktopRegionEnumProc, reinterpret_cast(&rgnDesktop))); rgnWindow.SetRegion(*prc); TINT(CombineRgn(rgnIntersect, rgnDesktop, rgnWindow, RGN_AND)); if (EqualRgn(rgnIntersect, rgnWindow) == 0) { LONG lDeltaX, lDeltaY; // Some part of the window is not within the visible desktop region // Move it until it all fits. Size it if it's too big. lDeltaX = lDeltaY = 0; if (prc->left < prcWorkArea->left) lDeltaX = prcWorkArea->left - prc->left; if (prc->top < prcWorkArea->top) lDeltaY = prcWorkArea->top - prc->top; if (prc->right > prcWorkArea->right) lDeltaX = prcWorkArea->right - prc->right; if (prc->bottom > prcWorkArea->bottom) lDeltaY = prcWorkArea->bottom - prc->bottom; TBOOL(OffsetRect(prc, lDeltaX, lDeltaY)); TBOOL(IntersectRect(&rcIntersect, prc, prcWorkArea)); TBOOL(CopyRect(prc, &rcIntersect)); } // Put WORKAREA RECT back into WORKAREA co-ordinates. TBOOL(OffsetRect(prc, -lOffsetX, -lOffsetY)); } } LPITEMIDLIST MyDocsIDList(void); #define FRAME_OPTIONS_TO_TEST (BFO_ADD_IE_TOCAPTIONBAR | BFO_USE_DIALUP_REF | BFO_USE_IE_TOOLBAR | \ BFO_BROWSER_PERSIST_SETTINGS | BFO_USE_IE_OFFLINE_SUPPORT) HRESULT CShellBrowser2::_SetBrowserFrameOptions(LPCITEMIDLIST pidl) { BROWSERFRAMEOPTIONS dwOptions = FRAME_OPTIONS_TO_TEST; if (FAILED(GetBrowserFrameOptionsPidl(pidl, dwOptions, &dwOptions))) { // GetBrowserFrameOptionsPidl() will fail if pidl is NULL. // in that case we want to use _fInternetStart to determine // if we want these bits set or not. if (_fInternetStart) dwOptions = FRAME_OPTIONS_TO_TEST; // Assume None. else dwOptions = BFO_NONE; // Assume None. } _fAppendIEToCaptionBar = BOOLIFY(dwOptions & BFO_ADD_IE_TOCAPTIONBAR); _fAddDialUpRef = BOOLIFY(dwOptions & BFO_USE_DIALUP_REF); _fUseIEToolbar = BOOLIFY(dwOptions & BFO_USE_IE_TOOLBAR); _fEnableOfflineFeature = BOOLIFY(dwOptions & BFO_USE_IE_OFFLINE_SUPPORT); _fUseIEPersistence = BOOLIFY(dwOptions & BFO_BROWSER_PERSIST_SETTINGS); return S_OK; } HRESULT CShellBrowser2::_ReplaceCmdLine(LPTSTR pszCmdLine, DWORD cchCmdLine) { TCHAR szVeryFirstPage[MAX_URL_STRING]; HRESULT hr = _GetStdLocation(szVeryFirstPage, ARRAYSIZE(szVeryFirstPage), DVIDM_GOFIRSTHOME); TraceMsg(DM_NAV, "CSB::_ReplaceCmdLine _GetStdLocation(DVIDM_GOFIRSTHOME) returned %x", hr); if (SUCCEEDED(hr)) { hr = StringCchCopy(pszCmdLine, cchCmdLine, szVeryFirstPage); TraceMsg(DM_NAV, "CSB::_ReplaceCmdLine _GetStdLocation(DVIDM_GOFIRSTHOME) returned %s", pszCmdLine); } return hr; } HRESULT CShellBrowser2::OnCreate(LPCREATESTRUCT pcs) { HRESULT hres = S_OK; IETHREADPARAM* piei = (IETHREADPARAM*)pcs->lpCreateParams; BOOL fUseHomePage = (piei->piehs ? FALSE : TRUE); // intentionally reversered DWORD dwExStyle = IS_BIDI_LOCALIZED_SYSTEM() ? dwExStyleRTLMirrorWnd : 0L; _clsidThis = (piei->uFlags & COF_IEXPLORE) ? CLSID_InternetExplorer : CLSID_ShellBrowserWindow; #ifdef NO_MARSHALLING if (!piei->fOnIEThread) _fOnIEThread = FALSE; #endif // // Make this thread foreground here so that any UI from // USERCLASS::OnCreate will be on the top of other windows. // We used to call this in _AfterWindowCreate, but it is // too late for dialog boxes we popup while processing WM_CREATE // message. // // Note that we do call SetForegroundWindow even if this window // is not created as a result of CoCreateInstance. The automation // client is supposed to make it visible and bring it to the // foreground if it needs to. // if (!piei->piehs) { SetForegroundWindow(_pbbd->_hwnd); } SUPERCLASS::OnCreate(pcs); EnsureWebViewRegSettings(); ASSERT(piei); _fRunningInIexploreExe = BOOLIFY(piei->uFlags & COF_IEXPLORE); v_InitMembers(); CString strCmdLine; if (piei->pszCmdLine) { strCmdLine = piei->pszCmdLine; } else { strCmdLine.Empty(); } if (piei->fCheckFirstOpen) { ASSERT(!ILIsRooted(piei->pidl)); // // We don't want to go to the very first page, if this window // is created as the result of CoCreateInstnace. // if (!piei->piehs && (piei->uFlags & COF_IEXPLORE)) { LPTSTR pstrCmdLine = strCmdLine.GetBuffer( MAX_URL_STRING ); if ( strCmdLine.GetAllocLength() < MAX_URL_STRING ) { TraceMsg( TF_WARNING, "CShellBrowser2::OnCreate() - strCmdLine Allocation Failed!" ); hres = E_OUTOFMEMORY; } else { if (SUCCEEDED(_ReplaceCmdLine( pstrCmdLine, MAX_URL_STRING ))) { _fInternetStart = TRUE; } // Let CString class own the buffer again. strCmdLine.ReleaseBuffer(); } } piei->fCheckFirstOpen = FALSE; } // NOTE: These flags and corresponding ones in IETHREADPARAM are set to FALSE at creation, // ParseCommandLine() is the only place where they are set. -- dli _fNoLocalFileWarning = piei->fNoLocalFileWarning; _fKioskMode = piei->fFullScreen; if (piei->fNoDragDrop) SetFlags(0, BSF_REGISTERASDROPTARGET); _fAutomation = piei->fAutomation; // If someone deliberately tell us not to use home page. if (piei->fDontUseHomePage) { fUseHomePage = 0; // only the IE path sets this flag. // this is used by iexplorer.exe -nohome // and by ie dde to start out blank then navigate next _fInternetStart = TRUE; } if (piei->ptl) InitializeTravelLog(piei->ptl, piei->dwBrowserIndex); LPITEMIDLIST pidl = NULL; BOOL fCloning = FALSE; if ((( ! strCmdLine.IsEmpty() ) || piei->pidl) && !_fAutomation) { if (piei->pidl) { pidl = ILClone(piei->pidl); } else { int cchCmdLine = strCmdLine.GetLength(); LPTSTR pstrCmdLine = strCmdLine.GetBuffer( MAX_URL_STRING ); HRESULT hresWrap; if ( strCmdLine.GetAllocLength() < MAX_URL_STRING ) { TraceMsg( TF_WARNING, "CShellBrowser2::OnCreate() - strCmdLine Allocation Failed!" ); hresWrap = E_OUTOFMEMORY; } else { hresWrap = WrapSpecialUrlFlat( pstrCmdLine, cchCmdLine + 1 ); // Let CString class own the buffer again. strCmdLine.ReleaseBuffer(); } if ( SUCCEEDED( hresWrap ) ) { HRESULT hresT = _ConvertPathToPidl(this, _pbbd->_hwnd, strCmdLine, &pidl); TraceMsg(DM_STARTUP, "CSB::OnCreate ConvertPathToPidl(strCmdLine) returns %x", hresT); } } } if (pidl) { fUseHomePage = FALSE; } else if (_pbbd->_ptl && SUCCEEDED(_pbbd->_ptl->GetTravelEntry((IShellBrowser *)this, 0, NULL))) { pidl = ILClone(&s_idlNULL); fCloning = TRUE; fUseHomePage = FALSE; // NOTE: if we ever hit this code when opening a window at non-web address // we'll need to be more selective about setting this flag _fInternetStart = TRUE; } else if (fUseHomePage) { // if we're not top level, assume we're going to be told // where to browse CString strPath; LPTSTR pstrPath = strPath.GetBuffer( MAX_URL_STRING ); if ( strPath.GetAllocLength() < MAX_URL_STRING ) { TraceMsg( TF_WARNING, "CShellBrowser2::OnCreate() - strPath Allocation Failed!" ); hres = E_OUTOFMEMORY; } else { if (piei->uFlags & COF_IEXPLORE) { hres = _GetStdLocation( pstrPath, MAX_URL_STRING, DVIDM_GOHOME ); } else { // we need to get the default location for an explorer window // which classically has been the root drive of the windows install GetModuleFileName( GetModuleHandle(NULL), pstrPath, MAX_URL_STRING ); PathStripToRoot(pstrPath); } // Let CString class own the buffer again. strPath.ReleaseBuffer(); } if (SUCCEEDED(hres)) { IECreateFromPath( strPath, &pidl ); } } // do this here after we've found what pidl we're looking at // but do it before the CalcWindowPlacement because // it might need to override _LoadBrowserWindowSettings(piei, pidl); // call this before PrepareInternetToolbar because it needs to know // _fInternetStart to know which toolbar config to use if (!_fInternetStart) { if (pidl) { if (fUseHomePage || IsURLChild(pidl, TRUE)) { _fInternetStart = TRUE; } else { DWORD dwAttrib = SFGAO_FOLDER | SFGAO_BROWSABLE; // if it's on the file system, we'll still consider it to be an // internet folder if it's a docobj (including .htm file) IEGetAttributesOf(pidl, &dwAttrib); if ((dwAttrib & (SFGAO_FOLDER | SFGAO_BROWSABLE)) == SFGAO_BROWSABLE) _fInternetStart = TRUE; } } else if (!(piei->uFlags & COF_SHELLFOLDERWINDOW)) { _fInternetStart = TRUE; } } _SetBrowserFrameOptions(pidl); CalcWindowPlacement(_fUseIEPersistence, _pbbd->_hwnd, piei, &piei->wp); if (!_PrepareInternetToolbar(piei)) return E_FAIL; _CreateToolbar(); // We must create _hwndStatus before navigating, because the // first navigate will go synchronous and the shell sends // status messages during that time. If the status window hasn't // been created, they drop on the floor. // _hwndStatus = CreateWindowEx(dwExStyle, STATUSCLASSNAME, NULL, WS_CHILD | SBARS_SIZEGRIP | WS_CLIPSIBLINGS | WS_VISIBLE | SBT_TOOLTIPS & ~(WS_BORDER | CCS_NODIVIDER), -100, -100, 10, 10, _pbbd->_hwnd, (HMENU)FCIDM_STATUS, HINST_THISDLL, NULL); #ifdef DEBUG if (g_dwPrototype & 0x00000004) { HRESULT hres = E_FAIL; if (_SaveToolbars(NULL) == S_OK) { // _LoadBrowserWindowSettings did a v_GetViewStream/ _LoadToolbars // if it succeeded (i.e. if we have > 0 toolbars), we're done // actually, even 0 toolbars could mean success, oh well... hres = S_OK; } ASSERT(SUCCEEDED(hres)); } #endif // REARCHITECT: do this early to let these objects see the first // navigate. but this causes a deadlock if the objects require // marshalling back to the main thread. _LoadBrowserHelperObjects(); BOOL fDontIncrementSessionCounter = FALSE; if (pidl) // paranoia { if (fCloning) { ASSERT(_pbbd->_ptl); hres = _pbbd->_ptl->Travel((IShellBrowser*)this, 0); } else { if (!_fAddDialUpRef) fDontIncrementSessionCounter = TRUE; hres = _NavigateToPidl(pidl, 0, 0); if (FAILED(hres)) { fDontIncrementSessionCounter = TRUE; // We're going to windows\blank.htm or fail ... if (_fAddDialUpRef) { // if we failed, but this was a URL child, // we should still activate and go to blank.htm hres = S_FALSE; } else if (piei->uFlags & COF_EXPLORE) { // If an explorer browser, fall back to the desktop. // // The reason is that we want Start->Windows Explorer to // bring up a browser even if MyDocs is inaccessible; // however we don't want Start->Run "" to bring up // a browser if is inaccessible. // BOOL fNavDesktop = (hres != HRESULT_FROM_WIN32(ERROR_CANCELLED)); if (!fNavDesktop) { LPITEMIDLIST pidlDocs = MyDocsIDList(); if (pidlDocs) { fNavDesktop = ILIsEqual(pidl, pidlDocs); ILFree(pidlDocs); } } if (fNavDesktop) hres = _NavigateToPidl(&s_idlNULL, 0, 0); } } } ILFree(pidl); } if (_fAddDialUpRef && !fDontIncrementSessionCounter) _IncrNetSessionCount(); if (IsOS(OS_WHISTLERORGREATER)) { if (piei->wp.length == 0) { HMONITOR hmon = (piei->uFlags & COF_HASHMONITOR) ? reinterpret_cast(piei->pidlRoot) : NULL; _GetDefaultWindowPlacement(_pbbd->_hwnd, hmon, &piei->wp); } } else { // 99/04/07 #141049 vtan: If hMonitor was given then use this as the basis // for placement of a new window. Move the window position from the primary // monitor (where user32 placed it) to the specified HMONITOR. If this // results in a placement off screen then SetWindowPlacement() will fix // this up for us. if ((piei->wp.length == 0) && ((piei->uFlags & COF_HASHMONITOR) != 0) && (piei->pidlRoot != NULL)) { MONITORINFO monitorInfo; piei->wp.length = sizeof(piei->wp); TBOOL(GetWindowPlacement(_pbbd->_hwnd, &piei->wp)); monitorInfo.cbSize = sizeof(monitorInfo); TBOOL(GetMonitorInfo(reinterpret_cast(piei->pidlRoot), &monitorInfo)); TBOOL(OffsetRect(&piei->wp.rcNormalPosition, monitorInfo.rcMonitor.left, monitorInfo.rcMonitor.top)); } } if (piei->wp.length == sizeof(piei->wp)) { BOOL fSetWindowPosition = TRUE; // we do a SetWindowPlacement first with SW_HIDE // to get the size right firsth // then we really show it. if ((piei->nCmdShow == SW_SHOWNORMAL) || (piei->nCmdShow == SW_SHOWDEFAULT)) piei->nCmdShow = piei->wp.showCmd; piei->wp.showCmd = SW_HIDE; HWND hwndTray = GetTrayWindow(); if (hwndTray) { RECT rc; if (GetWindowRect(hwndTray, &rc) && ISRECT_EQUAL(rc, piei->wp.rcNormalPosition)) { // In this case, we want to ignore the position because // it's equal to the tray. (Came from Win95/OSR2 days) fSetWindowPosition = FALSE; } } if (fSetWindowPosition) { EnsureWindowIsCompletelyOnScreen(&piei->wp.rcNormalPosition); SetWindowPlacement(_pbbd->_hwnd, &piei->wp); } } v_ShowHideChildWindows(TRUE); if (piei->piehs) { // this thread was created to be the browser automation object // turn this on to prove CoCreateInstance does not cause a dead lock. #ifdef MAX_DEBUG SendMessage(HWND_BROADCAST, WM_WININICHANGE, 0, 0); Sleep(5); SendMessage(HWND_BROADCAST, WM_WININICHANGE, 0, 0); #endif // // WARNING: Note that we must SetEvent even though we can't return // the marshalled automation object for some reason. Not signaling // the event will block the caller thread for a long time. // if (SUCCEEDED(hres)) { hres = CoMarshalInterface(piei->piehs->GetStream(), IID_IUnknown, _pbbd->_pautoWB2, MSHCTX_INPROC, 0, MSHLFLAGS_NORMAL); } piei->piehs->PutHresult(hres); SetEvent(piei->piehs->GetHevent()); } if (g_tidParking == GetCurrentThreadId()) { IEOnFirstBrowserCreation(_fAutomation ? _pbbd->_pautoWB2 : NULL); } SHGetThreadRef(&_punkMsgLoop); // pick up the ref to this thread TraceMsg(DM_STARTUP, "CSB::OnCreate returning hres=%x", hres); if (FAILED(hres)) { _SetMenu(NULL); return E_FAIL; } return S_OK; } void CShellBrowser2::_GetDefaultWindowPlacement(HWND hwnd, HMONITOR hmon, WINDOWPLACEMENT* pwp) { ASSERT(IsOS(OS_WHISTLERORGREATER)); // don't use on legacy systems. // We tailor our Web View content for 800x600 int cxView = 800; int cyView = 600; int x; int y; // Make sure we fit on the monitor... // if (NULL == hmon) hmon = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST); if (hmon) { MONITORINFO monInfo = {sizeof(monInfo), 0}; if (GetMonitorInfo(hmon, &monInfo)) { pwp->length = sizeof(WINDOWPLACEMENT); if (GetWindowPlacement(hwnd, pwp)) { // Move the window to the specified monitor. OffsetRect(&pwp->rcNormalPosition, monInfo.rcMonitor.left, monInfo.rcMonitor.top); // Reposition this window to fit on this monitor x = pwp->rcNormalPosition.left; y = pwp->rcNormalPosition.top; if (monInfo.rcWork.left <= pwp->rcNormalPosition.left && pwp->rcNormalPosition.left <= monInfo.rcWork.right && pwp->rcNormalPosition.left + cxView > monInfo.rcWork.right) { x = max(monInfo.rcWork.left, monInfo.rcWork.right - cxView); } if (monInfo.rcWork.top <= pwp->rcNormalPosition.top && pwp->rcNormalPosition.top <= monInfo.rcWork.bottom && pwp->rcNormalPosition.top + cyView > monInfo.rcWork.bottom) { y = max(monInfo.rcWork.top, monInfo.rcWork.bottom - cyView); } // Even with the above positioning, we don't want to be bigger than the monitor cxView = min(cxView, RECTWIDTH(monInfo.rcWork)); cyView = min(cyView, RECTHEIGHT(monInfo.rcWork)); // We're not using the whole screen so use the calculated position, else maximize. if (cxView != RECTWIDTH(monInfo.rcWork) || cyView != RECTHEIGHT(monInfo.rcWork)) { pwp->rcNormalPosition.left = x; pwp->rcNormalPosition.top = y; pwp->rcNormalPosition.right = x + cxView; pwp->rcNormalPosition.bottom = y + cyView; } else { pwp->showCmd = SW_MAXIMIZE; } } else { pwp->length = 0; } } } } //*** InfoIdmToTBIdm -- convert btwn browserbar IDM and TBIDM // int InfoIdmToTBIdm(int val, BOOL fToTB) { static const int menutab[] = { FCIDM_VBBSEARCHBAND, FCIDM_VBBFAVORITESBAND, FCIDM_VBBHISTORYBAND, FCIDM_VBBEXPLORERBAND, }; static const int tbtab[] = { TBIDM_SEARCH, TBIDM_FAVORITES, TBIDM_HISTORY, TBIDM_ALLFOLDERS, }; return SHSearchMapInt(fToTB ? menutab : tbtab, fToTB ? tbtab : menutab, ARRAYSIZE(menutab), val); } void _CheckSearch(UINT idmInfo, BOOL fCheck, IExplorerToolbar* _pxtb) { idmInfo = InfoIdmToTBIdm(idmInfo, TRUE); if (idmInfo == -1) return; if (_pxtb) { UINT uiState; if (SUCCEEDED(_pxtb->GetState(&CLSID_CommonButtons, idmInfo, &uiState))) { if (fCheck) uiState |= TBSTATE_CHECKED; else uiState &= ~TBSTATE_CHECKED; _pxtb->SetState(&CLSID_CommonButtons, idmInfo, uiState); } } } // // Implementation of CShellBrowser2::ShowToolbar // // Make toolbar visible or not and update our conception of whether it // should be shown. The toolbar by definition is strictly the toolbar. // The caller has no idea that part of our internet toolbar also has // the menu. We must make sure we don't hide the menuband -- only the // other bands on the internet toolbar. // // Returns: S_OK, if successfully done. // E_INVALIDARG, duh. // HRESULT CShellBrowser2::ShowToolbar(IUnknown* punkSrc, BOOL fShow) { HRESULT hres; UINT itb = _FindTBar(punkSrc); if (ITB_ITBAR == itb) { LPTOOLBARITEM ptbi = _GetToolbarItem(itb); ITBar_ShowDW(ptbi->ptbar, fShow, fShow, fShow); ptbi->fShow = fShow; hres = S_OK; } else hres = SUPERCLASS::ShowToolbar(punkSrc, fShow); return S_OK; } extern IDeskBand * _GetInfoBandBS(IBandSite *pbs, REFCLSID clsid); #ifdef DEBUG // { //*** // NOTES // WARNING: dtor frees up CBandSiteMenu on exit! // should we make sure some minimum set is created? HRESULT CShellBrowser2::_AddInfoBands(IBandSite *pbs) { if (!_pbsmInfo) return E_FAIL; BANDCLASSINFO *pbci; for (int i = 0; (pbci = _pbsmInfo->GetBandClassDataStruct(i)) != NULL; i++) { IDeskBand *pband = _GetInfoBandBS(pbs, pbci->clsid); if (pband != NULL) pband->Release(); } { // Exec -> Select or SetBandState ??? What do this mean ??? // REARCHITECT chrisfra 5/23/97 - ever heard of variants? this should set // vt = VT_I4 and lVal = 1. this is horrible, I assume this is being ripped // out when Select funcs added, if not, it should be recoded. VARIANTARG vaIn = { 0 }; //VariantInit(); vaIn.vt = VT_UNKNOWN; vaIn.punkVal = (IUnknown *)1; // show all IUnknown_Exec(pbs, &CGID_DeskBand, DBID_SHOWONLY, OLECMDEXECOPT_PROMPTUSER, &vaIn, NULL); //VariantClear(); } return S_OK; } #endif // } // REARCHITECT: [justmann 2000-01-27 this seems so ancient that it can be ignored] // this is for ie4 shell compat - the ie4 shell menus have a Explorer bar popup // need to make a pass through & fix all _GetBrowserBarMenu ref's, // since we're back to having view->explorer bars-> on all platforms HMENU CShellBrowser2::_GetBrowserBarMenu() { HMENU hmenu = _GetMenuFromID(FCIDM_VIEWBROWSERBARS); if (hmenu == NULL) { hmenu = _GetMenuFromID(FCIDM_MENU_VIEW); if (hmenu == NULL) { //if we're here, someone has taken our view menu (docobj) hmenu = SHGetMenuFromID(_hmenuPreMerged, FCIDM_VIEWBROWSERBARS); ASSERT(hmenu); } } ASSERT(IsMenu(hmenu)); return hmenu; } void CShellBrowser2::_AddBrowserBarMenuItems(HMENU hmenu) { // Find the placeholder item, so we can add items before it int iPos = SHMenuIndexFromID(hmenu, FCIDM_VBBPLACEHOLDER); if (iPos < 0) { // we've already had our way with this menu ASSERT(_pbsmInfo); return; } //_pbsmInfo is shared across all views in the view menu BOOL fCreatedNewBSMenu = FALSE; if (!_pbsmInfo) { IUnknown *punk; if (SUCCEEDED(CBandSiteMenu_CreateInstance(NULL, &punk, NULL))) { punk->QueryInterface(CLSID_BandSiteMenu, (void **)&_pbsmInfo); punk->Release(); fCreatedNewBSMenu = TRUE; } } if (!_pbsmInfo) return; int idCmdNext; UINT cBands = 0; if (fCreatedNewBSMenu) { // Load up infobands cBands = _pbsmInfo->LoadFromComCat(&CATID_InfoBand); // nuke any infoband entries that are already in the fixed list for (int i = FCIDM_VBBFIXFIRST; i < FCIDM_VBBFIXLAST; i++) { const CLSID *pclsid = _InfoIdmToCLSID(i); if (pclsid) { if (_pbsmInfo->DeleteBandClass(*pclsid)) cBands--; } } // merge the additional infobands contiguously idCmdNext = _pbsmInfo->CreateMergeMenu(hmenu, VBBDYN_MAXBAND, iPos - 1, FCIDM_VBBDYNFIRST,0); // Load up commbands _iCommOffset = cBands; cBands = _pbsmInfo->LoadFromComCat(&CATID_CommBand); } else { // Add the additional infobands contiguously int cMergedInfoBands = _pbsmInfo->GetBandClassCount(&CATID_InfoBand, TRUE /*merged*/); idCmdNext = _pbsmInfo->CreateMergeMenu(hmenu, cMergedInfoBands, iPos - 1, FCIDM_VBBDYNFIRST,0); cBands = _pbsmInfo->LoadFromComCat(NULL); } // placeholder position may have changed at this point iPos = SHMenuIndexFromID(hmenu, FCIDM_VBBPLACEHOLDER); // Add comm bands. if (_iCommOffset != cBands) { // Insert a separator if there are comm bands InsertMenu(hmenu, iPos + _iCommOffset + 1, MF_BYPOSITION | MF_SEPARATOR, -1, NULL); // Now merge the comm bands _pbsmInfo->CreateMergeMenu(hmenu, VBBDYN_MAXBAND, iPos + _iCommOffset + 2, idCmdNext, _iCommOffset); } DeleteMenu(hmenu, FCIDM_VBBPLACEHOLDER, MF_BYCOMMAND); if (!CMediaBarUtil::IsWMP7OrGreaterCapable()) { DeleteMenu(hmenu, FCIDM_VBBMEDIABAND, MF_BYCOMMAND); } } int CShellBrowser2::_IdBarFromCmdID(UINT idCmd) { const CATID* pcatid = _InfoIdmToCATID(idCmd); if (pcatid) { if (IsEqualCATID(*pcatid, CATID_InfoBand)) { // It's a vertical bar return IDBAR_VERTICAL; } else { // It's a horizontal bar ASSERT(IsEqualCATID(*pcatid, CATID_CommBand)); return IDBAR_HORIZONTAL; } } // Command doesn't correspond to any bar return IDBAR_INVALID; } int CShellBrowser2::_eOnOffNotMunge(int eOnOffNot, UINT idCmd, UINT idBar) { // FEATURE: todo -- drive an ashen stake through the foul heart of this function if (eOnOffNot == -1) { // toggle // 'special' guys are set; 'real' guys are toggled ASSERT(idCmd != FCIDM_VBBNOVERTICALBAR && idCmd != FCIDM_VBBNOHORIZONTALBAR); if (idCmd == FCIDM_VBBNOVERTICALBAR || idCmd == FCIDM_VBBNOHORIZONTALBAR) eOnOffNot = 0; else if ((idCmd >= FCIDM_VBBDYNFIRST) && (idCmd <= FCIDM_VBBDYNLAST)) eOnOffNot = (idBar == IDBAR_VERTICAL) ? (idCmd != _idmInfo) : (idCmd != _idmComm); else eOnOffNot = (idCmd != _idmInfo); } return eOnOffNot; } #define MIIM_FTYPE 0x00000100 //*** csb::_SetBrowserBarState -- handle menu/toolbar/exec command, *and* update UI // ENTRY/EXIT // idCmd FCIDM_VBB* or -1 (if want to use pclsid instead) // pclsid clsid or NULL (if want to use idCmd instead) // eOnOffToggle 1=on, 0=off, -1=not (off/not only for fixed bands for now) // NOTES // menu code calls w/ idCmd, Exec code calls w/ pclsid // void CShellBrowser2::_SetBrowserBarState(UINT idCmd, const CLSID *pclsid, int eOnOffNot, LPCITEMIDLIST pidl) { if (idCmd == -1) idCmd = _InfoCLSIDToIdm(pclsid); if (pclsid == NULL) pclsid = _InfoIdmToCLSID(idCmd); ASSERT(_InfoCLSIDToIdm(pclsid) == idCmd); int idBar = _IdBarFromCmdID(idCmd); if (idBar == IDBAR_INVALID) { // We don't recognize this bubby, bail return; } ASSERT(IDBAR_VERTICAL == idBar || IDBAR_HORIZONTAL == idBar); // Munge the unholy eOnOffNot eOnOffNot = _eOnOffNotMunge(eOnOffNot, idCmd, idBar); if (eOnOffNot == 0 && (idCmd != _idmInfo) && (idCmd != _idmComm)) { // already off return; } // _ShowHideBrowserBar can affect the size of the view window, but the on/off state of // the bar isn't actually updated until we update _idmInfo below. But we want the // view to be able to query the accurate on/off state of the bar during the resize. // So postpone resize of the actual hwnd until after the on/off state is set correctly. // _fHaveDelayedSize = FALSE; _hwndDelayedSize = _pbbd->_hwndView; // Reduce flicker: turn off window painting while we resize several windows BOOL fLock = LockWindowUpdate(_pbbd->_hwnd); ASSERT(0 == eOnOffNot || 1 == eOnOffNot); pclsid = _ShowHideBrowserBar(idBar, pclsid, eOnOffNot, pidl); if (IDBAR_VERTICAL == idBar) v_SetIcon(); if (IDBAR_VERTICAL == idBar) { // Vertical bar // since we support multiple searches in the same band // it is possible to have search band open when we clicked on // a different search so to avoid flicker we don't "unpress" the button if (_idmInfo != idCmd) _CheckSearch(_idmInfo, FALSE, _pxtb); _idmInfo = eOnOffNot ? idCmd : FCIDM_VBBNOVERTICALBAR; _CheckSearch(_idmInfo, TRUE, _pxtb); } else { // Horizontal bar _idmComm = eOnOffNot ? idCmd : FCIDM_VBBNOHORIZONTALBAR; } // Make sure that the toolbar is updated Exec(NULL, OLECMDID_UPDATECOMMANDS, 0, NULL, NULL); //set the dirty bit on itbar and save Exec(&CGID_PrivCITCommands, CITIDM_SET_DIRTYBIT, TRUE, NULL, NULL); Exec(&CGID_ShellBrowser, FCIDM_PERSISTTOOLBAR, 0, NULL, NULL); // If we delayed a resize of the view window, update it now if (_fHaveDelayedSize) { HWND hwnd = _hwndDelayedSize; _hwndDelayedSize = NULL; _PositionViewWindow(hwnd, &_rcDelayedSize); } else { _hwndDelayedSize = NULL; } if (fLock) LockWindowUpdate(NULL); } //*** do the op, but do *not* update the UI // ENTRY/EXIT // return guy who's now visible (pclsid, 0 [VBBNONE], or 1 [VBBALL]) // NOTES // don't call this directly, it's just a helper. // don't reference UI stuff (_idmInfo etc.) (except for ASSERTs). const CLSID * CShellBrowser2::_ShowHideBrowserBar(int idBar, const CLSID *pclsid, int eOnOff, LPCITEMIDLIST pidl /*= NULL*/) { ASSERT(IDBAR_VERTICAL == idBar || IDBAR_HORIZONTAL == idBar); IBandSite* pbsSite = NULL; HRESULT hr = E_FAIL; if (_fUISetByAutomation) { if (0 == eOnOff || NULL == pclsid) { // if pclsid -- hide that bar, else -- hide everyone ASSERT(NULL == pclsid || _InfoCLSIDToIdm(pclsid) == ((IDBAR_VERTICAL == idBar) ? _idmInfo : _idmComm)); _GetBrowserBar(idBar, FALSE, NULL, NULL); return NULL; } } if (0 == eOnOff || NULL == pclsid) { // if pclsid -- hide that bar, else -- hide everyone ASSERT(NULL == pclsid || _InfoCLSIDToIdm(pclsid) == ((IDBAR_VERTICAL == idBar) ? _idmInfo : _idmComm)); _GetBrowserBar(idBar, FALSE, NULL, NULL); return NULL; } hr = _GetBandSite(idBar, &pbsSite, pclsid, eOnOff); if (SUCCEEDED(hr)) { hr = _EnsureAndNavigateBand(pbsSite, pclsid, pidl); ASSERT(pbsSite); // _GetBandSite() or _GetBrowserBand() flunked with its return code ? pbsSite->Release(); } return SUCCEEDED(hr) ? pclsid : NULL; } HRESULT CShellBrowser2::_GetBandSite(int idBar, IBandSite** ppbsSite, const CLSID *pclsid, int eOnOff) { *ppbsSite = NULL; LPCWSTR pwszItem = (IDBAR_VERTICAL == idBar) ? INFOBAR_TBNAME : COMMBAR_TBNAME; //----- Persist current DeskBar (if it exists) ----- IDeskBar* pdbBar; HRESULT hr = FindToolbar(pwszItem, IID_PPV_ARG(IDeskBar, &pdbBar)); if (S_OK == hr) { VARIANT varClsid; // if a bar is being shown, tell CBrowserBar which clsid it is SA_BSTRGUID strClsid; InitFakeBSTR(&strClsid, *pclsid); varClsid.vt = VT_BSTR; varClsid.bstrVal = strClsid.wsz; IUnknown_Exec(pdbBar, &CGID_DeskBarClient, DBCID_CLSIDOFBAR, eOnOff, &varClsid, NULL); } ATOMICRELEASE(pdbBar); // get bar (create/cache or retrieve from cache) return _GetBrowserBar(idBar, TRUE, ppbsSite, pclsid); } HRESULT CShellBrowser2::_EnsureAndNavigateBand(IBandSite* pbsSite, const CLSID* pclsid, LPCITEMIDLIST pidl /*= NULL*/) { ASSERT(NULL != pbsSite); ASSERT(NULL != pclsid); IDeskBand* pdbBand = NULL; HRESULT hr = E_FAIL; if (NULL != _pbbd->_pautoWB2) { // check if this band can be found through automation SA_BSTRGUID strClsid; InitFakeBSTR(&strClsid, *pclsid); VARIANT varProp; hr = _pbbd->_pautoWB2->GetProperty(strClsid.wsz, &varProp); if (SUCCEEDED(hr)) { if (VT_UNKNOWN == varProp.vt && NULL != varProp.punkVal) { hr = varProp.punkVal->QueryInterface(IID_PPV_ARG(IDeskBand, &pdbBand)); } else { hr = E_FAIL; } VariantClear(&varProp); } // this property doesn't exist yet, so create a new band if (FAILED(hr)) { pdbBand = _GetInfoBandBS(pbsSite, *pclsid); if (pdbBand) { // add to the property so that it can be found later VARIANT var; var.vt = VT_UNKNOWN; var.punkVal = pdbBand; _pbbd->_pautoWB2->PutProperty(strClsid.wsz, var); } } } // automation object is not there, try to succeed anyway if (NULL == pdbBand) { ASSERTMSG(FALSE, "IWebBrowser2 is not available"); pdbBand = _GetInfoBandBS(pbsSite, *pclsid); } if (pdbBand) { IBandNavigate* pbn; if (pidl && SUCCEEDED(pdbBand->QueryInterface(IID_PPV_ARG(IBandNavigate, &pbn)))) { pbn->Select(pidl); pbn->Release(); } // show me, hide everyone else VARIANT var; var.vt = VT_UNKNOWN; var.punkVal = pdbBand; // Exec -> Select or SetBandState IUnknown_Exec(pbsSite, &CGID_DeskBand, DBID_SHOWONLY, OLECMDEXECOPT_PROMPTUSER, &var, NULL); pdbBand->Release(); hr = S_OK; } return hr; } BANDCLASSINFO* CShellBrowser2::_BandClassInfoFromCmdID(UINT idCmd) { if (IsInRange(idCmd, FCIDM_VBBDYNFIRST, FCIDM_VBBDYNLAST)) { if (_pbsmInfo) { int i, cnt = _pbsmInfo->GetBandClassCount(NULL, FALSE); for (i = 0; i < cnt; i++) { BANDCLASSINFO *pbci = _pbsmInfo->GetBandClassDataStruct(i); if (pbci && idCmd == pbci->idCmd) return pbci; } } } return NULL; } // map menu ID valued (FCIDM_VBB*'s) to corresponding CLSID // handles both 'fixed' and dynamic guys const CLSID *CShellBrowser2::_InfoIdmToCLSID(UINT idCmd) { const CLSID *pclsid = NULL; if (IsInRange(idCmd, FCIDM_VBBFIXFIRST, FCIDM_VBBFIXLAST)) { switch (idCmd) { case FCIDM_VBBSEARCHBAND: pclsid = &CLSID_SearchBand; break; case FCIDM_VBBFAVORITESBAND: pclsid = &CLSID_FavBand; break; case FCIDM_VBBHISTORYBAND: pclsid = &CLSID_HistBand; break; case FCIDM_VBBEXPLORERBAND: pclsid = &CLSID_ExplorerBand; break; case FCIDM_VBBMEDIABAND: pclsid = &CLSID_MediaBand; break; } } else { BANDCLASSINFO* pbci = _BandClassInfoFromCmdID(idCmd); if (pbci) pclsid = &pbci->clsid; } return pclsid; } const CATID *CShellBrowser2::_InfoIdmToCATID(UINT idCmd) { const CATID* pcatid = NULL; if (IsInRange(idCmd, FCIDM_VBBFIXFIRST, FCIDM_VBBFIXLAST)) { // The fixed bars are all in the vertical comcat pcatid = &CATID_InfoBand; } else { // Dynamic bar, have to look up the catid BANDCLASSINFO* pbci = _BandClassInfoFromCmdID(idCmd); if (pbci) pcatid = &pbci->catid; } return pcatid; } UINT CShellBrowser2::_InfoCLSIDToIdm(const CLSID *pguid) { if (pguid == NULL) return 0; else if (IsEqualIID(*pguid, CLSID_ExplorerBand)) return FCIDM_VBBEXPLORERBAND; else if (IsEqualIID(*pguid, CLSID_SearchBand)) return FCIDM_VBBSEARCHBAND; else if (IsEqualIID(*pguid, CLSID_FileSearchBand)) return FCIDM_VBBSEARCHBAND; else if (IsEqualIID(*pguid, CLSID_FavBand)) return FCIDM_VBBFAVORITESBAND; else if (IsEqualIID(*pguid, CLSID_HistBand)) return FCIDM_VBBHISTORYBAND; else if (IsEqualIID(*pguid, CLSID_MediaBand)) return FCIDM_VBBMEDIABAND; else { if (!_pbsmInfo) { // Load the Browser Bar Menu to load the class ids of all Component Categories dynamic Browser bars _AddBrowserBarMenuItems(_GetBrowserBarMenu()); // Unable to load the clsids from dynamic bars. if (!_pbsmInfo) return -1; } BANDCLASSINFO *pbci; for (int i = 0; NULL != (pbci = _pbsmInfo->GetBandClassDataStruct(i)); i++) if (IsEqualIID(*pguid, pbci->clsid)) return (pbci->idCmd); // FEATURE: look up in _pbsmInfo->LoadFromComCat's HDPA // ASSERT(0); } return -1; } HBITMAP CreateColorBitmap(int cx, int cy) { HBITMAP hbm = NULL; HDC hdc = GetDC(NULL); if (hdc) { hbm = CreateCompatibleBitmap(hdc, cx, cy); ReleaseDC(NULL, hdc); } return hbm; } HRESULT CShellBrowser2::_GetBSForBar(LPCWSTR pwszItem, IBandSite **ppbs) { *ppbs = NULL; IDeskBar *pdbBar; HRESULT hr = FindToolbar(pwszItem, IID_PPV_ARG(IDeskBar, &pdbBar)); if (hr == S_OK) { IUnknown *punkBS; hr = pdbBar->GetClient(&punkBS); if (SUCCEEDED(hr)) { hr = punkBS->QueryInterface(IID_PPV_ARG(IBandSite, ppbs)); ASSERT(SUCCEEDED(hr)); punkBS->Release(); } pdbBar->Release(); } return hr; } void CShellBrowser2::_ExecAllBands(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANTARG *pvarargIn, VARIANTARG *pvarargOut) { IBandSite *pbsBS; HRESULT hres = _GetBSForBar(INFOBAR_TBNAME, &pbsBS); if (hres == S_OK) { DWORD dwBandID; for (int i = 0; SUCCEEDED(pbsBS->EnumBands(i, &dwBandID)); i++) { IDeskBand *pstb; hres = pbsBS->QueryBand(dwBandID, &pstb, NULL, NULL, 0); if (SUCCEEDED(hres)) { IUnknown_Exec(pstb, pguidCmdGroup, nCmdID, nCmdexecopt, pvarargIn, pvarargOut); pstb->Release(); } } pbsBS->Release(); } } HRESULT CShellBrowser2::_GetBrowserBar(int idBar, BOOL fShow, IBandSite** ppbs, const CLSID* pclsid) { HRESULT hres; IUnknown *punkBar; IDeskBar *pdbBar = NULL; IUnknown *punkBS = NULL; if (ppbs) *ppbs = NULL; if (IDBAR_VERTICAL == idBar) { hres = FindToolbar(INFOBAR_TBNAME, IID_PPV_ARG(IDeskBar, &pdbBar)); } else { ASSERT(IDBAR_HORIZONTAL == idBar); // No other bars right now. hres = FindToolbar(COMMBAR_TBNAME, IID_PPV_ARG(IDeskBar, &pdbBar)); } TraceMsg(DM_MISC, "CSB::_GetBrowserBar FindToolbar returned %x", hres); BOOL fTurnOffAutoHide = FALSE; if (hres == S_OK) { // already have one hres = pdbBar->GetClient((IUnknown**) &punkBS); ASSERT(SUCCEEDED(hres)); punkBar = pdbBar; // punkBar->Release() down below } else { //if there's not a bar, don't bother creating one so it can be hidden if (!fShow) return S_OK; // 1st time, create a new one CBrowserBar* pdb = new CBrowserBar(); if (NULL == pdb) { return E_OUTOFMEMORY; } else { // add it pdb->QueryInterface(IID_PPV_ARG(IUnknown, &punkBar)); //if a bar is being shown, tell CBrowserBar which clsid it is SA_BSTRGUID strClsid; InitFakeBSTR(&strClsid, *pclsid); VARIANT varClsid; varClsid.vt = VT_BSTR; varClsid.bstrVal = strClsid.wsz; IUnknown_Exec(punkBar, &CGID_DeskBarClient, DBCID_CLSIDOFBAR, fShow, &varClsid, NULL); UINT uiWidthOrHeight = pdb->_PersistState(NULL, FALSE); //don't let anyone be 0 width if (uiWidthOrHeight == 0) uiWidthOrHeight = (IDBAR_VERTICAL == idBar) ? INFOBAR_WIDTH : COMMBAR_HEIGHT; fTurnOffAutoHide = !(GetSystemMetrics(SM_CXSCREEN) <= 800); CBrowserBarPropertyBag* ppb; // FEATURE - this needs to be persisted and restored // when % widths are implemented, should use that ppb = new CBrowserBarPropertyBag(); if (ppb) { if (IDBAR_VERTICAL == idBar) { ppb->SetDataDWORD(PROPDATA_SIDE, ABE_LEFT); // LEFT ppb->SetDataDWORD(PROPDATA_LEFT, uiWidthOrHeight); ppb->SetDataDWORD(PROPDATA_RIGHT, uiWidthOrHeight); } else { ppb->SetDataDWORD(PROPDATA_SIDE, ABE_BOTTOM); // BOTTOM ppb->SetDataDWORD(PROPDATA_TOP, uiWidthOrHeight); ppb->SetDataDWORD(PROPDATA_BOTTOM, uiWidthOrHeight); } ppb->SetDataDWORD(PROPDATA_MODE, WBM_BBOTTOMMOST); SHLoadFromPropertyBag(punkBar, ppb); ppb->Release(); } hres = AddToolbar(punkBar, (IDBAR_VERTICAL == idBar) ? INFOBAR_TBNAME : COMMBAR_TBNAME, DWFAF_HIDDEN); if (SUCCEEDED(hres)) { hres = BrowserBar_Init(pdb, &punkBS, idBar); } pdb->Release(); } } // need to set band info here each time since deskbar/bandsite get reused if (fShow && punkBS) { BANDSITEINFO bsinfo; bsinfo.dwMask = BSIM_STYLE; bsinfo.dwStyle = BSIS_NOGRIPPER | BSIS_LEFTALIGN; IBandSite* pSite; HRESULT hr = punkBS->QueryInterface(IID_PPV_ARG(IBandSite, &pSite)); if (SUCCEEDED(hr)) { pSite->SetBandSiteInfo(&bsinfo); pSite->Release(); } } // note: must call _SetTheaterBrowserBar BEFORE ShowToolbar when showing bar if (IDBAR_VERTICAL == idBar && fShow) _SetTheaterBrowserBar(); ShowToolbar(punkBar, fShow); // note: must call _SetTheaterBrowserBar AFTER ShowToolbar when hiding bar if (IDBAR_VERTICAL == idBar && !fShow) _SetTheaterBrowserBar(); //tell CBrowserBar about the new bar, must be AFTER it is shown (to get the size right) if (SUCCEEDED(hres) && fShow) { //if a bar is being shown, tell CBrowserBar which clsid it is SA_BSTRGUID strClsid; InitFakeBSTR(&strClsid, *pclsid); VARIANT varClsid; varClsid.vt = VT_BSTR; varClsid.bstrVal = strClsid.wsz; IUnknown_Exec(punkBar, &CGID_DeskBarClient, DBCID_CLSIDOFBAR, fShow, &varClsid, NULL); } else { IUnknown_Exec(punkBar, &CGID_DeskBarClient, DBCID_CLSIDOFBAR, 0, NULL, NULL); } // note: must have called ShowToolbar BEFORE setting pin button state if (fTurnOffAutoHide) { VARIANT v = { VT_I4 }; v.lVal = FALSE; IUnknown_Exec(punkBar, &CGID_Theater, THID_SETBROWSERBARAUTOHIDE, 0, &v, &v); } punkBar->Release(); //FEATURE: What should we do for CommBar in Theatre Mode? if (punkBS) { HRESULT hr = S_OK; if (ppbs) { hr = punkBS->QueryInterface(IID_PPV_ARG(IBandSite, ppbs)); } punkBS->Release(); return hr; // there are callers to _GetBrowserBar which need to know if QI for IBandSite succeeded } return E_FAIL; } #ifdef DEBUG //*** DBCheckCLSID -- make sure class tells truth about its CLSID // BOOL DBCheckCLSID(IUnknown *punk, const CLSID *pclsid) { CLSID clsid; HRESULT hr = IUnknown_GetClassID(punk, &clsid); if (SUCCEEDED(hr) && IsEqualGUID(*pclsid, clsid)) return TRUE; TraceMsg(DM_ERROR, "dbcc: CLSID mismatch! &exp=%x &act=%x", pclsid, clsid); return FALSE; } #endif IDeskBand * _GetInfoBandBS(IBandSite *pbs, REFCLSID clsid) { IDeskBand *pstb = FindBandByClsidBS(pbs, clsid); if (pstb == NULL) { TraceMsg(DM_MISC, "_gib: create band"); if (SUCCEEDED(CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IDeskBand, &pstb)))) { // hide all bands before adding new band VARIANTARG vaIn = { 0 }; vaIn.vt = VT_UNKNOWN; vaIn.punkVal = 0; IUnknown_Exec(pbs, &CGID_DeskBand, DBID_SHOWONLY, OLECMDEXECOPT_PROMPTUSER, &vaIn, NULL); pbs->AddBand(pstb); } } return pstb; } void CShellBrowser2::_OrganizeFavorites() { TCHAR szPath[MAX_PATH]; if (SHGetSpecialFolderPath(NULL, szPath, CSIDL_FAVORITES, TRUE)) { if (GetKeyState(VK_SHIFT) < 0) { OpenFolderPath(szPath); } else DoOrganizeFavDlgW(_pbbd->_hwnd, NULL); } } /*---------------------------------------------------------- Purpose: Handle WM_COMMAND for favorites menu */ void CShellBrowser2::_FavoriteOnCommand(HMENU hmenu, UINT idCmd) { switch (idCmd) { case FCIDM_ORGANIZEFAVORITES: _OrganizeFavorites(); break; case FCIDM_ADDTOFAVORITES: Exec(&CGID_Explorer, SBCMDID_ADDTOFAVORITES, OLECMDEXECOPT_PROMPTUSER, NULL, NULL); // Instrument add to favorites from menu UEMFireEvent(&UEMIID_BROWSER, UEME_INSTRBROWSER, UEMF_INSTRUMENT, UIBW_ADDTOFAV, UIBL_MENU); break; case FCIDM_UPDATESUBSCRIPTIONS: UpdateSubscriptions(); break; } } HRESULT CShellBrowser2::CreateBrowserPropSheetExt(REFIID riid, void **ppvObj) { *ppvObj = NULL; IUnknown *punk; HRESULT hr = CoCreateInstance(CLSID_ShellFldSetExt, NULL, CLSCTX_INPROC_SERVER, riid, (void **)&punk); if (SUCCEEDED(hr)) { IShellExtInit *psxi; hr = punk->QueryInterface(IID_PPV_ARG(IShellExtInit, &psxi)); if (SUCCEEDED(hr)) { hr = psxi->Initialize(NULL, NULL, 0); if (SUCCEEDED(hr)) { IUnknown_SetSite(punk, SAFECAST(this, IShellBrowser*)); IUnknown_Set((IUnknown **)ppvObj, punk); hr = S_OK; // All happy } psxi->Release(); } punk->Release(); } return hr; } LPITEMIDLIST CShellBrowser2::_GetSubscriptionPidl() { LPITEMIDLIST pidlSubscribe = NULL; IDispatch * pDispatch = NULL; IHTMLDocument2 * pHTMLDocument = NULL; // Search HTML for if ( SUCCEEDED(_pbbd->_pautoWB2->get_Document(&pDispatch)) && SUCCEEDED(pDispatch->QueryInterface(IID_PPV_ARG(IHTMLDocument2, &pHTMLDocument))) ) { IHTMLElementCollection * pLinksCollection; if (SUCCEEDED(GetDocumentTags(pHTMLDocument, OLESTR("LINK"), &pLinksCollection))) { long lItemCnt; // Step through each of the LINKs in the // collection looking for REL="Subscription". EVAL(SUCCEEDED(pLinksCollection->get_length(&lItemCnt))); for (long lItem = 0; lItem < lItemCnt; lItem++) { IDispatch * pDispItem = NULL; IHTMLLinkElement * pLinkElement = NULL; VARIANT vEmpty = { 0 }; VARIANT vIndex; V_VT(&vIndex) = VT_I4; V_I4(&vIndex) = lItem; if ( SUCCEEDED(pLinksCollection->item(vIndex, vEmpty, &pDispItem)) && SUCCEEDED(pDispItem->QueryInterface(IID_IHTMLLinkElement, (void **)&pLinkElement)) ) { BSTR bstrREL = NULL; BSTR bstrHREF = NULL; // Finally! We have a LINK element, check its REL type. if ( SUCCEEDED(pLinkElement->get_rel(&bstrREL)) && (bstrREL != NULL) && SUCCEEDED(pLinkElement->get_href(&bstrHREF)) && (bstrHREF != NULL) ) { // Check for REL="Subscription" if (StrCmpIW(bstrREL, OLESTR("Subscription")) == 0) { TCHAR szName[MAX_URL_STRING]; SHUnicodeToTChar(bstrHREF, szName, ARRAYSIZE(szName)); EVAL(SUCCEEDED(IECreateFromPath(szName, &pidlSubscribe))); } } if (bstrHREF != NULL) SysFreeString(bstrHREF); if (bstrREL != NULL) SysFreeString(bstrREL); } VariantClear(&vIndex); VariantClear(&vEmpty); SAFERELEASE(pLinkElement); SAFERELEASE(pDispItem); // If we found a correctl REL type, quit searching. if (pidlSubscribe != NULL) break; } pLinksCollection->Release(); } } SAFERELEASE(pHTMLDocument); SAFERELEASE(pDispatch); return pidlSubscribe; } LPITEMIDLIST CShellBrowser2::_TranslateRoot(LPCITEMIDLIST pidl) { LPCITEMIDLIST pidlChild = ILFindChild(ILRootedFindIDList(_pbbd->_pidlCur), pidl); ASSERT(pidlChild); LPITEMIDLIST pidlRoot = ILCloneFirst(_pbbd->_pidlCur); if (pidlRoot) { LPITEMIDLIST pidlRet = ILCombine(pidlRoot, pidlChild); ILFree(pidlRoot); return pidlRet; } return NULL; } BOOL CShellBrowser2::_ValidTargetPidl(LPCITEMIDLIST pidl, BOOL *pfTranslateRoot) { // validate that this is an allowable target to browse to. // check that it is a child of our root. if (pfTranslateRoot) *pfTranslateRoot = FALSE; if (ILIsRooted(_pbbd->_pidlCur)) { BOOL fRet = ILIsEqualRoot(_pbbd->_pidlCur, pidl); if (!fRet && pfTranslateRoot && ILIsParent(ILRootedFindIDList(_pbbd->_pidlCur), pidl, FALSE)) { fRet = TRUE; *pfTranslateRoot = TRUE; } return fRet; } return TRUE; } IStream* CShellBrowser2::_GetITBarStream(BOOL fWebBrowser, DWORD grfMode) { return GetITBarStream(fWebBrowser ? ITBS_WEB : ITBS_SHELL, grfMode); } HRESULT CShellBrowser2::_SaveITbarLayout(void) { HRESULT hres = E_FAIL; #ifdef NO_MARSHALLING if (!_fOnIEThread) return S_OK; #endif if (_fUISetByAutomation || _ptheater) { return S_OK; } if (_GetITBar()) { IPersistStreamInit *pITbarPSI; //Yes! It's a different type. We may need to save the stream if (SUCCEEDED(_GetITBar()->QueryInterface(IID_PPV_ARG(IPersistStreamInit, &pITbarPSI)))) { //Do we need to save the stream? if (pITbarPSI->IsDirty() == S_OK) { BOOL fInternet = (CITE_INTERNET == GetScode(IUnknown_Exec(pITbarPSI, &CGID_PrivCITCommands, CITIDM_ONINTERNET, CITE_QUERY, NULL, NULL))); IStream *pstm = _GetITBarStream(fInternet, STGM_WRITE); if (pstm) { //Stream exists. Save it there!. hres = pITbarPSI->Save(pstm, TRUE); pstm->Release(); } else { //Stream creation failed! Why? TraceMsg(DM_ITBAR, "CSB::_SaveITbarLayout ITBar Stream creation failed"); ASSERT(0); } } else hres = S_OK; // No need to save. Return success! pITbarPSI->Release(); } else { //ITBar doesn't support IPersistStreamInit? AssertMsg(0, TEXT("CSB::_NavigateToPidl ITBar doesn't support IPersistStreamInit")); } } return hres; } // Returns TRUE if we are supposed to fail the navigate, FALSE otherwise BOOL MaybeRunICW(LPCITEMIDLIST pidl, IShellBrowser *psb, HWND hwndUI) { TCHAR szURL[MAX_URL_STRING]; EVAL(SUCCEEDED(IEGetNameAndFlags(pidl, SHGDN_FORPARSING, szURL, SIZECHARS(szURL), NULL))); if (UrlHitsNetW(szURL) && !UrlIsInstalledEntry(szURL)) { if ((CheckRunICW(szURL)) || CheckSoftwareUpdateUI(hwndUI, psb)) // see if ICW needs to run return TRUE; } return FALSE; } HRESULT CShellBrowser2::_NavigateToPidl(LPCITEMIDLIST pidl, DWORD grfHLNF, DWORD dwFlags) { if (pidl) { ASSERT(_ValidTargetPidl(pidl, NULL)); if (!g_fICWCheckComplete && IsBrowserFrameOptionsPidlSet(pidl, BFO_USE_DIALUP_REF)) { if (MaybeRunICW(pidl, SAFECAST(this, IShellBrowser *), _pbbd->_hwnd)) { // ICW ran and this was first navigate, shut down now. // Or the user wants a software update, so we're launching a new browser // to the update page _pbbd->_pautoWB2->put_Visible(FALSE); _pbbd->_pautoWB2->Quit(); return E_FAIL; } } if (!_fVisitedNet && IsBrowserFrameOptionsPidlSet(pidl, BFO_USE_DIALUP_REF)) _IncrNetSessionCount(); } // See if we are about to navigate to a pidl of a different type. If so, // open the stream and call the ITBar's IPersistStreamInit::save to save. // If we don't have a _pidlCur, then we're opening for the first time, so don't need to save if (_pbbd->_pidlCur && _GetITBar()) { //Check if we are about to navigate to a different "type" of folder if (((INT_PTR)_pbbd->_pidlCur && !IsBrowserFrameOptionsSet(_pbbd->_psf, BFO_BROWSER_PERSIST_SETTINGS)) != ((INT_PTR)pidl && !IsBrowserFrameOptionsPidlSet(pidl, BFO_BROWSER_PERSIST_SETTINGS))) { _SaveITbarLayout(); } } return SUPERCLASS::_NavigateToPidl(pidl, grfHLNF, dwFlags); } HRESULT CShellBrowser2::BrowseObject(LPCITEMIDLIST pidl, UINT wFlags) { HRESULT hr; LPITEMIDLIST pidlFree = NULL; // if we're about to go to a new browser, save the layout so that they'll pick it up if (wFlags & SBSP_NEWBROWSER) _SaveITbarLayout(); // 99/03/30 vtan: part of #254171 addition // explore with explorer band visible = same window // explore with explorer band NOT visible = new window if (wFlags & SBSP_EXPLOREMODE) { BOOL fExplorerBandVisible; if (SUCCEEDED(IsControlWindowShown(FCW_TREE, &fExplorerBandVisible)) && fExplorerBandVisible) { wFlags &= ~SBSP_NEWBROWSER; wFlags |= SBSP_SAMEBROWSER; } else { wFlags &= ~SBSP_SAMEBROWSER; wFlags |= SBSP_NEWBROWSER; } } // if the caller did not specify explictly "new window" or "same window" // we compute that here for them. note, CBaseBrowser assumes SBSP_SAMEBROWSER // if SBSP_NEWBROWSER is not specified if ((wFlags & (SBSP_NEWBROWSER | SBSP_SAMEBROWSER)) == 0) { CABINETSTATE cs; GetCabState(&cs); if (GetAsyncKeyState(VK_CONTROL) < 0) cs.fNewWindowMode = !cs.fNewWindowMode; if (cs.fNewWindowMode) wFlags |= SBSP_NEWBROWSER | SBSP_NOTRANSFERHIST; } BOOL fTranslate = FALSE; // REVIEW: do this only if NEWBROWSER is not set? if (pidl && pidl != (LPCITEMIDLIST)-1 && !_ValidTargetPidl(pidl, &fTranslate)) { OpenFolderPidl(pidl); // we can't navigate to it... create a new top level dude return E_FAIL; } if (fTranslate) { pidl = pidlFree = _TranslateRoot(pidl); } if ((wFlags & SBSP_PARENT) && !_ShouldAllowNavigateParent()) { hr = E_FAIL; goto exit; } #ifdef BROWSENEWPROCESS_STRICT // "Nav in new process" has become "Launch in new process", so this is no longer needed // If we want to be strict about BrowseNewProcess (apparently not, // given recent email discussions), we'd have to try this one in // a new process. However, don't do that if the window would wind up // completely blank. // if ((_pbbd->_pidlCur || _pbbd->_pidlPending) && TryNewProcessIfNeeded(pidl)) { hr = S_OK; goto exit; } #endif hr = SUPERCLASS::BrowseObject(pidl, wFlags); exit: ILFree(pidlFree); return hr; } void CShellBrowser2::_ToolTipFromCmd(LPTOOLTIPTEXT pnm) { UINT idCommand = (UINT)pnm->hdr.idFrom; LPTSTR pszText = pnm->szText; int cchText = ARRAYSIZE(pnm->szText); DWORD dwStyle; ITravelLog *ptl; if (pnm->hdr.hwndFrom) dwStyle = GetWindowLong(pnm->hdr.hwndFrom, GWL_STYLE); switch (idCommand) { case FCIDM_NAVIGATEBACK: case FCIDM_NAVIGATEFORWARD: if (SUCCEEDED(GetTravelLog(&ptl))) { WCHAR wzText[MAX_PATH]; ASSERT(ptl); if (S_OK == ptl->GetToolTipText(SAFECAST(this, IShellBrowser *), idCommand == FCIDM_NAVIGATEBACK ? TLOG_BACK : TLOG_FORE, 0, wzText, ARRAYSIZE(wzText))) { SHUnicodeToTChar(wzText, pszText, cchText); if (pnm->hdr.hwndFrom) SetWindowLong(pnm->hdr.hwndFrom, GWL_STYLE, dwStyle | TTS_NOPREFIX); } ptl->Release(); return; } break; } if (pnm->hdr.hwndFrom) SetWindowLong(pnm->hdr.hwndFrom, GWL_STYLE, dwStyle & ~(TTS_NOPREFIX)); if (!MLLoadString(idCommand + MH_TTBASE, pszText, cchText)) *pszText = 0; } void CShellBrowser2::v_ParentFolder() { if (_ShouldAllowNavigateParent()) { IETHREADPARAM* piei = SHCreateIETHREADPARAM(NULL, 0, NULL, NULL); if (piei) { piei->hwndCaller = _pbbd->_hwnd; piei->pidl = ILClone(_pbbd->_pidlCur); if (!ILRemoveHiddenID(piei->pidl, IDLHID_NAVIGATEMARKER)) { ILRemoveLastID(piei->pidl); } piei->uFlags = COF_NORMAL; piei->nCmdShow = SW_SHOW; piei->psbCaller = this; AddRef(); SHOpenFolderWindow(piei); } } } LRESULT CShellBrowser2::v_ForwardMenuMsg(UINT uMsg, WPARAM wParam, LPARAM lParam) { return ForwardViewMsg(uMsg, wParam, lParam); } HRESULT CShellBrowser2::_GetCodePage(UINT *puiCodePage, DWORD dwCharSet) { HRESULT hres = E_FAIL; VARIANT varIn = { 0 }; VARIANT varResult = { 0 }; VARIANT *pvarIn; if (_pbbd->_pctView) { if (dwCharSet == SHDVID_DOCFAMILYCHARSET) { // need varIn varIn.vt = VT_I4; // varIn.lVal is already inited to zero which is what we want pvarIn = &varIn; } else { pvarIn = NULL; } _pbbd->_pctView->Exec(&CGID_ShellDocView, dwCharSet, 0, pvarIn, &varResult); *puiCodePage = (UINT)varResult.lVal; } return hres; } void CShellBrowser2::_SendCurrentPage(DWORD dwSendAs) { if (_pbbd->_pidlCur && !ILIsEmpty(_pbbd->_pidlCur)) { UINT uiCodePage; _GetCodePage(&uiCodePage, SHDVID_DOCCHARSET); IOleCommandTarget *pcmdt = NULL; if (_pbbd->_pautoWB2) { (_pbbd->_pautoWB2)->QueryInterface(IID_PPV_ARG(IOleCommandTarget, &pcmdt)); ASSERT(pcmdt); } SendDocToMailRecipient(_pbbd->_pidlCur, uiCodePage, dwSendAs, pcmdt); if (pcmdt) pcmdt->Release(); } } typedef void (* PFNSHOWJAVACONSOLE)(void); // We need a LoadLibrary/GetProcAddress stub here since msjava.lib improperly // exports ShowJavaConsole as undecorated (ShowJavaConsole vs. _ShowJavaConsole@0). STDAPI_(void) DL_ShowJavaConsole() { static PFNSHOWJAVACONSOLE s_pfn = (PFNSHOWJAVACONSOLE)-1; if (s_pfn == (PFNSHOWJAVACONSOLE)-1) { HMODULE hmodMSJAVA = LoadLibraryA("MSJAVA.DLL"); if (hmodMSJAVA) { s_pfn = (PFNSHOWJAVACONSOLE)GetProcAddress(hmodMSJAVA, "ShowJavaConsole"); } else { s_pfn = NULL; } } if (s_pfn) { s_pfn(); } } LRESULT CShellBrowser2::OnCommand(WPARAM wParam, LPARAM lParam) { int id; DWORD dwError; if (_ShouldForwardMenu(WM_COMMAND, wParam, lParam)) { ForwardViewMsg(WM_COMMAND, wParam, lParam); return S_OK; } UINT idCmd = GET_WM_COMMAND_ID(wParam, lParam); switch(idCmd) { case FCIDM_MOVE: case FCIDM_COPY: case FCIDM_PASTE: case FCIDM_SELECTALL: { IOleCommandTarget* pcmdt; HRESULT hres = _FindActiveTarget(IID_PPV_ARG(IOleCommandTarget, &pcmdt)); if (SUCCEEDED(hres)) { const static UINT c_mapEdit[] = { OLECMDID_CUT, OLECMDID_COPY, OLECMDID_PASTE, OLECMDID_SELECTALL }; pcmdt->Exec(NULL, c_mapEdit[idCmd-FCIDM_MOVE], OLECMDEXECOPT_PROMPTUSER, NULL, NULL); pcmdt->Release(); } } return S_OK; case FCIDM_DELETE: case FCIDM_PROPERTIES: case FCIDM_RENAME: if (_HasToolbarFocus()) { static const int tbtab[] = { FCIDM_DELETE, FCIDM_PROPERTIES, FCIDM_RENAME }; static const int cttab[] = { SBCMDID_FILEDELETE, SBCMDID_FILEPROPERTIES, SBCMDID_FILERENAME }; DWORD nCmdID = SHSearchMapInt(tbtab, cttab, ARRAYSIZE(tbtab), idCmd); IDockingWindow* ptbar = _GetToolbarItem(_itbLastFocus)->ptbar; if (SUCCEEDED(IUnknown_Exec(ptbar, &CGID_Explorer, nCmdID, 0, NULL, NULL))) return S_OK; } SUPERCLASS::OnCommand(wParam, lParam); break; case FCIDM_VIEWAUTOHIDE: IUnknown_Exec(_GetITBar(), &CGID_PrivCITCommands, CITIDM_VIEWAUTOHIDE, 0, NULL, NULL); break; case FCIDM_VIEWTOOLBARCUSTOMIZE: IUnknown_Exec(_GetITBar(), &CGID_PrivCITCommands, CITIDM_VIEWTOOLBARCUSTOMIZE, 0, NULL, NULL); break; case FCIDM_VIEWLOCKTOOLBAR: IUnknown_Exec(_GetITBar(), &CGID_PrivCITCommands, CITIDM_VIEWLOCKTOOLBAR, 0, NULL, NULL); break; case FCIDM_VIEWTEXTLABELS: if (!SHIsRestricted2W(_pbbd->_hwnd, REST_NoToolbarOptions, NULL, 0)) IUnknown_Exec(_GetITBar(), &CGID_PrivCITCommands, CITIDM_TEXTLABELS, 0, NULL, NULL); break; case FCIDM_EDITPAGE: IUnknown_Exec(_GetITBar(), &CGID_PrivCITCommands, CITIDM_EDITPAGE, 0, NULL, NULL); break; case FCIDM_FINDFILES: // Call Exec on ourselfes -- it's handled there if (!SHIsRestricted2W(_pbbd->_hwnd, REST_NoFindFiles, NULL, 0)) { IDockingWindow* ptbar = _GetToolbarItem(ITB_ITBAR)->ptbar; VARIANT var = {0}; VARIANT *pvar = NULL; if (ptbar) { pvar = &var; var.vt = VT_UNKNOWN; var.punkVal = ptbar; ptbar->AddRef(); } Exec(NULL, OLECMDID_FIND, OLECMDEXECOPT_PROMPTUSER, pvar, NULL); if (ptbar) ptbar->Release(); } break; case FCIDM_CONNECT: DoNetConnect(_pbbd->_hwnd); break; case FCIDM_DISCONNECT: DoNetDisconnect(_pbbd->_hwnd); break; case FCIDM_FORTEZZA_LOGIN: dwError = InternetFortezzaCommand(FORTCMD_LOGON, _pbbd->_hwnd, 0); break; case FCIDM_FORTEZZA_LOGOUT: dwError = InternetFortezzaCommand(FORTCMD_LOGOFF, _pbbd->_hwnd, 0); break; case FCIDM_FORTEZZA_CHANGE: dwError = InternetFortezzaCommand(FORTCMD_CHG_PERSONALITY, _pbbd->_hwnd, 0); break; case FCIDM_BACKSPACE: // NT #216896: We want to use FCIDM_PREVIOUSFOLDER even for URL PIDLs if they // have the folder attribute set because they could be using delegate // pidls thru DefView. (FTP & Web Folders) -BryanSt if (_pbbd->_pidlCur && IsBrowserFrameOptionsSet(_pbbd->_psf, BFO_NO_PARENT_FOLDER_SUPPORT)) { ITravelLog *ptl; if (SUCCEEDED(GetTravelLog(&ptl))) { ASSERT(ptl); if (S_OK == ptl->GetTravelEntry(SAFECAST(this, IShellBrowser *), TLOG_FORE, NULL)) { OnCommand(GET_WM_COMMAND_MPS(FCIDM_NAVIGATEBACK, GET_WM_COMMAND_HWND(wParam, lParam), GET_WM_COMMAND_CMD(wParam, lParam))); } ptl->Release(); } } else { OnCommand(GET_WM_COMMAND_MPS(FCIDM_PREVIOUSFOLDER, GET_WM_COMMAND_HWND(wParam, lParam), GET_WM_COMMAND_CMD(wParam, lParam))); } break; case FCIDM_PREVIOUSFOLDER: // missnamed... is really parent folder v_ParentFolder(); break; case FCIDM_FILECLOSE: PostMessage(_pbbd->_hwnd, WM_CLOSE, 0, 0); break; case FCIDM_FTPOPTIONS: { VARIANT varArgs = {0}; varArgs.vt = VT_I4; varArgs.lVal = SBO_NOBROWSERPAGES; Exec(&CGID_Explorer, SBCMDID_OPTIONS, 0, &varArgs, NULL); } break; case FCIDM_BROWSEROPTIONS: if (!IsBrowserFrameOptionsSet(_pbbd->_psf, BFO_RENAME_FOLDER_OPTIONS_TOINTERNET) || !SHIsRestricted2W(_pbbd->_hwnd, REST_NoBrowserOptions, NULL, 0)) Exec(&CGID_Explorer, SBCMDID_OPTIONS, 0, NULL, NULL); break; case FCIDM_RESETWEBSETTINGS: ResetWebSettings(_pbbd->_hwnd, NULL); break; case FCIDM_MAIL: SHRunIndirectRegClientCommand(_pbbd->_hwnd, MAIL_DEF_KEY); break; case FCIDM_MYCOMPUTER: { LPITEMIDLIST pidlMyComputer; SHGetSpecialFolderLocation(NULL, CSIDL_DRIVES, &pidlMyComputer); if (pidlMyComputer) { BrowseObject(pidlMyComputer, SBSP_SAMEBROWSER); ILFree(pidlMyComputer); } } break; case FCIDM_CONTACTS: SHRunIndirectRegClientCommand(_pbbd->_hwnd, CONTACTS_DEF_KEY); break; case FCIDM_NEWS: SHRunIndirectRegClientCommand(_pbbd->_hwnd, NEWS_DEF_KEY); break; case FCIDM_CALENDAR: SHRunIndirectRegClientCommand(_pbbd->_hwnd, CALENDAR_DEF_KEY); break; case FCIDM_TASKS: SHRunIndirectRegClientCommand(_pbbd->_hwnd, TASKS_DEF_KEY); break; case FCIDM_JOURNAL: SHRunIndirectRegClientCommand(_pbbd->_hwnd, JOURNAL_DEF_KEY); break; case FCIDM_NOTES: SHRunIndirectRegClientCommand(_pbbd->_hwnd, NOTES_DEF_KEY); break; case FCIDM_CALL: SHRunIndirectRegClientCommand(_pbbd->_hwnd, CALL_DEF_KEY); break; case FCIDM_NEWMESSAGE: DropOnMailRecipient(NULL, 0); break; case FCIDM_SENDLINK: case FCIDM_SENDDOCUMENT: _SendCurrentPage(idCmd == FCIDM_SENDDOCUMENT ? FORCE_COPY : FORCE_LINK); break; case FCIDM_STARTPAGE: case FCIDM_UPDATEPAGE: case FCIDM_CHANNELGUIDE: { LPITEMIDLIST pidl = NULL; ASSERT(IDP_START == 0); ASSERT(FCIDM_STARTPAGE+IDP_START == FCIDM_STARTPAGE); ASSERT(FCIDM_STARTPAGE+IDP_UPDATE == FCIDM_UPDATEPAGE); ASSERT(FCIDM_STARTPAGE+IDP_CHANNELGUIDE == FCIDM_CHANNELGUIDE); HRESULT hres = SHDGetPageLocation(_pbbd->_hwnd, idCmd-FCIDM_STARTPAGE, NULL, 0, &pidl); if (SUCCEEDED(hres)) { hres = BrowseObject(pidl, SBSP_SAMEBROWSER); ILFree(pidl); } } break; case FCIDM_SEARCHPAGE: { // This command from the Windows Explorer's Go menu used to be handled by navigating to // a search page on MSN. We now maintain consistency with the shell's handling of // Start->Find->On the Internet, by invoking the extension directly. ASSERT(FCIDM_STARTPAGE+IDP_SEARCH == FCIDM_SEARCHPAGE); IContextMenu *pcm; HRESULT hres = CoCreateInstance(CLSID_WebSearchExt, NULL, CLSCTX_INPROC_SERVER, IID_IContextMenu, (void **) &pcm); if (SUCCEEDED(hres)) { CMINVOKECOMMANDINFO ici = {0}; ici.cbSize = sizeof(ici); ici.nShow = SW_NORMAL; pcm->InvokeCommand(&ici); pcm->Release(); } } break; case FCIDM_HELPABOUT: { TCHAR szWindows[64]; MLLoadString(IDS_WINDOWSNT, szWindows, ARRAYSIZE(szWindows)); ShellAbout(_pbbd->_hwnd, szWindows, NULL, NULL); break; } case FCIDM_HELPTIPOFTHEDAY: _SetBrowserBarState(-1, &CLSID_TipOfTheDay, -1); break; case FCIDM_HELPISLEGAL: { TCHAR szFWLinkPathTemplate[MAX_PATH]; TCHAR szFWLinkPath[MAX_PATH]; LPITEMIDLIST pidl; LoadString(HINST_THISDLL, IDS_FWLINK_HELPISLEGAL, szFWLinkPathTemplate, ARRAYSIZE(szFWLinkPathTemplate)); if (SUCCEEDED(URLSubstitution(szFWLinkPathTemplate, szFWLinkPath, ARRAYSIZE(szFWLinkPath), URLSUB_CLCID))) { if (SUCCEEDED(IEParseDisplayName(CP_ACP, szFWLinkPath, &pidl))) { BrowseObject(pidl, SBSP_SAMEBROWSER); ILFree(pidl); } } break; } case FCIDM_NAVIGATEBACK: if (_pbbd->_psvPending) { _CancelPendingView(); } else { if (g_dwStopWatchMode & (SPMODE_BROWSER | SPMODE_JAVA)) { DWORD dwTime = GetPerfTime(); if (g_dwStopWatchMode & SPMODE_BROWSER) // Used to get browser total download time StopWatch_StartTimed(SWID_BROWSER_FRAME, TEXT("Browser Frame Back"), SPMODE_BROWSER | SPMODE_DEBUGOUT, dwTime); if (g_dwStopWatchMode & SPMODE_JAVA) // Used to get java applet load time StopWatch_StartTimed(SWID_JAVA_APP, TEXT("Java Applet Back"), SPMODE_JAVA | SPMODE_DEBUGOUT, dwTime); } NavigateToPidl(NULL, HLNF_NAVIGATINGBACK); } break; case FCIDM_NAVIGATEFORWARD: NavigateToPidl(NULL, HLNF_NAVIGATINGFORWARD); break; case FCIDM_ADDTOFAVNOUI: Exec(&CGID_Explorer, SBCMDID_ADDTOFAVORITES, OLECMDEXECOPT_DONTPROMPTUSER, NULL, NULL); // Instrument this, add to favorites called by keyboard UEMFireEvent(&UEMIID_BROWSER, UEME_INSTRBROWSER, UEMF_INSTRUMENT, UIBW_ADDTOFAV, UIBL_KEYBOARD); break; // Some tools relied on the old Command ID... case FCIDM_W95REFRESH: idCmd = FCIDM_REFRESH; // Fall through... case FCIDM_REFRESH: if (TRUE == _fInRefresh) { // We are already doing a refresh. If we keep doing refreshes, // then we can enter into infinite recursion. If the refresh // cause a dialog to be displayed and refresh messages keep coming // in, then the messagebox call will be called over and over. // Besides multiple dialog boxes, this grows the stack until // we run out of space and crash. break; } _fInRefresh = TRUE; // fall thru... case FCIDM_STOP: { SHELLSTATE ss = {0}; SHGetSetSettings(&ss, SSF_MAPNETDRVBUTTON, FALSE); if ((!_fShowNetworkButtons && ss.fMapNetDrvBtn) || (_fShowNetworkButtons && !ss.fMapNetDrvBtn)) { UINT uiBtnState = 0; _fShowNetworkButtons = ss.fMapNetDrvBtn; _pxtb->GetState(&CLSID_CommonButtons, TBIDM_CONNECT, &uiBtnState); if (ss.fMapNetDrvBtn) uiBtnState &= ~TBSTATE_HIDDEN; else uiBtnState |= TBSTATE_HIDDEN; _pxtb->SetState(&CLSID_CommonButtons, TBIDM_CONNECT, uiBtnState); _pxtb->SetState(&CLSID_CommonButtons, TBIDM_DISCONNECT, uiBtnState); } if (idCmd == FCIDM_REFRESH) { VARIANT v = {0}; v.vt = VT_I4; v.lVal = OLECMDIDF_REFRESH_NO_CACHE|OLECMDIDF_REFRESH_PROMPTIFOFFLINE; Exec(NULL, OLECMDID_REFRESH, OLECMDEXECOPT_DONTPROMPTUSER, &v, NULL); // Refresh the toolbar if (_pxtb) { IServiceProvider* psp; if (SUCCEEDED(_pxtb->QueryInterface(IID_PPV_ARG(IServiceProvider, &psp)))) { IAddressBand *pab = NULL; if (SUCCEEDED(psp->QueryService(IID_IAddressBand, IID_IAddressBand, (void**)&pab))) { VARIANTARG varType = {0}; varType.vt = VT_I4; varType.lVal = OLECMD_REFRESH_TOPMOST; pab->Refresh(&varType); pab->Release(); } psp->Release(); } } } else { if (g_dwStopWatchMode & SPMODE_BROWSER) StopWatch_Lap(SWID_BROWSER_FRAME | SWID_MASK_BROWSER_STOPBTN, TEXT("Browser Frame Esc"), SPMODE_BROWSER | SPMODE_DEBUGOUT); Exec(NULL, OLECMDID_STOP, OLECMDEXECOPT_DONTPROMPTUSER, NULL, NULL); } if (FCIDM_REFRESH == idCmd) { _fInRefresh = FALSE; } break; } #ifndef DISABLE_FULLSCREEN case FCIDM_THEATER: if (!SHRestricted2(REST_NoTheaterMode, NULL, 0)) { // Toggle theater mode. Don't allow theater mode if we're in kiosk mode. if (_ptheater || _fKioskMode) { _TheaterMode(FALSE, TRUE); } else { _TheaterMode(TRUE, FALSE); } } break; #endif case FCIDM_NEXTCTL: _CycleFocus(NULL); break; case FCIDM_VIEWOFFLINE: if ((!SHIsGlobalOffline()) && (IsCriticalOperationPending())) { if (MLShellMessageBox(_pbbd->_hwnd, MAKEINTRESOURCE(IDS_CANCELFILEDOWNLOAD), MAKEINTRESOURCE(IDS_FILEDOWNLOADCAPTION), MB_YESNO | MB_ICONSTOP) == IDNO) break; } Offline(SBSC_TOGGLE); if (_pbbd->_pszTitleCur) _SetTitle(_pbbd->_pszTitleCur); break; #ifdef TEST_AMBIENTS case FCIDM_VIEWLOCALOFFLINE: _LocalOffline(SBSC_TOGGLE); break; case FCIDM_VIEWLOCALSILENT: _LocalSilent(SBSC_TOGGLE); break; #endif // TEST_AMBIENTS case FCIDM_VIEWTOOLBAR: v_ShowControl(FCW_INTERNETBAR, SBSC_TOGGLE); break; case FCIDM_VIEWMENU: id = CITIDM_VIEWMENU; goto ITBarShowBand; case FCIDM_VIEWTOOLS: id = CITIDM_VIEWTOOLS; goto ITBarShowBand; case FCIDM_VIEWADDRESS: id = CITIDM_VIEWADDRESS; goto ITBarShowBand; case FCIDM_VIEWLINKS: id = CITIDM_VIEWLINKS; goto ITBarShowBand; ITBarShowBand: if (!SHIsRestricted2W(_pbbd->_hwnd, REST_NoToolbarOptions, NULL, 0)) IUnknown_Exec(_GetITBar(), &CGID_PrivCITCommands, id, 0, NULL, NULL); break; case FCIDM_VIEWSTATUSBAR: v_ShowControl(FCW_STATUS, SBSC_TOGGLE); break; case FCIDM_VBBSEARCHBAND: { IDockingWindow* ptbar = _GetToolbarItem(ITB_ITBAR)->ptbar; VARIANT var = {0}; var.vt = VT_I4; var.lVal = -1; IUnknown_Exec(ptbar, &CLSID_CommonButtons, TBIDM_SEARCH, 0, NULL, &var); } break; case FCIDM_VIEW_PRIVACY_POLICIES: { if ( _pbbd != NULL && _pbbd->_pctView != NULL) { HRESULT hr = _pbbd->_pctView->Exec(&CGID_ShellDocView, SHDVID_PRIVACYSTATUS, TRUE, NULL, NULL); } } break; case FCIDM_VBBEXPLORERBAND: case FCIDM_VBBFAVORITESBAND: case FCIDM_VBBHISTORYBAND: case FCIDM_VBBMEDIABAND: if (g_dwStopWatchMode) { StopWatch_Start(SWID_EXPLBAR, TEXT("Shell bar Start"), SPMODE_SHELL | SPMODE_DEBUGOUT); } switch (idCmd) { case FCIDM_VBBFAVORITESBAND: if (SHIsRestricted2W(_pbbd->_hwnd, REST_NoFavorites, NULL, 0)) break; default: _SetBrowserBarState(idCmd, NULL, -1); break; } if (g_dwStopWatchMode) { TCHAR szText[100]; TCHAR szMenu[32]; DWORD dwTime = GetPerfTime(); GetMenuString(_GetMenuFromID(FCIDM_MENU_VIEW), idCmd, szMenu, ARRAYSIZE(szMenu) - 1, MF_BYCOMMAND); StringCchPrintf(szText, ARRAYSIZE(szText), TEXT("Shell %s bar Stop"), szMenu); // truncation ok since this is for display only StopWatch_StopTimed(SWID_EXPLBAR, (LPCTSTR)szText, SPMODE_SHELL | SPMODE_DEBUGOUT, dwTime); } break; case FCIDM_JAVACONSOLE: DL_ShowJavaConsole(); break; case FCIDM_SHOWSCRIPTERRDLG: { HRESULT hr; hr = Exec(&CGID_ShellDocView, SHDVID_DISPLAYSCRIPTERRORS, 0, NULL, NULL); return hr; } break; default: if (IsInRange(idCmd, FCIDM_FAVORITECMDFIRST, FCIDM_FAVORITECMDLAST) && !SHIsRestricted2W(_pbbd->_hwnd, REST_NoFavorites, NULL, 0)) { _FavoriteOnCommand(NULL, idCmd); } else if (IsInRange(idCmd, FCIDM_RECENTFIRST, FCIDM_RECENTLAST)) { ITravelLog *ptl; GetTravelLog(&ptl); if (ptl) { ptl->Travel(SAFECAST(this, IShellBrowser *), idCmd - (FCIDM_RECENTFIRST + GOMENU_RECENT_ITEMS) + GOMENU_RECENT_ITEMS / 2); ptl->Release(); UpdateBackForwardState(); } } else if (IsInRange(idCmd, FCIDM_SEARCHFIRST, FCIDM_SEARCHLAST)) { if (_pcmSearch) { CMINVOKECOMMANDINFO ici = {0}; ici.cbSize = sizeof(ici); //ici.hwnd = NULL; // no need for hwnd for search cm InvokeCommand ici.lpVerb = (LPSTR)MAKEINTRESOURCE(idCmd - FCIDM_SEARCHFIRST); ici.nShow = SW_NORMAL; _pcmSearch->InvokeCommand(&ici); } else { TraceMsg(DM_TRACE, "CSB::OnCommand() - find cmd with NULL pcmFind"); } } else if (IsInRange(idCmd, FCIDM_MENU_TOOLS_FINDFIRST, FCIDM_MENU_TOOLS_FINDLAST)) { if (GetUIVersion() < 5 && _pcmFind) { LPITEMIDLIST pidl = (_pbbd->_pidlPending) ? _pbbd->_pidlPending : _pbbd->_pidlCur; TCHAR szPath[MAX_PATH]; SHGetNameAndFlags(pidl, SHGDN_FORPARSING, szPath, SIZECHARS(szPath), NULL); // Handle cases like "desktop" (make it default to My Computer) if (!PathIsDirectory(szPath)) { szPath[0] = TEXT('\0'); } CMINVOKECOMMANDINFO ici = {0}; ici.cbSize = sizeof(ici); //ici.hwnd = NULL; // no need for hwnd for search cm InvokeCommand ici.lpVerb = (LPSTR)MAKEINTRESOURCE(idCmd - FCIDM_MENU_TOOLS_FINDFIRST); ici.nShow = SW_NORMAL; // Set the root of the search char szAnsiPath[MAX_PATH]; szAnsiPath[0] = '\0'; SHTCharToAnsi(szPath, szAnsiPath, ARRAYSIZE(szAnsiPath)); ici.lpDirectory = szAnsiPath; _pcmFind->InvokeCommand(&ici); } } else if (IsInRange(idCmd, FCIDM_VBBDYNFIRST, FCIDM_VBBDYNLAST)) { _SetBrowserBarState(idCmd, NULL, -1); } else if (IsInRange(idCmd, FCIDM_FILECTX_FIRST, FCIDM_FILECTX_LAST)) { _ExecFileContext(idCmd); } else if (IsInRange(idCmd, FCIDM_EXTERNALBANDS_FIRST, FCIDM_EXTERNALBANDS_LAST)) { id = idCmd - FCIDM_EXTERNALBANDS_FIRST + CITIDM_VIEWEXTERNALBAND_FIRST; IUnknown_Exec(_GetITBar(), &CGID_PrivCITCommands, id, 0, NULL, NULL); } else { SUPERCLASS::OnCommand(wParam, lParam); } break; } return S_OK; } HMENU CShellBrowser2::_GetMenuFromID(UINT uID) { return SHGetMenuFromID(_hmenuCur, uID); } void CShellBrowser2::_PruneMailNewsItems(HMENU hmenu) { // // REARCHITECT: this logic is duplicated in _OnFileMenuPopup, // _OnMailMenuPopup, CDocObjectHost::_OnInitMenuPopup // // Iterate through the mail, news, contacts, etc. menu items, // and for each item, remove the item if either // // (a) REST_GoMenu is set, or // (b) the item has no registered client // // If all items are removed, remember to remove the separator too. // static const struct { DWORD dwCmd; LPCTSTR pszClient; } c_mailnewsitems[] = { { FCIDM_MAIL, MAIL_DEF_KEY }, { FCIDM_NEWS, NEWS_DEF_KEY }, { FCIDM_CONTACTS, CONTACTS_DEF_KEY }, { FCIDM_CALENDAR, CALENDAR_DEF_KEY }, { FCIDM_TASKS, TASKS_DEF_KEY }, { FCIDM_JOURNAL, JOURNAL_DEF_KEY }, { FCIDM_NOTES, NOTES_DEF_KEY }, { FCIDM_CALL, CALL_DEF_KEY }, }; BOOL fGoRestricted = SHRestricted2(REST_GoMenu, NULL, 0); for (int i = 0; i < ARRAYSIZE(c_mailnewsitems); i++) { if (fGoRestricted || !SHIsRegisteredClient(c_mailnewsitems[i].pszClient)) { DeleteMenu(hmenu, c_mailnewsitems[i].dwCmd, MF_BYCOMMAND); } } _SHPrettyMenu(hmenu); // to ensure separator is removed if necessary } void CShellBrowser2::_ExecFileContext(UINT idCmd) { if (_pcmNsc) { CMINVOKECOMMANDINFO ici = { sizeof(CMINVOKECOMMANDINFO), 0L, _pbbd->_hwnd, MAKEINTRESOURCEA(idCmd-FCIDM_FILECTX_FIRST), NULL, NULL, SW_NORMAL, }; _pcmNsc->InvokeCommand(&ici); // It's no good after an invoke... IUnknown_SetSite(_pcmNsc, NULL); ATOMICRELEASE(_pcmNsc); } } void CShellBrowser2::_EnableFileContext(HMENU hmenuPopup) { IContextMenu2 *pcm = NULL; OLECMDTEXTV cmdtv; OLECMDTEXT *pcmdText = &cmdtv; // First clean up any previous merge we may have done DeleteMenu(hmenuPopup, FCIDM_FILENSCBANDSEP, MF_BYCOMMAND); DeleteMenu(hmenuPopup, FCIDM_FILENSCBANDPOPUP, MF_BYCOMMAND); IUnknown_SetSite(_pcmNsc, NULL); ATOMICRELEASE(_pcmNsc); // Second, get the name and pcm for the NSC selection, if available if (_poctNsc) { OLECMD rgcmd = { SBCMDID_INITFILECTXMENU, 0 }; pcmdText->cwBuf = MAX_FILECONTEXT_STRING; pcmdText->cmdtextf = OLECMDTEXTF_NAME; pcmdText->rgwz[0] = 0; _poctNsc->QueryStatus(&CGID_Explorer, 1, &rgcmd, pcmdText); if (rgcmd.cmdf & OLECMDF_ENABLED) { VARIANT var = {0}; HRESULT hr = _poctNsc->Exec(&CGID_Explorer, SBCMDID_INITFILECTXMENU, OLECMDEXECOPT_PROMPTUSER, NULL, &var); if (SUCCEEDED(hr) && VT_UNKNOWN == var.vt && NULL != var.punkVal) { var.punkVal->QueryInterface(IID_PPV_ARG(IContextMenu2, &pcm)); } VariantClearLazy(&var); } } // Third, merge the menu in if we got it if (pcm) { HMENU hmenu = CreatePopupMenu(); if (hmenu) { IUnknown_SetSite(pcm, _poctNsc); HRESULT hr = pcm->QueryContextMenu(hmenu, 0, FCIDM_FILECTX_FIRST, FCIDM_FILECTX_LAST, CMF_EXPLORE); if (SUCCEEDED(hr)) { UINT nInsert = SHMenuIndexFromID(hmenuPopup, FCIDM_VIEWOFFLINE); if (-1 == nInsert) nInsert = SHMenuIndexFromID(hmenuPopup, FCIDM_FILECLOSE); if (-1 == nInsert) nInsert = GetMenuItemCount(hmenuPopup); MENUITEMINFO mii = {0}; mii.cbSize = sizeof(mii); mii.fMask = MIIM_ID | MIIM_TYPE; mii.fType = MFT_SEPARATOR; mii.wID = FCIDM_FILENSCBANDSEP; InsertMenuItem(hmenuPopup, nInsert, MF_BYPOSITION, &mii); // BUGBUG: "&" is a legal UI name, we need to map this to "&&" or whatever the menu escape sequence is... mii.fMask = MIIM_ID | MIIM_TYPE | MIIM_SUBMENU; mii.fType = MFT_STRING; mii.hSubMenu = hmenu; mii.dwTypeData = pcmdText->rgwz; mii.wID = FCIDM_FILENSCBANDPOPUP; InsertMenuItem(hmenuPopup, nInsert, MF_BYPOSITION, &mii); _pcmNsc = pcm; _pcmNsc->AddRef(); } else { IUnknown_SetSite(pcm, NULL); } if (FAILED(hr)) DestroyMenu(hmenu); } pcm->Release(); } } void CShellBrowser2::_MungeGoMyComputer(HMENU hmenuPopup) { //need to have a menu item My Computer but a user might have changed //it to something else so go get the new name LPITEMIDLIST pidlMyComputer; TCHAR szBuffer[MAX_PATH]; //buffer to hold menu item string TCHAR szMenuText[MAX_PATH+1+6]; SHGetSpecialFolderLocation(NULL, CSIDL_DRIVES, &pidlMyComputer); if (pidlMyComputer) { if (SUCCEEDED(SHGetNameAndFlags(pidlMyComputer, SHGDN_NORMAL, szMenuText, SIZECHARS(szMenuText), NULL))) { MENUITEMINFO mii; mii.cbSize = sizeof(MENUITEMINFO); mii.fMask = MIIM_TYPE; mii.fType = MFT_STRING; mii.dwTypeData = szBuffer; mii.cch = ARRAYSIZE(szBuffer); if (GetMenuItemInfoWrap(hmenuPopup, FCIDM_MYCOMPUTER, FALSE, &mii)) { LPTSTR pszHot; LPTSTR pszMenuItem = (LPTSTR) mii.dwTypeData; //before we get rid of the old name, need to get //the hot key for it //check if the old name had a hot key //StrChr is defined in shlwapi (strings.c) and accepts word even in ascii version if (NULL != (pszHot = StrChr(pszMenuItem, (WORD)TEXT('&')))) { //yes LPTSTR psz; pszHot++; //make it point to the hot key, not & //try to find the key in the new string if (NULL == (psz = StrChr(szMenuText, (WORD)*pszHot))) { //not found, then we'll insert & at the beginning of the new string psz = szMenuText; } // can't put hotkey to full width characters // and some of japanese specific half width chars. // the comparison BOOL fFEmnemonic = FALSE; if (g_fRunOnFE) { WORD wCharType[2]; // if built Ansi it takes max. 2 bytes to determine if // the given character is full width. // DEFAULT_SYSTEM_LOCALE has to change when we have a way // to get current UI locale. // GetStringTypeEx(LOCALE_SYSTEM_DEFAULT, CT_CTYPE3, psz, sizeof(WCHAR)/sizeof(TCHAR), wCharType); if ((wCharType[0] & C3_FULLWIDTH) ||(wCharType[0] & C3_KATAKANA) ||(wCharType[0] & C3_IDEOGRAPH) ||((wCharType[0] & C3_ALPHA) && !(wCharType[0] & C3_HALFWIDTH))) { fFEmnemonic = TRUE; } } if (fFEmnemonic) { size_t lenMenuText = lstrlen(szMenuText); if (lenMenuText + 4 < ARRAYSIZE(szMenuText)) { szMenuText[lenMenuText + 0] = TEXT('('); szMenuText[lenMenuText + 1] = TEXT('&'); szMenuText[lenMenuText + 2] = *pszHot; szMenuText[lenMenuText + 3] = TEXT(')'); szMenuText[lenMenuText + 4] = NULL; } } else { //make space for & to be inserted if (lstrlen(szMenuText) + 1 < ARRAYSIZE(szMenuText)) { memmove(psz+1, psz, (lstrlen(psz)+1) * sizeof(TCHAR)); psz[0] = TEXT('&'); } } } mii.dwTypeData = szMenuText; SetMenuItemInfo(hmenuPopup, FCIDM_MYCOMPUTER, FALSE, &mii); } } ILFree(pidlMyComputer); } } inline BOOL IsWebPidl(LPCITEMIDLIST pidl) { return (!pidl || ILIsWeb(pidl)); } void CShellBrowser2::_InsertTravelLogItems(HMENU hmenu, int nPos) { ITravelLog *ptl; GetTravelLog(&ptl); if (!ptl) return; //add the back items to the menu MENUITEMINFO mii = {0}; mii.cbSize = sizeof(MENUITEMINFO); mii.fMask = MIIM_ID | MIIM_TYPE; //delete all back menu items after the separator for (int i=GetMenuItemCount(hmenu); i >=0; i--) { mii.cch = 0; if (GetMenuItemInfoWrap(hmenu, i, TRUE, &mii) && IsInRange(mii.wID, FCIDM_RECENTMENU, FCIDM_RECENTLAST)) { DeleteMenu(hmenu, i, MF_BYPOSITION); if (i < nPos) nPos--; } } //add the items if (S_OK == ptl->InsertMenuEntries(SAFECAST(this, IShellBrowser*), hmenu, nPos, FCIDM_RECENTFIRST, FCIDM_RECENTFIRST + GOMENU_RECENT_ITEMS, TLMENUF_CHECKCURRENT | TLMENUF_BACKANDFORTH)) { //if something was added, insert a separator MENUITEMINFO mii = {0}; mii.cbSize = sizeof(MENUITEMINFO); mii.fMask = MIIM_ID | MIIM_TYPE; mii.fType = MFT_SEPARATOR; mii.wID = FCIDM_RECENTMENU; InsertMenuItem(hmenu, nPos, TRUE, &mii); } ptl->Release(); } void CShellBrowser2::_OnGoMenuPopup(HMENU hmenuPopup) { ITravelLog *ptl; GetTravelLog(&ptl); // if we've got a site or if we're trying to get to a site, // enable the back button BOOL fBackward = (ptl ? S_OK == ptl->GetTravelEntry(SAFECAST(this, IShellBrowser *), TLOG_BACK, NULL) : FALSE); _EnableMenuItem(hmenuPopup, FCIDM_NAVIGATEBACK, fBackward); BOOL fForeward = (ptl ? S_OK == ptl->GetTravelEntry(SAFECAST(this, IShellBrowser *), TLOG_FORE, NULL) : FALSE); _EnableMenuItem(hmenuPopup, FCIDM_NAVIGATEFORWARD, fForeward); if (IsBrowserFrameOptionsSet(_pbbd->_psf, BFO_NO_PARENT_FOLDER_SUPPORT) || SHRestricted2W(REST_GoMenu, NULL, 0)) { DeleteMenu(hmenuPopup, FCIDM_PREVIOUSFOLDER, MF_BYCOMMAND); } else _EnableMenuItem(hmenuPopup, FCIDM_PREVIOUSFOLDER, _ShouldAllowNavigateParent()); ATOMICRELEASE(ptl); if (SHRestricted2(REST_NoChannelUI, NULL, 0)) DeleteMenu(hmenuPopup, FCIDM_CHANNELGUIDE, MF_BYCOMMAND); _MungeGoMyComputer(hmenuPopup); _PruneMailNewsItems(hmenuPopup); // if in ie4 shell browser we leave travel log in the file menu if ((GetUIVersion() >= 5 || !_pbbd->_psf || IsBrowserFrameOptionsSet(_pbbd->_psf, BFO_GO_HOME_PAGE))) { // The travel log goes after "Home Page". int nPos = GetMenuPosFromID(hmenuPopup, FCIDM_STARTPAGE) + 1; // If "Home Page" isn't there, then just append to the end. if (nPos <= 0) { nPos = GetMenuItemCount(hmenuPopup); } _InsertTravelLogItems(hmenuPopup, nPos); } } HRESULT AssureFtpOptionsMenuItem(HMENU hmenuPopup) { HRESULT hr = S_OK; // Append the item if it is missing. It can be missing because // sometimes the menu will be displayed before the shell merges it's // menus, so we are modifying the template that will be used for other // pages. if (GetMenuPosFromID(hmenuPopup, FCIDM_FTPOPTIONS) == 0xFFFFFFFF) { // Yes, it's missing so we need to add it. int nToInsert = GetMenuPosFromID(hmenuPopup, FCIDM_BROWSEROPTIONS); if (EVAL(0xFFFFFFFF != nToInsert)) { TCHAR szInternetOptions[64]; MLLoadString(IDS_INTERNETOPTIONS, szInternetOptions, ARRAYSIZE(szInternetOptions)); MENUITEMINFO mii = {0}; mii.cbSize = sizeof(mii); mii.fMask = (MIIM_TYPE | MIIM_STATE | MIIM_ID); mii.fType = MFT_STRING; mii.fState = MFS_ENABLED | MFS_UNCHECKED; mii.wID = FCIDM_FTPOPTIONS; mii.dwTypeData = szInternetOptions; mii.cch = lstrlen(szInternetOptions); // We want to go right after "Folder Options" so we found // the spot. TBOOL(InsertMenuItem(hmenuPopup, (nToInsert + 1), TRUE, &mii)); // REARCHITECT: The PMs finally decided that // it would be good to always have "Inet Options" & "Folder Options" // in all views. (FTP, Shell, & Web) However doing it now // is too late so we want to do this later. When that is done // we can get ride of all this stuff. // Now we just want to make sure FCIDM_BROWSEROPTIONS is "Folder Options" // because some users over load it to say "Internet Options" which // just added above. So we want to force it back to "Folder Options". if (GetMenuItemInfo(hmenuPopup, FCIDM_BROWSEROPTIONS, FALSE, &mii)) { TCHAR szFolderOptions[MAX_PATH]; MLLoadString(IDS_FOLDEROPTIONS, szFolderOptions, ARRAYSIZE(szFolderOptions)); mii.dwTypeData = szFolderOptions; mii.cch = lstrlen(szFolderOptions); SetMenuItemInfo(hmenuPopup, FCIDM_BROWSEROPTIONS, FALSE, &mii); } } else { hr = E_FAIL; } } return hr; } HRESULT UpdateOptionsMenuItem(IShellFolder * psf, HMENU hmenuPopup, BOOL fForNT5) { BOOL fCorrectVersion; if (fForNT5) fCorrectVersion = (GetUIVersion() >= 5); else fCorrectVersion = (GetUIVersion() < 5); // We want "Internet Options" in addition to "Folder Options" on // NT5's Tools menu for FTP Folders. Is this the case? if (fCorrectVersion && IsBrowserFrameOptionsSet(psf, BFO_BOTH_OPTIONS)) { EVAL(SUCCEEDED(AssureFtpOptionsMenuItem(hmenuPopup))); } else { // No, so delete the item. DeleteMenu(hmenuPopup, FCIDM_FTPOPTIONS, MF_BYCOMMAND); } return S_OK; } void CShellBrowser2::_OnViewMenuPopup(HMENU hmenuPopup) { OLECMD rgcmd[] = { { CITIDM_VIEWTOOLS, 0 }, { CITIDM_VIEWADDRESS, 0 }, { CITIDM_VIEWLINKS, 0 }, { CITIDM_VIEWTOOLBARCUSTOMIZE, 0 }, { CITIDM_VIEWMENU, 0 }, { CITIDM_VIEWAUTOHIDE, 0 }, { CITIDM_TEXTLABELS, 0 }, { CITIDM_VIEWLOCKTOOLBAR, 0 }, }; UpdateOptionsMenuItem(_pbbd->_psf, hmenuPopup, FALSE); // See _MenuTemplate for the kooky enable/disable scenarios. // Today's kookiness: The ever-changing "Options" menuitem. // According to the table, we want Options under View on // Non-NT5, in the shell or FTP scenarios. Therefore, we want // options deleted in the opposite scenario. And for good measure, // we also delete it if we don't know who we are yet, or if we // are restricted. if (SHRestricted(REST_NOFOLDEROPTIONS) || (GetUIVersion() >= 5) || !_pbbd->_pidlCur || IsBrowserFrameOptionsSet(_pbbd->_psf, BFO_RENAME_FOLDER_OPTIONS_TOINTERNET)) { DeleteMenu(hmenuPopup, FCIDM_BROWSEROPTIONS, MF_BYCOMMAND); } if (SHRestricted2(REST_NoViewSource, NULL, 0)) _EnableMenuItem(hmenuPopup, DVIDM_MSHTML_FIRST+IDM_VIEWSOURCE, FALSE); if (_GetToolbarItem(ITB_ITBAR)->fShow) { IUnknown_QueryStatus(_GetITBar(), &CGID_PrivCITCommands, ARRAYSIZE(rgcmd), rgcmd, NULL); } HMENU hmenuToolbar = LoadMenuPopup(MENU_ITOOLBAR); MENUITEMINFO mii; mii.cbSize = sizeof(mii); mii.fMask = MIIM_SUBMENU; mii.hSubMenu = hmenuToolbar; // why _hmenuCur? why not hmenuPopup? SetMenuItemInfo(_hmenuCur, FCIDM_VIEWTOOLBAR, FALSE, &mii); _CheckMenuItem(hmenuToolbar, FCIDM_VIEWADDRESS, rgcmd[1].cmdf & OLECMDF_ENABLED); _CheckMenuItem(hmenuToolbar, FCIDM_VIEWLINKS, rgcmd[2].cmdf & OLECMDF_ENABLED); int cItemsBelowSep = 3; BOOL fCustomizeAvailable = TRUE; if (!(rgcmd[3].cmdf & OLECMDF_ENABLED)) { DeleteMenu(hmenuToolbar, FCIDM_VIEWTOOLBARCUSTOMIZE, MF_BYCOMMAND); fCustomizeAvailable = FALSE; cItemsBelowSep--; } DeleteMenu(hmenuToolbar, FCIDM_VIEWGOBUTTON, MF_BYCOMMAND); if (fCustomizeAvailable || _ptheater || SHRestricted2(REST_LOCKICONSIZE, NULL, 0)) { DeleteMenu(hmenuToolbar, FCIDM_VIEWTEXTLABELS, MF_BYCOMMAND); cItemsBelowSep--; } else { _CheckMenuItem (hmenuToolbar, FCIDM_VIEWTEXTLABELS, rgcmd[6].cmdf); } if (_ptheater) { _CheckMenuItem (hmenuToolbar, FCIDM_VIEWMENU, rgcmd[4].cmdf); _CheckMenuItem (hmenuToolbar, FCIDM_VIEWAUTOHIDE, rgcmd[5].cmdf); DeleteMenu(hmenuToolbar, FCIDM_VIEWTOOLS, MF_BYCOMMAND); } else { _CheckMenuItem(hmenuToolbar, FCIDM_VIEWTOOLS, rgcmd[0].cmdf & OLECMDF_ENABLED); DeleteMenu(hmenuToolbar, FCIDM_VIEWMENU, MF_BYCOMMAND); DeleteMenu(hmenuToolbar, FCIDM_VIEWAUTOHIDE, MF_BYCOMMAND); cItemsBelowSep--; } if (_ptheater || SHRestricted2(REST_NOBANDCUSTOMIZE, NULL, 0)) { // No lock in theater mode or Windows Explorer DeleteMenu(hmenuToolbar, FCIDM_VIEWLOCKTOOLBAR, MF_BYCOMMAND); } else { _CheckMenuItem(hmenuToolbar, FCIDM_VIEWLOCKTOOLBAR, rgcmd[7].cmdf & OLECMDF_ENABLED); } _CheckMenuItem(hmenuPopup, FCIDM_VIEWSTATUSBAR, v_ShowControl(FCW_STATUS, SBSC_QUERY) == SBSC_SHOW); #ifndef DISABLE_FULLSCREEN if (SHRestricted2(REST_NoTheaterMode, NULL, 0)) _EnableMenuItem(hmenuPopup, FCIDM_THEATER, FALSE); else _CheckMenuItem(hmenuPopup, FCIDM_THEATER, (_ptheater ? TRUE : FALSE)); #endif // if we're on nt5 OR we're not integrated and we're not in explorer // add browser bars to the view menu if (_GetBrowserBarMenu() == hmenuPopup) { _AddBrowserBarMenuItems(hmenuPopup); } // else it gets added only on view/explorer bars RestrictItbarViewMenu(hmenuPopup, _GetITBar()); if (!cItemsBelowSep) DeleteMenu(hmenuToolbar, FCIDM_VIEWCONTEXTMENUSEP, MF_BYCOMMAND); DWORD dwValue; DWORD dwSize = sizeof(dwValue); BOOL fDefault = FALSE; // Check the registry to see if we need to show the "Java Console" menu item. // SHRegGetUSValue(TEXT("Software\\Microsoft\\Java VM"), TEXT("EnableJavaConsole"), NULL, (LPBYTE)&dwValue, &dwSize, FALSE, (void *) &fDefault, sizeof(fDefault)); // If the value is false or absent, remove the menu item. // if (!dwValue) { RemoveMenu(hmenuPopup, FCIDM_JAVACONSOLE, MF_BYCOMMAND); } // Component categories cache can be passively (and efficiently) kept consistent through // a registry change notification in integrated platforms on NT and Win=>98. // both of these do an async update as necessary. if (g_fRunningOnNT && GetUIVersion() >= 5) { _QueryHKCRChanged(); } else if (!_fValidComCatCache) { // With browser-only, we'll refresh only if we haven't done so already. _fValidComCatCache = S_OK == _FreshenComponentCategoriesCache(TRUE /* unconditional update */) ; } IDispatch * pDispatch = NULL; IHTMLDocument2* pHTMLDocument = NULL; BSTR bstrUrl = NULL; if( SUCCEEDED(_pbbd->_pautoWB2->get_Document(&pDispatch)) && SUCCEEDED(pDispatch->QueryInterface(IID_PPV_ARG(IHTMLDocument2, &pHTMLDocument))) && pHTMLDocument != NULL && SUCCEEDED(pHTMLDocument->get_URL( &bstrUrl))) { bool fEnableViewPrivacyPolicies = (0 == StrNCmpI( bstrUrl, L"http", ARRAYSIZE(L"http")-1)); _EnableMenuItem( hmenuPopup, FCIDM_VIEW_PRIVACY_POLICIES, fEnableViewPrivacyPolicies); // if( !fEnableViewPrivacyPolicies) // DeleteMenu( hmenuPopup, FCIDM_VIEW_PRIVACY_POLICIES, MF_BYCOMMAND); } SAFERELEASE( pDispatch); SAFERELEASE( pHTMLDocument); SysFreeString( bstrUrl); bstrUrl = NULL; // prettify the menu (make sure first and last items aren't // separators and that there are no runs of >1 separator) _SHPrettyMenu(hmenuPopup); } void CShellBrowser2::_OnToolsMenuPopup(HMENU hmenuPopup) { // Party on tools->options // // Again _MenuTemplate has the gory details. We want to lose // "Options" in the non-NT5, shell or FTP scenarios, so we want // to keep it in the opposite case. (FTP is a freebie since FTP // doesn't have a Tools menu to begin with.) // // And don't forget restrictions. // And as a bonus, we have to change the name of the menuitem // in the web scenario to "Internet &Options". BOOL fWeb = IsWebPidl(_pbbd->_pidlCur); UpdateOptionsMenuItem(_pbbd->_psf, hmenuPopup, TRUE); // // Figure out whether or not "reset web settings" is needed // if (!fWeb || // only visible in web mode !IsResetWebSettingsEnabled() || // only if not disabled by the ieak !IsResetWebSettingsRequired()) // and only needed if someone clobbered our reg keys { DeleteMenu(hmenuPopup, FCIDM_RESETWEBSETTINGS, MF_BYCOMMAND); } DWORD dwOptions; GetBrowserFrameOptions(_pbbd->_psf, (BFO_RENAME_FOLDER_OPTIONS_TOINTERNET | BFO_BOTH_OPTIONS), &dwOptions); DWORD rgfAttrib = SFGAO_FOLDER; if (SHRestricted(REST_NOFOLDEROPTIONS) && SUCCEEDED(IEGetAttributesOf(_pbbd->_pidlCur, &rgfAttrib)) && (rgfAttrib & SFGAO_FOLDER)) { DeleteMenu(hmenuPopup, FCIDM_BROWSEROPTIONS, MF_BYCOMMAND); } else { // Only do this if the NSE wants it named "Internet Options" but doesn't want "Folder Options" // also. if (IsBrowserFrameOptionsSet(_pbbd->_psf, BFO_RENAME_FOLDER_OPTIONS_TOINTERNET)) { TCHAR szInternetOptions[64]; MLLoadString(IDS_INTERNETOPTIONS, szInternetOptions, ARRAYSIZE(szInternetOptions)); MENUITEMINFO mii; mii.cbSize = sizeof(mii); mii.fMask = MIIM_TYPE | MIIM_STATE | MIIM_ID; mii.fType = MFT_STRING; mii.fState = MFS_ENABLED | MFS_UNCHECKED; mii.dwTypeData = szInternetOptions; mii.cch = lstrlen(szInternetOptions); mii.wID = FCIDM_BROWSEROPTIONS; // Append the item if it is missing, else just set it if (GetMenuState(hmenuPopup, FCIDM_BROWSEROPTIONS, MF_BYCOMMAND) == 0xFFFFFFFF) { AppendMenu(hmenuPopup, MF_SEPARATOR, -1, NULL); InsertMenuItem(hmenuPopup, 0xFFFFFFFF, TRUE, &mii); } else { SetMenuItemInfo(hmenuPopup, FCIDM_BROWSEROPTIONS, FALSE, &mii); } } } // Nuke tools->connect through tools->disconnect if restricted or if no net if ((!(GetSystemMetrics(SM_NETWORK) & RNC_NETWORKS)) || SHRestricted(REST_NONETCONNECTDISCONNECT)) { for (int i = FCIDM_CONNECT; i <= FCIDM_CONNECT_SEP; i++) DeleteMenu(hmenuPopup, i, MF_BYCOMMAND); } // Nuke tools->find + sep if restricted or if UI version >= 5 // or if running rooted explorer (since the Find extensions assume // unrooted) if (SHRestricted(REST_NOFIND) || (GetUIVersion() >= 5)) { DeleteMenu(hmenuPopup, FCIDM_TOOLSSEPARATOR, MF_BYCOMMAND); DeleteMenu(hmenuPopup, FCIDM_MENU_FIND, MF_BYCOMMAND); } BOOL fAvailable; uCLSSPEC ucs; QUERYCONTEXT qc = { 0 }; MENUITEMINFO mii; ucs.tyspec = TYSPEC_CLSID; ucs.tagged_union.clsid = CLSID_SubscriptionMgr; // see if this option is available fAvailable = (SUCCEEDED(FaultInIEFeature(NULL, &ucs, &qc, FIEF_FLAG_PEEK))); if (fAvailable && !_fShowSynchronize) { // Turn it back on if (NULL != _pszSynchronizeText) { _fShowSynchronize = TRUE; mii.cbSize = sizeof(mii); mii.fMask = MIIM_TYPE | MIIM_ID; mii.fType = MFT_STRING; mii.wID = FCIDM_UPDATESUBSCRIPTIONS; mii.dwTypeData = _pszSynchronizeText; InsertMenuItem(hmenuPopup, _iSynchronizePos, MF_BYPOSITION, &mii); } } else if (!fAvailable && _fShowSynchronize) { // Turn it off int iSyncPos = GetMenuPosFromID(hmenuPopup, FCIDM_UPDATESUBSCRIPTIONS); if (NULL == _pszSynchronizeText) { _iSynchronizePos = iSyncPos; MENUITEMINFO mii; TCHAR szBuf[MAX_PATH]; mii.cbSize = sizeof(mii); mii.fMask = MIIM_TYPE | MIIM_ID; mii.dwTypeData = szBuf; mii.cch = ARRAYSIZE(szBuf); if (GetMenuItemInfo(hmenuPopup, FCIDM_UPDATESUBSCRIPTIONS, MF_BYCOMMAND, &mii)) { Str_SetPtr(&_pszSynchronizeText, (LPTSTR)mii.dwTypeData); } } DeleteMenu(hmenuPopup, FCIDM_UPDATESUBSCRIPTIONS, MF_BYCOMMAND); _fShowSynchronize = FALSE; } ASSERT((fAvailable && _fShowSynchronize) || (!fAvailable && !_fShowSynchronize)); if (SHRestricted2(REST_NoWindowsUpdate, NULL, 0)) { DeleteMenu(hmenuPopup, (DVIDM_HELPMSWEB+2), MF_BYCOMMAND); } else { DWORD dwRet; DWORD dwType; DWORD dwSize; TCHAR szNewUpdateName[MAX_PATH]; // check to see if "Windows Update" should be called // something different in the menu dwSize = sizeof(szNewUpdateName); dwRet = SHRegGetUSValue(c_szMenuItemCust, c_szWindowUpdateName, &dwType, (LPVOID)szNewUpdateName, &dwSize, FALSE, NULL, 0); if (dwRet == ERROR_SUCCESS) { ASSERT(dwSize <= sizeof(szNewUpdateName)); ASSERT(szNewUpdateName[(dwSize/sizeof(TCHAR))-1] == TEXT('\0')); // if we got anything, replace the menu item's text, or delete // the item if the text was NULL. we can tell if the text was // an empty string by seeing whether we got back more // bytes than just a null terminator if (dwSize > sizeof(TCHAR)) { MENUITEMINFO mii; mii.cbSize = sizeof(mii); mii.fMask = MIIM_TYPE; mii.fType = MFT_STRING; mii.dwTypeData = szNewUpdateName; SetMenuItemInfo(hmenuPopup, FCIDM_PRODUCTUPDATES, FALSE, &mii); } else { ASSERT(dwSize == 0); DeleteMenu(hmenuPopup, FCIDM_PRODUCTUPDATES, MF_BYCOMMAND); } } } // Disable Mail and News submenu if we don't support it OLECMD rgcmd[] = { { SBCMDID_DOMAILMENU, 0 }, }; HRESULT hr = QueryStatus(&CGID_Explorer, ARRAYSIZE(rgcmd), rgcmd, NULL); _EnableMenuItem(hmenuPopup, FCIDM_MAILANDNEWS, SUCCEEDED(hr) && (rgcmd[0].cmdf & OLECMDF_ENABLED)); // prettify the menu (make sure first and last items aren't // separators and that there are no runs of >1 separator) _SHPrettyMenu(hmenuPopup); } void CShellBrowser2::_OnFileMenuPopup(HMENU hmenuPopup) { // disable create shortcut, rename, delete, and properties // we'll enable them bellow if they are available _EnableMenuItem(hmenuPopup, FCIDM_DELETE, FALSE); _EnableMenuItem(hmenuPopup, FCIDM_PROPERTIES, FALSE); _EnableMenuItem(hmenuPopup, FCIDM_RENAME, FALSE); _EnableMenuItem(hmenuPopup, FCIDM_LINK, FALSE); if (SHRestricted2(REST_NoExpandedNewMenu, NULL, 0) && (GetMenuState(hmenuPopup, DVIDM_NEW, MF_BYCOMMAND) != 0xFFFFFFFF)) { TCHAR szNewWindow[64]; MLLoadString(IDS_NEW_WINDOW, szNewWindow, ARRAYSIZE(szNewWindow)); MENUITEMINFO mii; mii.cbSize = sizeof(MENUITEMINFO); mii.fMask = MIIM_ID | MIIM_TYPE; mii.fType = MFT_STRING; mii.fState = MFS_ENABLED; mii.wID = DVIDM_NEWWINDOW; mii.dwTypeData = szNewWindow; mii.cch = lstrlen(szNewWindow); InsertMenuItem(hmenuPopup, DVIDM_NEW, FALSE, &mii); DeleteMenu(hmenuPopup, DVIDM_NEW, MF_BYCOMMAND); } if (_HasToolbarFocus()) { OLECMD rgcmd[] = { { SBCMDID_FILEDELETE, 0 }, { SBCMDID_FILEPROPERTIES, 0 }, { SBCMDID_FILERENAME, 0}, { SBCMDID_CREATESHORTCUT, 0}, }; IDockingWindow* ptbar = _GetToolbarItem(_itbLastFocus)->ptbar; if (SUCCEEDED(IUnknown_QueryStatus(ptbar, &CGID_Explorer, ARRAYSIZE(rgcmd), rgcmd, NULL))) { _EnableMenuItem(hmenuPopup, FCIDM_DELETE, rgcmd[0].cmdf & OLECMDF_ENABLED); _EnableMenuItem(hmenuPopup, FCIDM_PROPERTIES, rgcmd[1].cmdf & OLECMDF_ENABLED); _EnableMenuItem(hmenuPopup, FCIDM_RENAME, rgcmd[2].cmdf & OLECMDF_ENABLED); _EnableMenuItem(hmenuPopup, FCIDM_LINK, rgcmd[3].cmdf & OLECMDF_ENABLED); } } _EnableMenuItem(hmenuPopup, FCIDM_FILECLOSE, S_FALSE == _DisableModeless()); _EnableFileContext(hmenuPopup); if (_fEnableOfflineFeature || (GetUIVersion() < 5)) { _CheckMenuItem(hmenuPopup, FCIDM_VIEWOFFLINE, (Offline(SBSC_QUERY) == S_OK)); } else RemoveMenu(hmenuPopup, FCIDM_VIEWOFFLINE, MF_BYCOMMAND); if (_fVisitedNet && NeedFortezzaMenu()) // Do not load WININET.DLL in explorer mode { // The logic here ensures that the menu is created once per instance // and only if there is a need to display a Fortezza menu. if (!_fShowFortezza) { static TCHAR szItemText[16] = TEXT(""); if (!szItemText[0]) // The string will be loaded only once MLLoadString(IDS_FORTEZZA_MENU, szItemText, ARRAYSIZE(szItemText)); if (_hfm==NULL) _hfm = FortezzaMenu(); InsertMenu(hmenuPopup, FCIDM_FILECLOSE, MF_POPUP, (UINT_PTR) _hfm, szItemText); _fShowFortezza = TRUE; } SetFortezzaMenu(hmenuPopup); } else if (_fShowFortezza) // Don't need the menu but already displayed? { // Remove without destroying the handle int cbItems = GetMenuItemCount(hmenuPopup); RemoveMenu(hmenuPopup, cbItems-2, MF_BYPOSITION); _fShowFortezza = FALSE; } // See if we can edit the page OLECMD rgcmd[] = { { CITIDM_EDITPAGE, 0 }, }; struct { OLECMDTEXT ct; wchar_t rgwz[128]; } cmdText = {0}; cmdText.ct.cwBuf = ARRAYSIZE(cmdText.rgwz) + ARRAYSIZE(cmdText.ct.rgwz); cmdText.ct.cmdtextf = OLECMDTEXTF_NAME; IDockingWindow* ptbar = _GetITBar(); IUnknown_QueryStatus(ptbar, &CGID_PrivCITCommands, ARRAYSIZE(rgcmd), rgcmd, &cmdText.ct); _EnableMenuItem(hmenuPopup, FCIDM_EDITPAGE, rgcmd[0].cmdf & OLECMDF_ENABLED); // Update the name of the edit menu item TCHAR szText[80]; MENUITEMINFO mii = {0}; mii.cbSize = sizeof(MENUITEMINFO); mii.fMask = MIIM_TYPE; mii.dwTypeData = szText; if (cmdText.ct.cwActual > 1) { SHUnicodeToTChar(cmdText.ct.rgwz, szText, ARRAYSIZE(szText)); } else { // Use default edit text MLLoadString(IDS_EDITPAGE, szText, ARRAYSIZE(szText)); } SetMenuItemInfo(hmenuPopup, FCIDM_EDITPAGE, FALSE, &mii); #ifdef TEST_AMBIENTS _CheckMenuItem(hmenuPopup, FCIDM_VIEWLOCALOFFLINE, _LocalOffline(SBSC_QUERY) == TRUE); _CheckMenuItem(hmenuPopup, FCIDM_VIEWLOCALSILENT, _LocalSilent(SBSC_QUERY) == TRUE); #endif // TEST_AMBIENTS // must not change ie4 shell experience // so travel log still goes to the file menu if ((GetUIVersion() < 5) && !IsWebPidl(_pbbd->_pidlCur)) { int nPos = GetMenuItemCount(hmenuPopup) - 1; // Start with the last item MENUITEMINFO mii = {0}; BOOL fFound = FALSE; mii.cbSize = sizeof(MENUITEMINFO); mii.fMask = MIIM_ID | MIIM_TYPE; // Find the last separator separator while (!fFound && nPos > 0) { mii.cch = 0; GetMenuItemInfo(hmenuPopup, nPos, TRUE, &mii); if (mii.fType & MFT_SEPARATOR) fFound = TRUE; else nPos --; } if (fFound) { _InsertTravelLogItems(hmenuPopup, nPos); } } HMENU hmFileNew = SHGetMenuFromID(hmenuPopup, DVIDM_NEW); if (hmFileNew) { // remove menu items for unregistered components // this code is duplicated in shdocvw\dochost.cpp and is necessary here // so that unwanted items are not present before dochost has fully loaded const static struct { LPCTSTR pszClient; UINT idCmd; } s_Clients[] = { { NEW_MAIL_DEF_KEY, DVIDM_NEWMESSAGE }, { NEW_CONTACTS_DEF_KEY, DVIDM_NEWCONTACT }, { NEW_NEWS_DEF_KEY, DVIDM_NEWPOST }, { NEW_APPOINTMENT_DEF_KEY, DVIDM_NEWAPPOINTMENT }, { NEW_MEETING_DEF_KEY, DVIDM_NEWMEETING }, { NEW_TASK_DEF_KEY, DVIDM_NEWTASK }, { NEW_TASKREQUEST_DEF_KEY, DVIDM_NEWTASKREQUEST }, { NEW_JOURNAL_DEF_KEY, DVIDM_NEWJOURNAL }, { NEW_NOTE_DEF_KEY, DVIDM_NEWNOTE }, { NEW_CALL_DEF_KEY, DVIDM_CALL } }; BOOL bItemRemoved = FALSE; for (int i = 0; i < ARRAYSIZE(s_Clients); i++) { if (!SHIsRegisteredClient(s_Clients[i].pszClient)) { if (RemoveMenu(hmFileNew, s_Clients[i].idCmd, MF_BYCOMMAND)) bItemRemoved = TRUE; } } if (bItemRemoved) // ensure the last item is not a separator _SHPrettyMenu(hmFileNew); } if (!SHIsRegisteredClient(MAIL_DEF_KEY)) { // disable Send Page by Email, Send Link by Email HMENU hmFileSend = SHGetMenuFromID(hmenuPopup, DVIDM_SEND); if (hmFileSend) { EnableMenuItem(hmFileSend, DVIDM_SENDPAGE, MF_BYCOMMAND | MF_GRAYED); EnableMenuItem(hmFileSend, DVIDM_SENDSHORTCUT, MF_BYCOMMAND | MF_GRAYED); } } if (!IEHardened() && -1 != GetMenuState(hmenuPopup, DVIDM_ADDSITE, MF_BYCOMMAND)) { DeleteMenu(hmenuPopup, DVIDM_ADDSITE, MF_BYCOMMAND); } } void CShellBrowser2::_OnSearchMenuPopup(HMENU hmenuPopup) { if (!_pcmSearch) _pxtb->QueryInterface(IID_PPV_ARG(IContextMenu3, &_pcmSearch)); if (_pcmSearch) _pcmSearch->QueryContextMenu(hmenuPopup, 0, FCIDM_SEARCHFIRST, FCIDM_SEARCHLAST, 0); } void CShellBrowser2::_OnHelpMenuPopup(HMENU hmenuPopup) { RIP(IS_VALID_HANDLE(hmenuPopup, MENU)); // Do nothing if this is the DocHost version of the Help menu, // which always says "About Internet Explorer", and bring up // IE about dlg. // If we're running in native browser mode, // it says "About Windows" and bring up shell about dlg. // Change the "About Windows" to "About Windows NT" if running on NT. // Not sure what to do for Memphis yet. // // remove menu items which have been marked for removal // via the IEAK restrictions // if (SHRestricted2(REST_NoHelpItem_TipOfTheDay, NULL, 0)) { DeleteMenu(hmenuPopup, FCIDM_HELPTIPOFTHEDAY, MF_BYCOMMAND); } if (SHRestricted2(REST_NoHelpItem_NetscapeHelp, NULL, 0)) { DeleteMenu(hmenuPopup, FCIDM_HELPNETSCAPEUSERS, MF_BYCOMMAND); } if (SHRestricted2(REST_NoHelpItem_Tutorial, NULL, 0)) { DeleteMenu(hmenuPopup, DVIDM_HELPTUTORIAL, MF_BYCOMMAND); } if (SHRestricted2(REST_NoHelpItem_SendFeedback, NULL, 0)) { DeleteMenu(hmenuPopup, FCIDM_HELPSENDFEEDBACK, MF_BYCOMMAND); } if (!IEHardened()) { DeleteMenu(hmenuPopup, DVIDM_HELPIESEC, MF_BYCOMMAND); } // "Is this copy of Windows legal?" only supported on Whistler and greater. if (!IsOS(OS_WHISTLERORGREATER)) { DeleteMenu(hmenuPopup, FCIDM_HELPISLEGAL, MF_BYCOMMAND); } UINT ids = IDS_ABOUTWINDOWS; if (IsOS(OS_NT4ORGREATER) && !IsOS(OS_WIN2000ORGREATER)) { ids = IDS_ABOUTWINDOWSNT; } else if (IsOS(OS_WIN98ORGREATER)) { ids = IDS_ABOUTWINDOWS9X; } if (ids) { MENUITEMINFO mii = { 0 }; TCHAR szName[80]; // The name better not be any bigger. mii.cbSize = sizeof(MENUITEMINFO); mii.fMask = MIIM_TYPE; // We only try to get FCIDM_HELPABOUT, which will fail if this // is the DocHost version of help menu (who has DVIDM_HELPABOUT.) if (GetMenuItemInfoWrap(hmenuPopup, FCIDM_HELPABOUT, FALSE, &mii) && MLLoadString(ids, szName, ARRAYSIZE(szName))) { mii.dwTypeData = szName; SetMenuItemInfo(hmenuPopup, FCIDM_HELPABOUT, FALSE, &mii); } } SHCheckMenuItem(hmenuPopup, FCIDM_HELPTIPOFTHEDAY, (_idmComm == _InfoCLSIDToIdm(&CLSID_TipOfTheDay))); } void CShellBrowser2::_OnMailMenuPopup(HMENU hmenuPopup) { if (!SHIsRegisteredClient(MAIL_DEF_KEY)) { DeleteMenu(hmenuPopup, FCIDM_MAIL, MF_BYCOMMAND); DeleteMenu(hmenuPopup, FCIDM_NEWMESSAGE, MF_BYCOMMAND); DeleteMenu(hmenuPopup, FCIDM_SENDLINK, MF_BYCOMMAND); DeleteMenu(hmenuPopup, FCIDM_SENDDOCUMENT, MF_BYCOMMAND); DeleteMenu(hmenuPopup, FCIDM_MAILNEWSSEPARATOR, MF_BYCOMMAND); } if (!SHIsRegisteredClient(NEWS_DEF_KEY)) { DeleteMenu(hmenuPopup, FCIDM_MAILNEWSSEPARATOR, MF_BYCOMMAND); DeleteMenu(hmenuPopup, FCIDM_NEWS, MF_BYCOMMAND); } } void CShellBrowser2::_OnEditMenuPopup(HMENU hmenuPopup) { OLECMD rgcmdEdit[] = {{CITIDM_EDITPAGE, 0 }}; OLECMD rgcmd[] = { { OLECMDID_CUT, 0 }, { OLECMDID_COPY, 0 }, { OLECMDID_PASTE, 0 }, { OLECMDID_SELECTALL, 0 } }; ASSERT(FCIDM_COPY==FCIDM_MOVE+1); ASSERT(FCIDM_PASTE==FCIDM_MOVE+2); ASSERT(FCIDM_SELECTALL==FCIDM_MOVE+3); TraceMsg(DM_PREMERGEDMENU, "CSB::_OnEditMenuPopup got FCIDM_MENU_EDIT"); IOleCommandTarget* pcmdt; HRESULT hres = _FindActiveTarget(IID_PPV_ARG(IOleCommandTarget, &pcmdt)); if (SUCCEEDED(hres)) { pcmdt->QueryStatus(NULL, ARRAYSIZE(rgcmd), rgcmd, NULL); pcmdt->Release(); } for (int i=0; iQueryInterface(IID_PPV_ARG(IOleCommandTarget, &pcmdt)))) { pcmdt->QueryStatus(&CGID_PrivCITCommands, ARRAYSIZE(rgcmdEdit), rgcmdEdit, NULL); pcmdt->Release(); } _EnableMenuItem(hmenuPopup, FCIDM_EDITPAGE, rgcmdEdit[0].cmdf & OLECMDF_ENABLED); // prettify the menu (make sure first and last items aren't // separators and that there are no runs of >1 separator) _SHPrettyMenu(hmenuPopup); } void CShellBrowser2::_OnFindMenuPopup(HMENU hmenuPopup) { TraceMsg(DM_TRACE, "CSB::_OnFindMenuPopup cabinet InitMenuPopup of Find commands"); ASSERT(GetUIVersion() < 5); // otherwise the menu is deleted when we load it from resources ASSERT(!SHRestricted(REST_NOFIND)); // otherwise the menu is deleted when we load it from resources ATOMICRELEASE(_pcmFind); _pcmFind = SHFind_InitMenuPopup(hmenuPopup, _pbbd->_hwnd, FCIDM_MENU_TOOLS_FINDFIRST, FCIDM_MENU_TOOLS_FINDLAST); } void CShellBrowser2::_OnExplorerBarMenuPopup(HMENU hmenuPopup) { if (_hEventComCat) { // Wait a bit for the comcat cache enumeration to finish WaitForSingleObject(_hEventComCat, 1500); CloseHandle(_hEventComCat); _hEventComCat = NULL; } _AddBrowserBarMenuItems(hmenuPopup); if (SHRestricted2(REST_NoFavorites, NULL, 0)) _EnableMenuItem(hmenuPopup, FCIDM_VBBFAVORITESBAND, FALSE); if (SHRestricted2(REST_No_LaunchMediaBar, NULL, 0)) _EnableMenuItem(hmenuPopup, FCIDM_VBBMEDIABAND, FALSE); for (int idCmd = FCIDM_VBBFIXFIRST; idCmd <= FCIDM_VBBDYNLAST; idCmd++) SHCheckMenuItem(hmenuPopup, idCmd, FALSE); MENUITEMINFO mii; mii.cbSize = sizeof(mii); mii.fState = MFS_CHECKED; mii.fMask = MIIM_STATE; SetMenuItemInfo(hmenuPopup, _idmInfo, FALSE, &mii); SetMenuItemInfo(hmenuPopup, _idmComm, FALSE, &mii); // if we have pre-ie4 shell32, remove the folders bar option if (GetUIVersion() < 4) DeleteMenu(hmenuPopup, FCIDM_VBBEXPLORERBAND, MF_BYCOMMAND); } LRESULT CShellBrowser2::v_OnInitMenuPopup(HMENU hmenuPopup, int nIndex, BOOL fSystemMenu) { if (hmenuPopup == _GetMenuFromID(FCIDM_MENU_EXPLORE)) { _OnGoMenuPopup(hmenuPopup); } else if (hmenuPopup == _GetMenuFromID(FCIDM_MENU_VIEW)) { _OnViewMenuPopup(hmenuPopup); } else if (hmenuPopup == _GetMenuFromID(FCIDM_MENU_TOOLS)) { _OnToolsMenuPopup(hmenuPopup); } else if (hmenuPopup == _GetMenuFromID(FCIDM_MENU_FILE)) { _OnFileMenuPopup(hmenuPopup); } else if (hmenuPopup == _GetMenuFromID(FCIDM_SEARCHMENU)) { _OnSearchMenuPopup(hmenuPopup); } else if ((hmenuPopup == _GetMenuFromID(FCIDM_MENU_HELP)) || (hmenuPopup == SHGetMenuFromID(_hmenuFull, FCIDM_MENU_HELP))) { // For the help menu we try both the current menu and by chance the FullSB menu // as if we get here before the menu merge we will not have set the current menu // and that would leave Help about windows95 for all platforms. _OnHelpMenuPopup(hmenuPopup); } else if (hmenuPopup == _GetMenuFromID(FCIDM_MENU_EDIT)) { _OnEditMenuPopup(hmenuPopup); } else if (hmenuPopup == _GetMenuFromID(FCIDM_MENU_FIND)) { _OnFindMenuPopup(hmenuPopup); } else if (hmenuPopup == _GetMenuFromID(FCIDM_VIEWBROWSERBARS)) { _OnExplorerBarMenuPopup(hmenuPopup); } else { UINT wID = GetMenuItemID(hmenuPopup, 0); // assume the first item on the popup identifies the menu if (wID == FCIDM_MAIL) { _OnMailMenuPopup(hmenuPopup); } else if (_pcmNsc && IsInRange(wID, FCIDM_FILECTX_FIRST, FCIDM_FILECTX_LAST)) { _pcmNsc->HandleMenuMsg(WM_INITMENUPOPUP, (WPARAM)hmenuPopup, (LPARAM)MAKELONG(nIndex, fSystemMenu)); } else if (_pcm) { _pcm->HandleMenuMsg(WM_INITMENUPOPUP, (WPARAM)hmenuPopup, (LPARAM)MAKELONG(nIndex, fSystemMenu)); } } return S_OK; } #pragma warning (disable:4200) typedef struct { int nItemOffset; int nPopupOffset; struct { UINT uID; HMENU hPopup; } sPopupIDs[]; } MENUHELPIDS; #pragma warning (default:4200) void CShellBrowser2::_SetMenuHelp(HMENU hmenu, UINT wID, LPCTSTR pszHelp) { if (pszHelp && pszHelp[0]) { UINT flags = SBT_NOBORDERS | 255; // If the menu text is RTL, then so too will the status text be MENUITEMINFO mii = { sizeof(mii) }; mii.fMask = MIIM_TYPE; if (GetMenuItemInfo(hmenu, wID, FALSE, &mii) && (mii.fType & MFT_RIGHTORDER)) flags |= SBT_RTLREADING; SendMessage(_hwndStatus, SB_SETTEXT, flags, (LPARAM)pszHelp); SendMessage(_hwndStatus, SB_SIMPLE, 1, 0); } } void CShellBrowser2::_SetExternalBandMenuHelp(HMENU hmenu, UINT wID) { OLECMD cmd = { CITIDM_VIEWEXTERNALBAND_FIRST + (wID - FCIDM_EXTERNALBANDS_FIRST), 0 }; OLECMDTEXTV cmdtv; cmdtv.cwBuf = MAX_PATH; cmdtv.cmdtextf = OLECMDTEXTF_STATUS; cmdtv.rgwz[0] = 0; IUnknown_QueryStatus(_GetITBar(), &CGID_PrivCITCommands, 1, &cmd, &cmdtv); _SetMenuHelp(hmenu, wID, cmdtv.rgwz); } void CShellBrowser2::_SetBrowserBarMenuHelp(HMENU hmenu, UINT wID) { if (_pbsmInfo) { BANDCLASSINFO *pbci = _BandClassInfoFromCmdID(wID); if (pbci) { LPCTSTR pszHelp = pbci->pszHelpPUI ? pbci->pszHelpPUI : pbci->pszHelp; _SetMenuHelp(hmenu, wID, pszHelp); } } } // Handles WM_MENUSELECT. Returns FALSE if this menu item isn't handled by // the frame. LRESULT CShellBrowser2::_OnMenuSelect(WPARAM wParam, LPARAM lParam, UINT uHelpFlags) { MENUHELPIDS sMenuHelpIDs = { MH_ITEMS, MH_POPUPS, 0, NULL, // Placeholder for specific menu 0, NULL // This list must be NULL terminated }; TCHAR szHint[MAX_PATH]; // OK with MAX_PATH UINT uMenuFlags = GET_WM_MENUSELECT_FLAGS(wParam, lParam); WORD wID = GET_WM_MENUSELECT_CMD(wParam, lParam); HMENU hMenu = GET_WM_MENUSELECT_HMENU(wParam, lParam); /* HACKHACK USER32 TrackPopup menus send a menu deselect message which clears our status text at inopportune times. We work around this with a private MBIgnoreNextDeselect message. */ // Did someone ask us to clear the status text? if (!hMenu && LOWORD(uMenuFlags)==0xffff) { // Yes // Should we honour that request? if (!_fIgnoreNextMenuDeselect) // Yes SendMessage(_hwndStatus, SB_SIMPLE, 0, 0L); else // No _fIgnoreNextMenuDeselect = FALSE; return 1L; } // Clear this out just in case, but don't update yet SendMessage(_hwndStatus, SB_SETTEXT, SBT_NOBORDERS|255, (LPARAM)(LPTSTR)c_szNULL); SendMessage(_hwndStatus, SB_SIMPLE, 1, 0L); if (uMenuFlags & MF_SYSMENU) { // We don't put special items on the system menu any more, so go // straight to the MenuHelp goto DoMenuHelp; } if (uMenuFlags & MH_POPUP) { MENUITEMINFO miiSubMenu; if (!_hmenuCur) { return(0L); } miiSubMenu.cbSize = sizeof(MENUITEMINFO); miiSubMenu.fMask = MIIM_SUBMENU|MIIM_ID; if (!GetMenuItemInfoWrap(GET_WM_MENUSELECT_HMENU(wParam, lParam), wID, TRUE, &miiSubMenu)) { // Check if this was a top level menu return(0L); } // Change the parameters to simulate a "normal" menu item wParam = miiSubMenu.wID; wID = (WORD)miiSubMenu.wID; // // NOTES: We are eliminating this range check so that we can display // help-text on sub-menus. I'm not sure why explorer.exe has this check. // #if 0 if (!IsInRange(wID, FCIDM_GLOBALFIRST, FCIDM_GLOBALLAST)) return 0L; #endif uMenuFlags = 0; } // FEATURE: chrisfra 9/2/97 // No menu help for context menu stuck in File Menu or menus that aren't ours // in IE 5.0, might want to write code to use context // menu to get help to work if (IsInRange(wID, FCIDM_FILECTX_FIRST, FCIDM_FILECTX_LAST) || !IsInRange(wID, FCIDM_FIRST, FCIDM_LAST)) return 0L; if (_pcmSearch && IsInRange(wID, FCIDM_SEARCHFIRST, FCIDM_SEARCHLAST)) { _pcmSearch->HandleMenuMsg(WM_MENUSELECT, wParam, lParam); return 0L; } #if 0 if (IsInRange(wID, FCIDM_RECENTFIRST, FCIDM_RECENTLAST)) { wID = FCIDM_RECENTFIRST; } #endif // Menu help for plug-in explorer bars. if (IsInRange(wID, FCIDM_VBBDYNFIRST, FCIDM_VBBDYNLAST)) { _SetBrowserBarMenuHelp(hMenu, wID); return 0L; } // Menu help for plug-in itbar bands if (IsInRange(wID, FCIDM_EXTERNALBANDS_FIRST, FCIDM_EXTERNALBANDS_LAST)) { _SetExternalBandMenuHelp(hMenu, wID); return 0L; } szHint[0] = 0; sMenuHelpIDs.sPopupIDs[0].uID = 0; sMenuHelpIDs.sPopupIDs[0].hPopup = NULL; DoMenuHelp: MenuHelp(WM_MENUSELECT, wParam, lParam, _hmenuCur, MLGetHinst(), _hwndStatus, (UINT *)&sMenuHelpIDs); return 1L; } void CShellBrowser2::_DisplayFavoriteStatus(LPCITEMIDLIST pidl) { LPTSTR pszURL = NULL; IUniformResourceLocator * pURL; if (SUCCEEDED(CoCreateInstance(CLSID_InternetShortcut, NULL, CLSCTX_INPROC_SERVER, IID_IUniformResourceLocator, (void **)&pURL))) { IPersistFile *ppf; if (SUCCEEDED(pURL->QueryInterface(IID_PPV_ARG(IPersistFile, &ppf)))) { WCHAR wszPath[MAX_PATH]; // Get the full path to the .lnk if (SHGetPathFromIDListW(pidl, wszPath)) { // Attempt to connect the storage of the IURL to the pidl if (SUCCEEDED(ppf->Load(wszPath, STGM_READ))) { pURL->GetURL(&pszURL); } } ppf->Release(); } pURL->Release(); } SendMessage(_hwndStatus, SB_SIMPLE, 1, 0L); SendMessage(_hwndStatus, SB_SETTEXT, SBT_NOBORDERS|255, (LPARAM)pszURL); if (pszURL) SHFree(pszURL); } LRESULT CShellBrowser2::_ThunkTTNotify(LPTOOLTIPTEXTA pnmTTTA) { TOOLTIPTEXTW tttw = {0}; tttw.hdr = pnmTTTA->hdr; tttw.hdr.code = TTN_NEEDTEXTW; tttw.lpszText = tttw.szText; tttw.hinst = pnmTTTA->hinst; tttw.uFlags = pnmTTTA->uFlags; tttw.lParam = pnmTTTA->lParam; LRESULT lRes = SUPERCLASS::OnNotify(&tttw.hdr); pnmTTTA->hdr = tttw.hdr; pnmTTTA->hdr.code = TTN_NEEDTEXTA; pnmTTTA->hinst = tttw.hinst; pnmTTTA->uFlags = tttw.uFlags; pnmTTTA->lParam = tttw.lParam; if (tttw.lpszText == LPSTR_TEXTCALLBACKW) pnmTTTA->lpszText = LPSTR_TEXTCALLBACKA; else if (!tttw.lpszText) pnmTTTA->lpszText = NULL; else if (!HIWORD(tttw.lpszText)) pnmTTTA->lpszText = (LPSTR)tttw.lpszText; else { WideCharToMultiByte(CP_ACP, 0, tttw.lpszText, -1, pnmTTTA->szText, ARRAYSIZE(pnmTTTA->szText), NULL, NULL); } return lRes; } UINT GetDDEExecMsg() { static UINT uDDEExec = 0; if (!uDDEExec) uDDEExec = RegisterWindowMessage(TEXT("DDEEXECUTESHORTCIRCUIT")); return uDDEExec; } LRESULT CShellBrowser2::OnNotify(LPNMHDR pnm) { switch (pnm->code) { case NM_DBLCLK: { int idCmd = -1; LPNMCLICK pnmc = (LPNMCLICK)pnm; switch(pnmc->dwItemSpec) { case STATUS_PANE_NAVIGATION: idCmd = SHDVID_NAVIGATIONSTATUS; break; case STATUS_PANE_PROGRESS: idCmd = SHDVID_PROGRESSSTATUS; break; case STATUS_PANE_OFFLINE: idCmd = SHDVID_ONLINESTATUS; break; case STATUS_PANE_PRIVACY: idCmd = SHDVID_PRIVACYSTATUS; break; //case STATUS_PANE_PRINTER: // idCmd = SHDVID_PRINTSTATUS; // break; case STATUS_PANE_ZONE: idCmd = SHDVID_ZONESTATUS; break; case STATUS_PANE_SSL: idCmd = SHDVID_SSLSTATUS; break; default: break; } if (_pbbd->_pctView && (idCmd != -1)) { HRESULT hr = _pbbd->_pctView->Exec(&CGID_ShellDocView, idCmd, NULL, NULL, NULL); // If the parent couldn't handle it, maybe we can. if (FAILED(hr)) { if (pnmc->dwItemSpec == _uiZonePane && _pbbd->_pidlCur) { WCHAR wszUrl[MAX_URL_STRING]; if (SUCCEEDED(::IEGetDisplayName(_pbbd->_pidlCur, wszUrl, SHGDN_FORPARSING))) { ULONG_PTR uCookie = 0; SHActivateContext(&uCookie); ZoneConfigureW(_pbbd->_hwnd, wszUrl); if (uCookie) { SHDeactivateContext(uCookie); } } } } } break; } case TTN_NEEDTEXTA: case TTN_NEEDTEXTW: if (IsInRange(pnm->idFrom, FCIDM_SHVIEWFIRST, FCIDM_SHVIEWLAST)) { if (pnm->code == TTN_NEEDTEXTA && _fUnicode) return _ThunkTTNotify((LPTOOLTIPTEXTA)pnm); else return SUPERCLASS::OnNotify(pnm); } return 0; case SEN_DDEEXECUTE: // 381213 - webfolders needs dde shortcircuit in IE to work - ZekeL - 30-APR-2001 // on NT4SUR (non-integrated) we have to make sure that webfolders // continues to be able to get folder window reuse for navigation. // // this was: // if (pnm->idFrom == 0 && GetUIVersion() >= 4) // and i am pretty sure some thing will break, since we once again // allow the shortcircuit code to run on pre-shell integrated. // but maybe not since we no longer use the bogus folder navigation // in order to implement OpenNew window for HTMLFile if (pnm->idFrom == 0) { LPNMVIEWFOLDER pnmPost = DDECreatePostNotify((LPNMVIEWFOLDER)pnm) ; if (pnmPost) { PostMessage(_pbbd->_hwnd, GetDDEExecMsg(), 0, (LPARAM)pnmPost); return TRUE; } } break; case SBN_SIMPLEMODECHANGE: if ((pnm->idFrom == FCIDM_STATUS) && _hwndProgress) _ShowHideProgress(); break; default: break; } return 0; } DWORD CShellBrowser2::_GetTempZone() { LPCITEMIDLIST pidlChild; IShellFolder* psfParent; WCHAR szURL[MAX_URL_STRING]; szURL[0] = 0; // parse name for zone goes here if (SUCCEEDED(IEBindToParentFolder(_pbbd->_pidlCur, &psfParent, &pidlChild))) { // see if this is a folder shortcut, if so we use it's path for the zone IShellLink *psl; if (SUCCEEDED(psfParent->GetUIObjectOf(NULL, 1, (LPCITEMIDLIST*)&pidlChild, IID_IShellLink, NULL, (void **)&psl))) { LPITEMIDLIST pidlTarget; if (S_OK == psl->GetIDList(&pidlTarget)) { ::IEGetDisplayName(pidlTarget, szURL, SHGDN_FORPARSING); ILFree(pidlTarget); } psl->Release(); } psfParent->Release(); } if (NULL == _pism) { // Don't need to QueryService for this since CShellBrowser is the top of the chain. CoCreateInstance(CLSID_InternetSecurityManager, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IInternetSecurityManager, &_pism)); } DWORD nZone = ZONE_UNKNOWN; if (_pism && (szURL[0] || SUCCEEDED(::IEGetDisplayName(_pbbd->_pidlCur, szURL, SHGDN_FORPARSING)))) { _pism->MapUrlToZone(szURL, &nZone, 0); } return nZone; } void Exec_GetZone(IUnknown * punk, VARIANTARG *pvar) { IUnknown_Exec(punk, &CGID_Explorer, SBCMDID_MIXEDZONE, 0, NULL, pvar); if (pvar->vt == VT_UI4) // MSHTML was able to figure out what zone we are in pvar->ulVal = MAKELONG(STATUS_PANE_ZONE, pvar->ulVal); else if (pvar->vt == VT_NULL) // MSHTML has figured us to be in a mixed zone pvar->ulVal = MAKELONG(STATUS_PANE_ZONE, ZONE_MIXED); else // We don't have zone info pvar->ulVal = MAKELONG(STATUS_PANE_ZONE, ZONE_UNKNOWN); pvar->vt = VT_UI4; } // // in: // pvar if NULL, we query the view for the zone // non NULL, contains a VT_UI4 that encodes the zone pane and the zone value void CShellBrowser2::_UpdateZonesPane(VARIANT *pvar) { LONG lZone = ZONE_UNKNOWN; BOOL fMixed = FALSE; TCHAR szDisplayName[MAX_ZONE_DISPLAYNAME]; VARIANTARG var = {0}; if (NULL == pvar) { pvar = &var; Exec_GetZone(_pbbd->_pctView, &var); } // Do we already have the zone and fMixed info? if (pvar->vt == VT_UI4) { lZone = (signed short)HIWORD(pvar->lVal); _uiZonePane = (int)(signed short)LOWORD(pvar->lVal); if (lZone == ZONE_MIXED) { lZone = ZONE_UNKNOWN; fMixed = TRUE; } if (lZone < 0 && !IS_SPECIAL_ZONE(lZone)) { // sometimes we're getting back an invalid zone index from urlmon, // and if we don't bound the index, we'll crash later lZone = ZONE_UNKNOWN; } } var.vt = VT_EMPTY; if (_pbbd->_pctView && SUCCEEDED(_pbbd->_pctView->Exec(&CGID_Explorer, SBCMDID_GETPANE, PANE_ZONE, NULL, &var))) _uiZonePane = var.ulVal; else _uiZonePane = STATUS_PANE_ZONE; // Sanity Check the zone if (_pbbd->_pidlCur) { DWORD nTempZone = _GetTempZone(); if (nTempZone != ZONE_UNKNOWN) if (nTempZone > (DWORD)lZone) lZone = nTempZone; } szDisplayName[0] = 0; if (ZONE_UNKNOWN == lZone) MLLoadStringW(IDS_UNKNOWNZONE, szDisplayName, ARRAYSIZE(szDisplayName)); else { if (_hZoneIcon) { // Before we can delete it, make comctl32's statusbar code stop using it. // Or else we rip. SendControlMsg(FCW_STATUS, SB_SETICON, _uiZonePane, (LPARAM)NULL, NULL); DestroyIcon(_hZoneIcon); } // This will zero the icon & name on failure _GetCachedZoneIconAndName(lZone, &_hZoneIcon, szDisplayName, ARRAYSIZE(szDisplayName)); } if (fMixed) { TCHAR szMixed[32]; MLLoadString(IDS_MIXEDZONE, szMixed, ARRAYSIZE(szMixed)); StringCchCat(szDisplayName, ARRAYSIZE(szDisplayName), szMixed); // truncation ok } SendControlMsg(FCW_STATUS, SB_SETTEXTW, _uiZonePane, (LPARAM)szDisplayName, NULL); SendControlMsg(FCW_STATUS, SB_SETICON, _uiZonePane, (LPARAM)_hZoneIcon, NULL); } HRESULT CShellBrowser2::ReleaseShellView() { // Give the current view a chance to save before we navigate away if (!_fClosingWindow) { // only try to save if we actually have a current view (this gets // called multiple times in a row on destruction, and it gets called // before the first view is created) // if (_pbbd->_psv) _SaveState(); } return SUPERCLASS::ReleaseShellView(); } bool IsWin95ClassicViewState (void) { DWORD dwValue; DWORD cbSize = sizeof(dwValue); return ERROR_SUCCESS == SHGetValue(HKEY_CURRENT_USER, TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced"), TEXT("ClassicViewState"), NULL, &dwValue, &cbSize) && dwValue; } BOOL _PersistOpenBrowsers() { return SHRegGetBoolUSValue(TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced"), TEXT("PersistBrowsers"), FALSE, FALSE); } // For Folder Advanced Options flags that we check often, it's better // to cache the values as flags in CBaseBrowser2. Update them here. void CShellBrowser2::_UpdateRegFlags() { _fWin95ViewState = IsWin95ClassicViewState(); } HRESULT CShellBrowser2::CreateViewWindow(IShellView* psvNew, IShellView* psvOld, LPRECT prcView, HWND* phwnd) { if (_pbbd->_psv) { // snag the current view's setting so we can pass it along _UpdateFolderSettings(_pbbd->_pidlPending); // this is not a valid flag to pass along after the first one _fsd._fs.fFlags &= ~FWF_BESTFITWINDOW; } return SUPERCLASS::CreateViewWindow(psvNew, psvOld, prcView, phwnd); } HRESULT CShellBrowser2::ActivatePendingView(void) { _fTitleSet = FALSE; // NOTES: (SatoNa) // // Notice that we no longer call SetRect(&_rcBorderDoc, 0, 0, 0, 0) // here. We call it in CShellBrowser2::ReleaseShellView instead. // See my comment over there for detail. // HRESULT hres = SUPERCLASS::ActivatePendingView(); if (FAILED(hres)) return hres; _ReloadStatusbarIcon(); _SetTitle(NULL); v_SetIcon(); VALIDATEPENDINGSTATE(); if (_pxtb) _pxtb->SendToolbarMsg(&CLSID_CommonButtons, TB_ENABLEBUTTON, TBIDM_PREVIOUSFOLDER, _ShouldAllowNavigateParent(), NULL); UpdateWindowList(); if (!_HasToolbarFocus()) { HWND hwndFocus = GetFocus(); // // Trident may take the input focus when they are being UIActivated. // In that case, don't mess with the focus. // if (_pbbd->_hwndView && (hwndFocus==NULL || !IsChild(_pbbd->_hwndView, hwndFocus))) SetFocus(_pbbd->_hwndView); } // Let's profile opening time if (g_dwProfileCAP & 0x00010000) StopCAP(); // Let's profile opening time if (g_dwProfileCAP & 0x00000020) StartCAP(); return S_OK; } void CShellBrowser2::_UpdateBackForwardStateNow() { _fUpdateBackForwardPosted = FALSE; SUPERCLASS::UpdateBackForwardState(); } HRESULT CShellBrowser2::UpdateBackForwardState() { if (!_fUpdateBackForwardPosted) { PostMessage(_pbbd->_hwnd, CWM_UPDATEBACKFORWARDSTATE, 0, 0); _fUpdateBackForwardPosted = TRUE; } return S_OK; } HRESULT CShellBrowser2::_TryShell2Rename(IShellView* psv, LPCITEMIDLIST pidlNew) { HRESULT hres = SUPERCLASS::_TryShell2Rename(psv, pidlNew); if (SUCCEEDED(hres)) { _SetTitle(NULL); } return hres; } /*---------------------------------------------------------- Purpose: Determines if this message should be forwarded onto the dochost frame. Returns: TRUE if the message needs to be forwarded */ BOOL CShellBrowser2::_ShouldForwardMenu(UINT uMsg, WPARAM wParam, LPARAM lParam) { if (!_fDispatchMenuMsgs) return FALSE; switch (uMsg) { case WM_MENUSELECT: { // See CDocObjectHost::_ShouldForwardMenu for more details // about how this works. HMENU hmenu = GET_WM_MENUSELECT_HMENU(wParam, lParam); if (hmenu && (MF_POPUP & GET_WM_MENUSELECT_FLAGS(wParam, lParam))) { HMENU hmenuSub = GetSubMenu(hmenu, GET_WM_MENUSELECT_CMD(wParam, lParam)); if (hmenu == _hmenuCur) { // Normal case, where we just look at the topmost popdown menus _fForwardMenu = _menulist.IsObjectMenu(hmenuSub); } else if (_menulist.IsObjectMenu(hmenuSub)) { // This happens if the cascading submenu (micro-merged help menu for // example) should be forwarded on, but the parent menu should // not. _fForwardMenu = TRUE; } } break; } case WM_COMMAND: if (_fForwardMenu) { // Stop forwarding menu messages after WM_COMMAND _fForwardMenu = FALSE; // If it wasn't from an accelerator, forward it if (0 == GET_WM_COMMAND_CMD(wParam, lParam)) return TRUE; } break; } return _fForwardMenu; } DWORD CShellBrowser2::v_RestartFlags() { return COF_CREATENEWWINDOW; } void CShellBrowser2::_CloseAllParents() { LPITEMIDLIST pidl = ILClone(_pbbd->_pidlCur); if (pidl) { for (ILRemoveLastID(pidl); !ILIsEmpty(pidl); ILRemoveLastID(pidl)) { HWND hwnd; if (WinList_FindFolderWindow(pidl, NULL, &hwnd, NULL) == S_OK) { TraceMsg(DM_SHUTDOWN, "csb.cap: post WM_CLOSE hwnd=%x", hwnd); PostMessage(hwnd, WM_CLOSE, 0, 0); } } ILFree(pidl); } } BOOL CShellBrowser2::_ShouldSaveWindowPlacement() { // If this is done by automation, maybe we should not update the defaults, so // to detect this we say if the window is not visible, don't save away the defaults // For the internet, save one setting for all, otherwise use the win95 // view stream mru return (IsWindowVisible(_pbbd->_hwnd) && _fUseIEPersistence && !_fUISetByAutomation && _pbbd->_pidlCur && IsBrowserFrameOptionsSet(_pbbd->_psf, BFO_BROWSER_PERSIST_SETTINGS)); } void CShellBrowser2::_OnConfirmedClose() { if (_pbbd->_pidlCur && IsCShellBrowser2() && (GetKeyState(VK_SHIFT) < 0)) { _CloseAllParents(); } if (_fUseIEPersistence && IsCShellBrowser2()) { // save off whether we should launch in fullscreen or not SHRegSetUSValue(TEXT("Software\\Microsoft\\Internet Explorer\\Main"), TEXT("FullScreen"), REG_SZ, _ptheater ? TEXT("yes") : TEXT("no"), _ptheater ? sizeof(TEXT("yes")) : sizeof(TEXT("no")), SHREGSET_DEFAULT); } if (_ptheater) { ShowWindow(_pbbd->_hwnd, SW_HIDE); _TheaterMode(FALSE, FALSE); _fDontSaveViewOptions = TRUE; } else { if (_ShouldSaveWindowPlacement()) { StorePlacementOfWindow(_pbbd->_hwnd); } else _fDontSaveViewOptions = TRUE; } // for now we use the same 12-hour (SessionTime) rule // possibly we should just do it always? UEMFireEvent(&UEMIID_BROWSER, UEME_CTLSESSION, UEMF_XEVENT, FALSE, -1); if (!g_bRunOnNT5) { // for down-level guys (old explorer), fake a shell end session too UEMFireEvent(&UEMIID_SHELL, UEME_CTLSESSION, UEMF_XEVENT, FALSE, -1); } // Save view states before closing all toolbars // Remember that we saved so we don't do it again // during _ReleaseShellView _SaveState(); _fClosingWindow = TRUE; // To prevent flashing, we move the window off the screen, unfortunately // we can't hide it as shockwave briefly puts up dialog which causes // an ugly blank taskbar icon to appear. // do this after _SaveState() because that saves window pos info // NTRAID 455003: this won't look too good with multi monitors... SetWindowPos(_pbbd->_hwnd, NULL, 10000, 10000, 0, 0, SWP_NOSIZE|SWP_NOZORDER); // Save the Internet toolbar before we close it! if (!_fDontSaveViewOptions) _SaveITbarLayout(); _CloseAndReleaseToolbars(TRUE); ATOMICRELEASE(_pxtb); // If you wait until WM_DESTROY (DestroyWindow below) to do this, under some // circumstances (eg an html page with an iframe whose src is an UNC based directory) // Ole will not Release the CShellBrowser2 that it addref'ed on RegisterDragDrop // (chrisfra 7/22/97) SetFlags(0, BSF_REGISTERASDROPTARGET); // If you wait until WM_DESTROY to do this, some OCs (like shockwave) // will hang (probably posting themselves a message) _CancelPendingView(); ReleaseShellView(); ATOMICRELEASE(_pmb); // Destroy the icons we created while we still can _SetWindowIcon(_pbbd->_hwnd, NULL, ICON_SMALL); _SetWindowIcon(_pbbd->_hwnd, NULL, ICON_BIG); // getting a random fault on rooted explorer on shutdown on this Destroy, maybe // somehow getting reentered. So atomic destroy it... // NOTE: chrisg removed this at one point - is it dead? HWND hwndT = _pbbd->_hwnd; PutBaseBrowserData()->_hwnd = NULL; DestroyWindow(hwndT); } // these three functions, CommonHandleFielSysChange, // v_HandleFileSysChange and this one // may seem strange, but the idea is that the notify may come in from // different sources (OneTree vs, win95 style fsnotify vs nt style) // _OnFSNotify cracks the input, unifies it and calls CommonHnaldeFileSysChange // that calls to v_HandleFIleSysChange. The Common...() is for stuff both needs // the v_Handle...() is for overridden ones void CShellBrowser2::_OnFSNotify(WPARAM wParam, LPARAM lParam) { LPSHChangeNotificationLock pshcnl = NULL; LONG lEvent; LPITEMIDLIST *ppidl = NULL; // on error, SHChangeNotification_Lock doesn't zero this out! IShellChangeNotify * pIFSN; if (g_fNewNotify && (wParam || lParam)) { // New style of notifications need to lock and unlock in order to free the memory... pshcnl = SHChangeNotification_Lock((HANDLE)wParam, (DWORD)lParam, &ppidl, &lEvent); } else { lEvent = (LONG)lParam; ppidl = (LPITEMIDLIST*)wParam; } if (ppidl) { // // If we haven't initialized "this" yet, we should ignore all the // notification. // if (_pbbd->_pidlCur) { _CommonHandleFileSysChange(lEvent, ppidl[0], ppidl[1]); // // Forward to ITBar too... // if (_GetITBar() && SUCCEEDED(_GetITBar()->QueryInterface(IID_PPV_ARG(IShellChangeNotify, &pIFSN)))) { pIFSN->OnChange(lEvent, ppidl[0], ppidl[1]); pIFSN->Release(); } } } if (pshcnl) { SHChangeNotification_Unlock(pshcnl); } } LPITEMIDLIST BurnDrivePidl() { LPITEMIDLIST pidl = NULL; ICDBurn *pcdb; if (SUCCEEDED(CoCreateInstance(CLSID_CDBurn, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(ICDBurn, &pcdb)))) { WCHAR szDrive[4]; if (SUCCEEDED(pcdb->GetRecorderDriveLetter(szDrive, ARRAYSIZE(szDrive)))) { pidl = ILCreateFromPath(szDrive); } pcdb->Release(); } return pidl; } BOOL IsCurrentBurnDrive(LPCITEMIDLIST pidl) { BOOL fRet = FALSE; LPITEMIDLIST pidlBurn = BurnDrivePidl(); if (pidlBurn) { fRet = ILIsEqual(pidlBurn, pidl) || ILIsParent(pidlBurn, pidl, FALSE); ILFree(pidlBurn); } return fRet; } // fDisconnectAlways means we shouldn't try to re-open the folder (like when // someone logs off of a share, reconnecting would ask them for // a password again when they just specified that they want to log off) void CShellBrowser2::_FSChangeCheckClose(LPCITEMIDLIST pidl, BOOL fDisconnect) { if (ILIsParent(pidl, _pbbd->_pidlCur, FALSE) || (ILIsRooted(_pbbd->_pidlCur) && (ILIsParent(pidl, ILRootedFindIDList(_pbbd->_pidlCur), FALSE)))) { if (!fDisconnect) { // APPCOMPAT: FileNet IDMDS (Panagon)'s shell folder extension // incorrectly reports itself as a file system folder, so sniff the // pidl to see if we should ignore the bit. (B#359464: tracysh) // (tybeam) argh put the burndrive check back in again. // this app compat hack brings me no joy, its false positive city and basically all it is is the // PathFileExistsAndAttributes check. if you ever have an issue where you have a namespace // extension that reports that it's on the filesystem and could possibly fail a PathFileExists // on a parsing name (which happens in the burning folder if theres no cd in the drive and it // checks the parsing name of the root) and it closes the window randomly, this is the problem // right here. TCHAR szPath[MAX_PATH]; DWORD dwAttrib = SFGAO_FILESYSTEM | SFGAO_BROWSABLE; if (SUCCEEDED(SHGetNameAndFlags(_pbbd->_pidlCur, SHGDN_FORPARSING, szPath, SIZECHARS(szPath), &dwAttrib)) && (dwAttrib & SFGAO_FILESYSTEM) && !(dwAttrib & SFGAO_BROWSABLE) && IsFlagClear(SHGetObjectCompatFlagsFromIDList(_pbbd->_pidlCur), OBJCOMPATF_NOTAFILESYSTEM) && !PathFileExistsAndAttributes(szPath, NULL) && !IsCurrentBurnDrive(_pbbd->_pidlCur)) { fDisconnect = TRUE; } } if (fDisconnect) _pbbd->_pautoWB2->Quit(); } } void CShellBrowser2::v_HandleFileSysChange(LONG lEvent, LPITEMIDLIST pidl1, LPITEMIDLIST pidl2) { BOOL fDisconnectAlways = FALSE; // // If we are in the middle of changing folders, // ignore this event. // if (_pbbd->_psvPending) { return; } // README: // If you need to add events here, then you must change SHELLBROWSER_FSNOTIFY_FLAGS in // order to get the notifications switch(lEvent) { case SHCNE_DRIVEADDGUI: if (ILIsParent(pidl1, _pbbd->_pidlCur, FALSE)) { PostMessage(_pbbd->_hwnd, WM_COMMAND, FCIDM_REFRESH, 0L); } break; case SHCNE_DELETE: case SHCNE_RMDIR: case SHCNE_MEDIAREMOVED: case SHCNE_SERVERDISCONNECT: case SHCNE_DRIVEREMOVED: if (g_fRunningOnNT || (lEvent == SHCNE_MEDIAREMOVED) || (lEvent == SHCNE_SERVERDISCONNECT)) fDisconnectAlways = TRUE; // the cd burning case can get a removal event when we lock the // drive to commence burning or when the user ejects. // since we have an open browser on the drive we could get closed and thats bad, // so we prevent that here. if ((lEvent == SHCNE_MEDIAREMOVED) && IsCurrentBurnDrive(_pbbd->_pidlCur)) { // jump out, we don't want to close. break; } // fall through case SHCNE_UPDATEDIR: case SHCNE_NETUNSHARE: // preserve old behavior of when the explorer (all folders) bar is up, // go to nearest parent folder if (_idmInfo == FCIDM_VBBEXPLORERBAND) break; _FSChangeCheckClose(pidl1, fDisconnectAlways); break; } } // converts a simple pidl to a full pidl LPITEMIDLIST _SimpleToReal(LPCITEMIDLIST pidl) { LPITEMIDLIST pidlReturn = NULL; IShellFolder *psf; LPCITEMIDLIST pidlChild; if (SUCCEEDED(IEBindToParentFolder(pidl, &psf, &pidlChild))) { LPITEMIDLIST pidlRealChild; if (SUCCEEDED(SHGetRealIDL(psf, pidlChild, &pidlRealChild))) { LPITEMIDLIST pidlParent = ILCloneParent(pidl); if (pidlParent) { pidlReturn = ILCombine(pidlParent, pidlRealChild); ILFree(pidlParent); } ILFree(pidlRealChild); } psf->Release(); } return pidlReturn; } void CShellBrowser2::_CommonHandleFileSysChange(LONG lEvent, LPITEMIDLIST pidl1, LPITEMIDLIST pidl2) { v_HandleFileSysChange(lEvent, pidl1, pidl2); // WARNING: In all cases _pbbd will have NULL contents before first navigate. if (_pbbd->_psvPending) { return; } // stuff that needs to be done tree or no tree switch (lEvent) { // README: // If you need to add events here, then you must change SHELLBROWSER_FSNOTIFY_FLAGS in // order to get the notifications case SHCNE_RENAMEFOLDER: { // the rename might be ourselfs or our parent... if it's // our parent, we want to tack on the child idl's from the renamed // parent to us onto the new pidl (pidlExtra). // then show that result. LPCITEMIDLIST pidlChild = ILFindChild(pidl1, _pbbd->_pidlCur); if (pidlChild) { LPITEMIDLIST pidlTarget = ILCombine(pidl2, pidlChild); if (pidlTarget) { LPITEMIDLIST pidlReal = _SimpleToReal(pidlTarget); if (pidlReal) { if (!ILIsEqual(pidlReal, _pbbd->_pidlCur)) { BrowseObject(pidlReal, SBSP_REDIRECT | SBSP_SAMEBROWSER); } ILFree(pidlReal); } ILFree(pidlTarget); } } } // fall through case SHCNE_UPDATEITEM: // the name could have changed if (ILIsEqual(_pbbd->_pidlCur, pidl1)) _SetTitle(NULL); break; case SHCNE_UPDATEIMAGE: IUnknown_CPContainerInvokeParam(_pbbd->_pautoEDS, DIID_DWebBrowserEvents2, DISPID_TITLEICONCHANGE, NULL, 0); #ifdef DEBUG if (_pbbd->_pautoEDS) { // Verify that every IExpDispSupport also supports IConnectionPointContainer IConnectionPointContainer *pcpc; IExpDispSupport* peds; if (SUCCEEDED(_pbbd->_pautoEDS->QueryInterface(IID_IConnectionPointContainer, (void **)&pcpc))) { pcpc->Release(); } else if (SUCCEEDED(_pbbd->_pautoEDS->QueryInterface(IID_IExpDispSupport, (void **)&peds))) { peds->Release(); AssertMsg(0, TEXT("IExpDispSupport without IConnectionPointContainer for %08x"), _pbbd->_pautoEDS); } } #endif v_SetIcon(); break; } } //--------------------------------------------------------------------------- // Helper Function to see if a pidl is on a network drive which is not // persistent. This is useful if we are shuting down and saving a list // of the open windows to restore as we won't be able to restore these. BOOL FPidlOnNonPersistentDrive(LPCITEMIDLIST pidl) { TCHAR szPath[MAX_PATH]; HANDLE hEnum; BOOL fRet = TRUE; TraceMsg(DM_SHUTDOWN, "csb.wp: FPidlOnNonPersistentDrive(pidl=%x)", pidl); if (!SHGetPathFromIDList(pidl, szPath) || (szPath[0] == TEXT('\0'))) return(FALSE); // not file system pidl assume ok. TraceMsg(DM_SHUTDOWN, "csb.wp: FPidlOnNonPersistentDrive - After GetPath=%s)", szPath); if (PathIsUNC(szPath) || !IsNetDrive(DRIVEID(szPath))) { fRet = FALSE; goto End; } // Ok we got here so now we have a network drive ... // we will have to enumerate over // if (WNetOpenEnum(RESOURCE_REMEMBERED, RESOURCETYPE_DISK, RESOURCEUSAGE_CONTAINER | RESOURCEUSAGE_ATTACHED, NULL, &hEnum) == WN_SUCCESS) { DWORD dwCount=1; union { NETRESOURCE nr; // Large stack usage but I TCHAR buf[1024]; // Dont think it is thunk to 16 bits... }nrb; DWORD dwBufSize = sizeof(nrb); while (WNetEnumResource(hEnum, &dwCount, &nrb.buf, &dwBufSize) == WN_SUCCESS) { // We only want to add items if they do not have a local // name. If they had a local name we would have already // added them! if ((nrb.nr.lpLocalName != NULL) && (CharUpperChar(*(nrb.nr.lpLocalName)) == CharUpperChar(szPath[0]))) { fRet = FALSE; break; } } WNetCloseEnum(hEnum); } End: TraceMsg(DM_TRACE, "c.c_arl: %s, is Persistent? %d", szPath, fRet); return(fRet); } void HackToPrepareForEndSession(LPCITEMIDLIST pidl) { TCHAR szPath[MAX_PATH]; TraceMsg(DM_SHUTDOWN, "csb.wp: HackToPrepareForEndSession(pidl=%x)", pidl); SHGetPathFromIDList(pidl, szPath); } //--------------------------------------------------------------------------- // returns: // TRUE if the user wants to abort the startup sequence // FALSE keep going // // note: this is a switch, once on it will return TRUE to all // calls so these keys don't need to be pressed the whole time BOOL AbortStartup() { static BOOL bAborted = FALSE; // static so it sticks! // TraceMsg(DM_TRACE, "Abort Startup?"); if (bAborted) return TRUE; // don't do funky startup stuff else { bAborted = (GetSystemMetrics(SM_CLEANBOOT) || ((GetAsyncKeyState(VK_CONTROL) < 0) || (GetAsyncKeyState(VK_SHIFT) < 0))); return bAborted; } } //--------------------------------------------------------------------------- // Restore all of the window that asked to save a command line to be // restarted when windows was exited. // BOOL AddToRestartList(DWORD dwFlags, LPCITEMIDLIST pidl) { int cItems = 0; DWORD cbData = sizeof(cItems); TCHAR szSubKey[80]; BOOL fRet = FALSE; IStream *pstm; // cases that we don't want to save window state for... if (SHRestricted(REST_NOSAVESET) || FPidlOnNonPersistentDrive(pidl) || !_PersistOpenBrowsers()) return FALSE; HKEY hkRestart = SHGetShellKey(SHELLKEY_HKCU_EXPLORER, TEXT("RestartCommands"), TRUE); if (hkRestart) { if (ERROR_SUCCESS != (SHGetValueGoodBoot(hkRestart, NULL, TEXT("Count"), NULL, (BYTE *)&cItems, &cbData))) cItems = 0; // Now Lets Create a registry Stream for this guy... if (SUCCEEDED(StringCchPrintf(szSubKey, ARRAYSIZE(szSubKey), TEXT("%d"), cItems))) { pstm = OpenRegStream(hkRestart, NULL, szSubKey, STGM_WRITE); TraceMsg(DM_SHUTDOWN, "csb.wp: AddToRestartList(pstm=%x)", pstm); if (pstm) { WORD wType = (WORD)-1; // sizeof of cmd line == -1 implies pidl... // Now Write a preamble to the start of the line that // tells wType that this is an explorer pstm->Write(&wType, sizeof(wType), NULL); // Now Write out the version number of this stream // Make sure to inc the version number if the structure changes pstm->Write(&c_wVersion, sizeof(c_wVersion), NULL); // Now Write out the dwFlags pstm->Write(&dwFlags, sizeof(dwFlags), NULL); // And the pidl; ILSaveToStream(pstm, pidl); // And Release the stream; pstm->Release(); cItems++; // Say that there are twice as many items... fRet = (ERROR_SUCCESS == SHSetValue(hkRestart, NULL, TEXT("Count"), REG_BINARY, &cItems, sizeof(cItems))); } } RegCloseKey(hkRestart); } return fRet; } //--------------------------------------------------------------------------- void SHCreateSavedWindows(void) { HKEY hkRestart = SHGetShellKey(SHELLKEY_HKCU_EXPLORER, TEXT("RestartCommands"), FALSE); if (_PersistOpenBrowsers() && hkRestart) { int cItems = 0; DWORD cbData = sizeof(cItems); SHGetValueGoodBoot(hkRestart, NULL, TEXT("Count"), NULL, (PBYTE)&cItems, &cbData); // walk in the reverse order that they were added. for (cItems--; cItems >= 0; cItems--) { if (AbortStartup()) break; TCHAR szName[80]; if (SUCCEEDED(StringCchPrintf(szName, ARRAYSIZE(szName), TEXT("%d"), cItems))) { IStream *pstm = OpenRegStream(hkRestart, NULL, szName, STGM_READ); if (pstm) { WORD wType; if (SUCCEEDED(pstm->Read(&wType, sizeof(wType), NULL))) { if (wType == (WORD)-1) { WORD wVersion; DWORD dwFlags; LPITEMIDLIST pidl = NULL; // need to be inited for ILLoadFromStream() // We have a folder serialized so get: // WORD:wVersion, DWORD:dwFlags, PIDL:pidlRoot, PIDL:pidl if (SUCCEEDED(pstm->Read(&wVersion, sizeof(wVersion), NULL)) && (wVersion == c_wVersion) && SUCCEEDED(pstm->Read(&dwFlags, sizeof(dwFlags), NULL)) && SUCCEEDED(ILLoadFromStream(pstm, &pidl)) && pidl) { // this call does window instance management IETHREADPARAM* piei = SHCreateIETHREADPARAM(NULL, 0, NULL, NULL); if (piei) { piei->pidl = pidl; pidl = NULL; // so this is not freed below piei->uFlags = dwFlags; piei->nCmdShow = SW_SHOWDEFAULT; SHOpenFolderWindow(piei); } ILFree(pidl); } } } pstm->Release(); } } } } if (hkRestart) { SHDeleteKeyA(hkRestart, NULL); RegCloseKey(hkRestart); } } // // This code intercept the WM_CONTEXTMENU message from USER and popups // up the context menu of the folder itself when the user clicks the icon // at the left-top corner of the frame (only when it is in the folder mode). // BOOL CShellBrowser2::v_OnContextMenu(WPARAM wParam, LPARAM lParam) { BOOL fProcessed = FALSE; TraceMsg(DM_TRACE, "csb.ocm Got WM_CONTEXTMENU"); if (_pbbd->_pidlCur && !ILIsEmpty(_pbbd->_pidlCur) && (SendMessage(_pbbd->_hwnd, WM_NCHITTEST, 0, lParam) == HTSYSMENU) && !SHRestricted(REST_NOVIEWCONTEXTMENU)) { IShellFolder *psfParent; LPCITEMIDLIST pidlChild; if (SUCCEEDED(IEBindToParentFolder(_pbbd->_pidlCur, &psfParent, &pidlChild))) { IContextMenu * pcm; HRESULT hres = psfParent->GetUIObjectOf(_pbbd->_hwnd, 1, (LPCITEMIDLIST*)&pidlChild, IID_IContextMenu, NULL, (void **)&pcm); if (SUCCEEDED(hres)) { HMENU hpopup = LoadMenuPopup(MENU_SYSPOPUP); if (hpopup) { pcm->QueryContextMenu(hpopup, GetMenuItemCount(hpopup), IDSYSPOPUP_FIRST, IDSYSPOPUP_LAST, 0); // Open doesn't make sense, since you're already looking at the folder ContextMenu_DeleteCommandByName(pcm, hpopup, IDSYSPOPUP_FIRST, L"open"); // These are just confusing ContextMenu_DeleteCommandByName(pcm, hpopup, IDSYSPOPUP_FIRST, L"delete"); ContextMenu_DeleteCommandByName(pcm, hpopup, IDSYSPOPUP_FIRST, L"link"); // The above may have allowed two separators to now be adjascent _SHPrettyMenu(hpopup); // For sendto menu, we go on even if this fails pcm->QueryInterface(IID_PPV_ARG(IContextMenu3, &_pcm)); if (GetMenuItemCount(hpopup) > 1) { // only do this if the context menu added something... // otherwise we end up with nothing but a "close" menu fProcessed=TRUE; UINT idCmd = TrackPopupMenu(hpopup, TPM_RETURNCMD | TPM_RIGHTBUTTON | TPM_LEFTALIGN, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), 0, _pbbd->_hwnd, NULL); switch(idCmd) { case 0: break; // canceled case IDSYSPOPUP_CLOSE: _pbbd->_pautoWB2->Quit(); break; default: { TCHAR szPath[MAX_PATH]; // unless we KNOW that our target can handle CommandInfoEx, we cannot send it to them CMINVOKECOMMANDINFO ici = { sizeof(ici), 0L, _pbbd->_hwnd, (LPSTR)MAKEINTRESOURCE(idCmd - IDSYSPOPUP_FIRST), NULL, NULL, SW_NORMAL }; #ifdef UNICODE CHAR szPathAnsi[MAX_PATH]; SHGetPathFromIDListA(_pbbd->_pidlCur, szPathAnsi); SHGetPathFromIDList(_pbbd->_pidlCur, szPath); ici.lpDirectory = szPathAnsi; // ici.lpDirectoryW = szPath; ici.fMask |= CMIC_MASK_UNICODE; #else SHGetPathFromIDList(_pbbd->_pidlCur, szPath); ici.lpDirectory = szPath; #endif pcm->InvokeCommand(&ici); break; } } } ATOMICRELEASE(_pcm); DestroyMenu(hpopup); } pcm->Release(); } psfParent->Release(); } } return fProcessed; } void CShellBrowser2::_OnClose(BOOL fPushed) { // We can't close if it's nested. if (fPushed) { #ifdef NO_MARSHALLING // IEUNIX : Mark this window for delayed deletion from the main message // pump. The problem is , if scripting closes a window and immediately // opens a modal dialog. The WM_CLOSE message for the browser window is // dispatched from the modal loop and we end up being called from the // window proc. This happens a lot on UNIX because we have multiple // browser windows on the same thread. if (!_fDelayedClose) _fDelayedClose = TRUE; else #endif MessageBeep(0); return; } if (SHIsRestricted2W(_pbbd->_hwnd, REST_NoBrowserClose, NULL, 0)) return; // We are not supposed to process WM_CLOSE if modeless operation is // disabled. if (S_OK == _DisableModeless()) { TraceMsg(DM_ERROR, "CShellBrowser2::_OnClose called when _DisableModeless() is TRUE. Ignored."); MessageBeep(0); UINT id = MLShellMessageBox(_pbbd->_hwnd, MAKEINTRESOURCE(IDS_CLOSEANYWAY), MAKEINTRESOURCE(IDS_TITLE), MB_OKCANCEL | MB_SETFOREGROUND | MB_ICONSTOP); if (id == IDCANCEL) { #ifdef NO_MARSHALLING _fReallyClosed = FALSE; #endif return; } } #ifdef NO_MARSHALLING _fReallyClosed = TRUE; #endif // we cannot close in the middle of creating view window. // someone dispatched messages and it wasn't us... // we WILL fault. // FEATURE: after ie3, we can flag this and close when we're done tryingto create the // viewwindow if (_pbbd->_fCreatingViewWindow) return; // The dochost needs to know that we are shutting // down so that it do such things send an Exec to // Trident to tell it we are unloading. // Exec(&CGID_Explorer, SBCMDID_ONCLOSE, 0, NULL, NULL); if (_MaySaveChanges() != S_FALSE) { // Close the browse context and release it. IHlinkBrowseContext * phlbc = NULL; if (_pbbd->_phlf) _pbbd->_phlf->GetBrowseContext(&phlbc); if (phlbc) { _pbbd->_phlf->SetBrowseContext(NULL); phlbc->Close(0); phlbc->Release(); } FireEvent_Quit(_pbbd->_pautoEDS); // this is once we KNOW that we're going to close down // give subclasses a chance to clean up #ifdef NO_MARSHALLING RemoveBrowserFromList(this); #endif _OnConfirmedClose(); } // // NOTES: Originally, this call was made only for RISC platform. // We, however, got a request from ISVs that their OCs should be // unloaded when the user closes the window. // // On risc NT we need to call CoFreeUnusedLibraries in case any x86 dlls // were loaded by Ole32. We call this after calling _OnClose so that // we can even unload the OC on the current page. (SatoNa) // CoFreeUnusedLibraries(); } // // stolen from comctl32 // // in: // hwnd to do check on // x, y in client coordinates // // returns: // TRUE the user began to drag (moved mouse outside double click rect) // FALSE mouse came up inside click rect // // FEATURE, should support VK_ESCAPE to cancel BOOL CheckForDragBegin(HWND hwnd, int x, int y) { RECT rcDragRadius; int cxDrag = GetSystemMetrics(SM_CXDRAG); int cyDrag = GetSystemMetrics(SM_CYDRAG); ASSERT((cxDrag > 1) && (cyDrag > 1)); // See if the user moves a certain number of pixels in any direction SetRect(&rcDragRadius, x - cxDrag, y - cyDrag, x + cxDrag, y + cyDrag); MapWindowRect(hwnd, NULL, &rcDragRadius); SetCapture(hwnd); do { MSG msg; // NTRAID 610356: Sleep the thread waiting for mouse input. Prevents pegging the CPU in a // PeekMessage loop. switch (MsgWaitForMultipleObjectsEx(0, NULL, INFINITE, QS_MOUSE, MWMO_INPUTAVAILABLE)) { case WAIT_OBJECT_0: { if (PeekMessage(&msg, NULL, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE)) { // See if the application wants to process the message... if (CallMsgFilter(&msg, MSGF_COMMCTRL_BEGINDRAG) == 0) { switch (msg.message) { case WM_LBUTTONUP: case WM_RBUTTONUP: case WM_LBUTTONDOWN: case WM_RBUTTONDOWN: { // Released the mouse without moving outside the // drag radius, not beginning a drag. ReleaseCapture(); return FALSE; } case WM_MOUSEMOVE: { if (!PtInRect(&rcDragRadius, msg.pt)) { // Moved outside the drag radius, beginning a drag. ReleaseCapture(); return TRUE; } break; } default: { TranslateMessage(&msg); DispatchMessage(&msg); break; } } } } break; } default: break; } // WM_CANCELMODE messages will unset the capture, in that // case I want to exit this loop } while (GetCapture() == hwnd); return FALSE; } void CShellBrowser2::_SetTheaterBrowserBar() { #ifndef DISABLE_FULLSCREEN if (_ptheater) { IDeskBar *pdbBar = NULL; FindToolbar(INFOBAR_TBNAME, IID_PPV_ARG(IDeskBar, &pdbBar)); _ptheater->SetBrowserBar(pdbBar, 120, 200); if (pdbBar) pdbBar->Release(); } #endif } void CShellBrowser2::_TheaterMode(BOOL fShow, BOOL fRestorePrevious) { #ifndef DISABLE_FULLSCREEN if (BOOLIFY(fShow) == BOOLIFY(_ptheater)) return; WINDOWPLACEMENT wp; RECT rc; if (fRestorePrevious && !fShow) { _ptheater->GetPreviousWindowPlacement(&wp, &rc); } else fRestorePrevious = FALSE; HRESULT hresResize = _pbsInner->AllowViewResize(FALSE); if (!fShow) { if (_ptheater) { if (fRestorePrevious) { PutBaseBrowserData()->_hwnd = _ptheater->GetMasterWindow(); SHSetWindowBits(_pbbd->_hwnd, GWL_STYLE, WS_DLGFRAME | WS_THICKFRAME | WS_BORDER, WS_DLGFRAME | WS_THICKFRAME | WS_BORDER); SetWindowPos(_pbbd->_hwnd, NULL, 0, 0,0,0,SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE|SWP_FRAMECHANGED); } delete _ptheater; _ptheater = NULL; } } else { _SaveITbarLayout(); _SaveState(); SHSetWindowBits(_pbbd->_hwnd, GWL_STYLE, WS_DLGFRAME | WS_THICKFRAME, 0); // if we're going to theater mode, don't allow best fit stuff _fsd._fs.fFlags &= ~FWF_BESTFITWINDOW; HWND hwndToolbar = NULL; if (_GetITBar()) _GetITBar()->GetWindow(&hwndToolbar); _ptheater = new CTheater(_pbbd->_hwnd, hwndToolbar, (IOleCommandTarget*)this); if (_ptheater) { _SetTheaterBrowserBar(); // the progress control is a bit special in this mode. we pull this out and make it topmost. _ShowHideProgress(); } } // the itbar is special in that it stays with the auto-hide window. // it needs to know about theater mode specially // Also, set _ptheater->_fAutoHideToolbar to _pitbar->_fAutoHide VARIANT vOut = { VT_I4 }; vOut.lVal = FALSE; // default: no auto hide explorer toolbar IUnknown_Exec(_GetITBar(), &CGID_PrivCITCommands, CITIDM_THEATER, fShow ? THF_ON : THF_OFF, &vOut, &vOut); if (_ptheater) { _ptheater->SetAutoHideToolbar(vOut.lVal); } _pbsInner->AllowViewResize(hresResize == S_OK); SUPERCLASS::OnSize(SIZE_RESTORED); if (_ptheater) _ptheater->Begin(); // kick start! // notify trident that it's ambients are invalid to force // it to re-query us for the flat property if (_pbbd->_pctView) { VARIANTARG vaIn; vaIn.vt = VT_I4; vaIn.lVal = DISPID_UNKNOWN; _pbbd->_pctView->Exec(&CGID_ShellDocView, SHDVID_AMBIENTPROPCHANGE, NULL, &vaIn, NULL); } if (_pxtb) { UINT uiState; if (SUCCEEDED(_pxtb->GetState(&CLSID_CommonButtons, TBIDM_THEATER, &uiState))) { if (_ptheater) uiState |= TBSTATE_CHECKED; else uiState &= ~TBSTATE_CHECKED; _pxtb->SetState(&CLSID_CommonButtons, TBIDM_THEATER, uiState); } } if (!_ptheater && !_fShowMenu) IUnknown_Exec(_GetITBar(), &CGID_PrivCITCommands, CITIDM_SHOWMENU, FALSE, NULL, NULL); if (fRestorePrevious) { SetWindowPos(_pbbd->_hwnd, NULL, rc.left, rc.top, RECTWIDTH(rc), RECTHEIGHT(rc), 0); if (IsWindowVisible(_pbbd->_hwnd)) { ShowWindow(_pbbd->_hwnd, wp.showCmd); SetWindowPlacement(_pbbd->_hwnd, &wp); } } #endif /* !DISABLE_FULLSCREEN */ } BOOL CShellBrowser2::_OnSysMenuClick(BOOL bLeftClick, WPARAM wParam, LPARAM lParam) { POINT pt = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)}; DWORD dwStart = GetTickCount(); MapWindowPoints(NULL, _pbbd->_hwnd, &pt, 1); if (!CheckForDragBegin(_pbbd->_hwnd, pt.x, pt.y)) { if (bLeftClick) { DWORD dwDelta = (GetTickCount() - dwStart); DWORD dwDblClick = GetDoubleClickTime(); if (dwDelta < dwDblClick) { // HACK: use the lParam (coords) as the timer ID to communicate // that to the WM_TIMER handler // // HACK: store the timer id in a global. Since there's only one // double-click on a sysmenu at a time, this should be fine. if (g_sysmenuTimer) KillTimer(_GetCaptionWindow(), g_sysmenuTimer); // We are special casing 0 as meaning there is no timer, so if the coords come in at // 0 then cheat them to 1. if (lParam == 0) lParam++; g_sysmenuTimer = SetTimer(_GetCaptionWindow(), lParam, dwDblClick - dwDelta, NULL); } else DefWindowProcWrap(_pbbd->_hwnd, WM_CONTEXTMENU, (WPARAM)_pbbd->_hwnd, lParam); } else SendMessage(_pbbd->_hwnd, WM_CONTEXTMENU, (WPARAM)_pbbd->_hwnd, lParam); return FALSE; } IOleCommandTarget *pcmdt = NULL; if (_pbbd->_pautoWB2) { (_pbbd->_pautoWB2)->QueryInterface(IID_PPV_ARG(IOleCommandTarget, &pcmdt)); ASSERT(pcmdt); } BOOL fRet = DoDragDropWithInternetShortcut(pcmdt, _pbbd->_pidlCur, _pbbd->_hwnd); if (pcmdt) pcmdt->Release(); return fRet; } void _SetWindowsListMarshalled(IWebBrowser2 *pautoWB2) { IEFrameAuto* pief; if (SUCCEEDED(pautoWB2->QueryInterface(IID_IEFrameAuto, (void **)&pief))) { pief->OnWindowsListMarshalled(); pief->Release(); } } BOOL CShellBrowser2::_OnTimer(UINT_PTR idTimer) { BOOL fResult = FALSE; // HACK: _OnSysMenuClick uses the cursor coords as the timer ID. // So first check if g_sysmenuTimer is set before checking for // standard timer IDs. if (g_sysmenuTimer == idTimer) { KillTimer(_GetCaptionWindow(), g_sysmenuTimer); g_sysmenuTimer = 0; // the timer ID is the lParam from the left click! SendMessage(_GetCaptionWindow(), WM_SYSMENU, 0, idTimer); fResult = TRUE; } else { switch (idTimer) { case SHBTIMER_MENUSELECT: KillTimer(_pbbd->_hwnd, SHBTIMER_MENUSELECT); fResult = TRUE; if (_pidlMenuSelect) { _DisplayFavoriteStatus(_pidlMenuSelect); Pidl_Set(&_pidlMenuSelect, NULL); } break; } } return fResult; } void CShellBrowser2::_OnActivate(UINT uMsg, WPARAM wParam, LPARAM lParam) { if (LOWORD(wParam) == WA_INACTIVE) _fActivated = FALSE; else _fActivated = TRUE; if (_pbbd->_hwndView) SendMessage(_pbbd->_hwndView, uMsg, wParam, lParam); if (LOWORD(wParam) != WA_INACTIVE) { // remember who had focus last, since trident will // grab focus on an OnFrameWindowActivate(TRUE) int itbLast = _pbsOuter->_get_itbLastFocus(); _pbsOuter->OnFrameWindowActivateBS(TRUE); if (itbLast != ITB_VIEW) { // restore focus to its rightful owner LPTOOLBARITEM ptbi = _GetToolbarItem(itbLast); if (ptbi) IUnknown_UIActivateIO(ptbi->ptbar, TRUE, NULL); } } else { #ifdef KEYBOARDCUES if (_pbbd->_hwnd) { SendMessage(_pbbd->_hwnd, WM_CHANGEUISTATE, MAKEWPARAM(UIS_SET, UISF_HIDEFOCUS | UISF_HIDEACCEL), 0); } #endif _pbsOuter->OnFrameWindowActivateBS(FALSE); } } // Main window proc for CShellBrowser2 LRESULT CShellBrowser2::WndProcBS(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { LRESULT lRet = 0; if (_TranslateMenuMessage(hwnd, uMsg, &wParam, &lParam, &lRet)) return lRet; switch(uMsg) { case WMC_DISPATCH: BSTR Url; { HRESULT hres; switch(wParam) { case DSID_NOACTION: return S_OK; case DSID_NAVIGATEIEBROWSER: // // APPCOMPAT: To be fully compatible with IE 2.0, we don't want to use // the window that has a navigation in progress. Enabling this code, // however, causes some problem with the very first DDE. I need to // investigate more, IF we need that level of compatibility. (SatoNa) // // this is only used for IE Browser. // if this is not in iemode, then fail. // this prevents us from reusing C:\ to navigate to www if (!v_IsIEModeBrowser()) return E_FAIL; ASSERT(lParam); if (!lParam) break; Url = ((DDENAVIGATESTRUCT*)lParam)->wszUrl; hres = _pbbd->_pautoWB2->Navigate(Url, NULL, NULL, NULL, NULL); return hres; break; case DSID_GETLOCATIONURL: return _pbbd->_pautoWB2->get_LocationURL((BSTR*)lParam); case DSID_GETLOCATIONTITLE: return _pbbd->_pautoWB2->get_LocationName((BSTR*)lParam); case DSID_GETHWND: *(HWND*)lParam = hwnd; return S_OK; #if 0 case DSID_CANCEL: return _pbbd->_pautoWB2->Stop(); #endif case DSID_EXIT: return _pbbd->_pautoWB2->Quit(); } } return (LRESULT)HRESULT_FROM_WIN32(ERROR_BUSY); case CWM_CLONEPIDL: if (_pbbd->_pidlCur) { return (LRESULT)SHAllocShared(_pbbd->_pidlCur, ILGetSize(_pbbd->_pidlCur), (DWORD)wParam); } break; case CWM_SELECTITEM: { LPITEMIDLIST pidl = (LPITEMIDLIST)SHLockShared((HANDLE)lParam, GetCurrentProcessId()); if (pidl) { if (_pbbd->_psv) _pbbd->_psv->SelectItem(pidl, (UINT)wParam); SHUnlockShared(pidl); } SHFreeShared((HANDLE)lParam, GetCurrentProcessId()); // Receiver responsible for freeing break; } case CWM_THEATERMODE: _TheaterMode(BOOLFROMPTR(wParam), !wParam); break; case CWM_GLOBALSTATECHANGE: // need to update the title if (wParam == CWMF_GLOBALSTATE) _SetTitle(NULL); else if (wParam == CWMF_SECURITY) { _UpdateZonesPane(NULL); } break; case CWM_FSNOTIFY: _OnFSNotify(wParam, lParam); break; case CWM_UPDATEBACKFORWARDSTATE: _UpdateBackForwardStateNow(); break; case CWM_SHOWDRAGIMAGE: return DAD_ShowDragImage((BOOL)lParam); case WM_ENDSESSION: TraceMsg(DM_SHUTDOWN, "csb.wp: WM_ENDSESSION wP=%d lP=%d", wParam, lParam); if (wParam && IsWindowVisible(_pbbd->_hwnd) && _pbbd->_pidlCur && !_fUISetByAutomation) { TraceMsg(DM_SHUTDOWN, "csb.wp: call AddToRestartList"); if (!IsBrowserFrameOptionsSet(_pbbd->_psf, BFO_NO_REOPEN_NEXT_RESTART)) AddToRestartList(v_RestartFlags(), _pbbd->_pidlCur); // for now we use the same 12-hour (SessionTime) rule // possibly we should just do it always? UEMFireEvent(&UEMIID_BROWSER, UEME_CTLSESSION, UEMF_XEVENT, FALSE, -1); if (!g_bRunOnNT5) { // for down-level guys (old explorer), fake a shell end session too UEMFireEvent(&UEMIID_SHELL, UEME_CTLSESSION, UEMF_XEVENT, FALSE, -1); } // And make sure we have saved it's state out TraceMsg(DM_SHUTDOWN, "csb.wp: call _SaveState"); _SaveState(); } TraceMsg(DM_SHUTDOWN, "csb.wp: WM_ENDSESSION return 0"); break; case WM_TIMER: if (!_OnTimer(wParam)) goto DoDefault; break; case WM_NCLBUTTONDOWN: case WM_NCRBUTTONDOWN: if (wParam != HTSYSMENU) goto DoDefault; _OnSysMenuClick(uMsg == WM_NCLBUTTONDOWN, wParam, lParam); break; case WM_NCLBUTTONDBLCLK: // We fault while shutting down the window if the timing is bad. // We're not sure why, but USER get's mightily confused. The only // difference between this scheme and a normal double-click-on-sysmenu // is the timer we have hanging around. Kill the timer before // processing this message. Hopefully that will work [mikesh/cheechew] // // HACK: remember this timer id is stored in a global variable // if (g_sysmenuTimer) { KillTimer(_GetCaptionWindow(), g_sysmenuTimer); g_sysmenuTimer = 0; } // We still want to process this DBLCLK goto DoDefault; case WM_CONTEXTMENU: if (!v_OnContextMenu(wParam, lParam)) goto DoDefault; break; case WM_WININICHANGE: { DWORD dwSection = SHIsExplorerIniChange(wParam, lParam); // Hack for NT4 and Win95, where there is no SPI_GETMENUSHOWDELAY // Don't need to check wParam == SPI_SETMENUSHOWDELAY since we // always query afresh on NT5/Win98. if (dwSection & EICH_SWINDOWS) g_lMenuPopupTimeout = -1; /* in case MenuShowDelay changed */ // Transitioning to/from "Working Offline" just broadcasts (0,0) // so that's all we listen for if (dwSection == EICH_UNKNOWN) { _ReloadTitle(); _ReloadStatusbarIcon(); } } goto DoDefault; case WM_INITMENUPOPUP: v_OnInitMenuPopup((HMENU)wParam, LOWORD(lParam), HIWORD(lParam)); v_ForwardMenuMsg(uMsg, wParam, lParam); break; case WM_MENUSELECT: if (_ShouldForwardMenu(uMsg, wParam, lParam)) { ForwardViewMsg(uMsg, wParam, lParam); } else { BOOL fIsPopup = GET_WM_MENUSELECT_FLAGS(wParam, lParam) & MF_POPUP; if ((!_OnMenuSelect(wParam, lParam, 0) && (fIsPopup || IsInRange(LOWORD(wParam), FCIDM_SHVIEWFIRST, FCIDM_SHVIEWLAST))) || (_fDispatchMenuMsgs && fIsPopup)) { ForwardViewMsg(uMsg, wParam, lParam); } } break; case WM_EXITSIZEMOVE: _fDisallowSizing = FALSE; break; case WM_WINDOWPOSCHANGING: if (_fDisallowSizing) { LPWINDOWPOS pwp = (LPWINDOWPOS)lParam; pwp->flags |= SWP_NOMOVE | SWP_NOSIZE; } break; case WM_ENTERSIZEMOVE: if (_ptheater) _fDisallowSizing = TRUE; break; case WM_EXITMENULOOP: case WM_ENTERMENULOOP: ForwardViewMsg(uMsg, wParam, lParam); break; case WM_DRAWITEM: case WM_MEASUREITEM: if (_ShouldForwardMenu(uMsg, wParam, lParam)) ForwardViewMsg(uMsg, wParam, lParam); else { UINT idCmd; switch (uMsg) { case WM_MEASUREITEM: idCmd = GET_WM_COMMAND_ID(((MEASUREITEMSTRUCT *)lParam)->itemID, 0); break; case WM_DRAWITEM: idCmd = GET_WM_COMMAND_ID(((LPDRAWITEMSTRUCT)lParam)->itemID, 0); break; } if (InRange(idCmd, FCIDM_SEARCHFIRST, FCIDM_SEARCHLAST) && _pcmSearch) _pcmSearch->HandleMenuMsg(uMsg, wParam, lParam); else if (_pcmNsc && IsInRange(idCmd, FCIDM_FILECTX_FIRST, FCIDM_FILECTX_LAST)) _pcmNsc->HandleMenuMsg(uMsg, wParam, lParam); else if (_pcm && (_pcm->HandleMenuMsg(uMsg, wParam, lParam) == S_OK)) { // the context menu ate it } else { v_ForwardMenuMsg(uMsg, wParam, lParam); } } break; case WM_QUERYENDSESSION: TraceMsg(DM_SHUTDOWN, "csb.wp: WM_QUERYENDSESSION"); #ifdef DEBUG if (S_OK == _DisableModeless()) { TraceMsg(DM_WARNING, "CSB::WndProc got WM_QUERYENDSESSION when disabled"); MessageBeep(0); UINT id = MLShellMessageBox(_pbbd->_hwnd, MAKEINTRESOURCE(IDS_CLOSEANYWAY), MAKEINTRESOURCE(IDS_TITLE), MB_OKCANCEL | MB_SETFOREGROUND | MB_ICONSTOP); if (id==IDCANCEL) { return FALSE; } } #endif // Try calling something that will call SHGetPathFromIDList to make sure we won't // call GetProcAddress while processing the WM_ENDSESSION... if (_pbbd->_pidlCur) HackToPrepareForEndSession(_pbbd->_pidlCur); return TRUE; // OK to close case WM_CLOSE: #ifdef NO_MARSHALLING _OnClose(_fOnIEThread); #else _OnClose(TRUE); #endif break; case PUI_OFFICE_COMMAND: { switch (wParam) { case PLUGUI_CMD_SHUTDOWN: { HRESULT hr; VARIANT v; // first, kill the internet options modal // property sheet if it exists // it might be open because that's one of // out UI lang change scenarios V_VT(&v) = VT_BYREF; v.byref = NULL; if (_pbbd != NULL && _pbbd->_pctView != NULL) { hr = _pbbd->_pctView->Exec(&CGID_ShellDocView, SHDVID_GETOPTIONSHWND, 0, NULL, &v); if (SUCCEEDED(hr)) { ASSERT(V_VT(&v) == VT_BYREF); if (v.byref != NULL) { // close the lang change modal property sheet SendMessage((HWND)v.byref, WM_CLOSE, NULL, NULL); } } } // now try to close the browser in general if (_pbbd != NULL && _pbbd->_pautoWB2 != NULL) _pbbd->_pautoWB2->Quit(); break; } case PLUGUI_CMD_QUERY: { HMODULE hMod; // answer if we're an iexplore.exe process because // that means we're not sharing any dlls with the shell hMod = GetModuleHandle(TEXT("IEXPLORE.EXE")); if (hMod != NULL && !g_bRunOnNT5) { PLUGUI_QUERY puiQuery; ASSERT(!g_bRunOnNT5); // we indicate that we participate in plugUI shutdown by // returning the version number for Office 9 puiQuery.uQueryVal = 0; puiQuery.PlugUIInfo.uMajorVersion = OFFICE_VERSION_9; puiQuery.PlugUIInfo.uOleServer = FALSE; return puiQuery.uQueryVal; } break; } } // switch (wParam) break; // PUI_OFFICE_COMMAND } case WM_SYSCOMMAND: // // WARNING: User uses low four bits for some undocumented feature // (only for SC_*). We need to mask those bits to make this case // statement work. // switch (wParam & 0xfff0) { case SC_MAXIMIZE: if (GetKeyState(VK_CONTROL) < 0) { LPTOOLBARITEM ptbi = _GetToolbarItem(ITB_ITBAR); if (ptbi->fShow) PostMessage(_pbbd->_hwnd, CWM_THEATERMODE, TRUE, 0); else goto DoDefault; } else goto DoDefault; break; case SC_CLOSE: // Make it posted so that we can detect if it's nested. PostMessage(_pbbd->_hwnd, WM_CLOSE, 0, 0); break; case SC_MINIMIZE: goto DoDefault; case SC_RESTORE: if (_ptheater && !_fMinimized) { PostMessage(_pbbd->_hwnd, CWM_THEATERMODE, FALSE, 0); return 0; } goto DoDefault; default: goto DoDefault; } break; case WM_SIZE: // WARNING: Remember that we won't get WM_SIZE if we directly process // WM_WINDOWPOSCHANGED. { BOOL fMinimized = (wParam == SIZE_MINIMIZED); if (BOOLIFY(_fMinimized) != fMinimized) { TraceMsg(DM_ONSIZE, "SB::_WndProc WM_SIZE _fMinimized %d -> %d", _fMinimized, fMinimized); _fMinimized = fMinimized; // Pause/Resume toolbars (intentionally ignores _pbbd->_psvPending). VARIANT var = { 0 }; var.vt = VT_I4; var.lVal = !_fMinimized; _ExecChildren(NULL, TRUE, NULL, OLECMDID_ENABLE_INTERACTION, OLECMDEXECOPT_DONTPROMPTUSER, &var, NULL); // Pause/Resule the view (refrelcts _pbbd->_psvPending too). _PauseOrResumeView(_fMinimized); } } #ifndef DISABLE_FULLSCREEN if (_ptheater && !_fMinimized) _ptheater->RecalcSizing(); #endif goto DoDefault; case WM_ACTIVATE: _OnActivate(uMsg, wParam, lParam); break; case WM_SETFOCUS: goto DoDefault; case WM_MENUCHAR: { LRESULT lres = 0; // Forwarding for IContextMenu3. UINT idCmd = GetMenuItemID((HMENU)lParam, 0); // approximately correct: assume the first item on the menu identifies the range if (_pcm && _pcm->HandleMenuMsg2(uMsg, wParam, lParam, &lres) == S_OK) ; // do nothing else if (_pcmSearch && _pcmSearch->HandleMenuMsg2(uMsg, wParam, lParam, &lres) == S_OK) ; // do nothing else if (_pcmNsc && InRange(idCmd, FCIDM_FILECTX_FIRST, FCIDM_FILECTX_LAST)) SHForwardContextMenuMsg(_pcmNsc, uMsg, wParam, lParam, &lres, FALSE); else lres = v_ForwardMenuMsg(uMsg, wParam, lParam); return lres; } break; case WM_CREATE: #ifdef KEYBOARDCUES SendMessage(hwnd, WM_CHANGEUISTATE, MAKEWPARAM(UIS_INITIALIZE, 0), 0); #endif lRet = SUPERCLASS::WndProcBS(hwnd, uMsg, wParam, lParam); if (lRet) { _OnClose(FALSE); _GetMenuBand(TRUE); } return lRet; case WMC_MARSHALIDISPATCHSLOW: { #ifndef NO_MARSHALLING IStream *pIStream; HRESULT hres = CreateStreamOnHGlobal(NULL, TRUE, &pIStream); if (SUCCEEDED(hres)) { HANDLE hShared = NULL; _fMarshalledDispatch = TRUE; hres = CoMarshalInterface(pIStream, IID_IDispatch, _pbbd->_pautoWB2, MSHCTX_NOSHAREDMEM, NULL, MSHLFLAGS_NORMAL); if (SUCCEEDED(hres)) { _SetWindowsListMarshalled(_pbbd->_pautoWB2); ULARGE_INTEGER uliPos; const LARGE_INTEGER li = {0,0}; pIStream->Seek(li, STREAM_SEEK_CUR, &uliPos); // And point back to the beginning... pIStream->Seek(li, STREAM_SEEK_SET, NULL); hShared = SHAllocShared(NULL, uliPos.LowPart + sizeof(DWORD), (DWORD)lParam); if (hShared) { LPBYTE pv = (LPBYTE)SHLockShared(hShared, (DWORD)lParam); if (pv) { *((DWORD*)pv) = uliPos.LowPart; pIStream->Read(pv + sizeof(DWORD), uliPos.LowPart, NULL); SHUnlockShared(pv); } else { SHFreeShared(hShared, (DWORD)lParam); hShared = NULL; } } } pIStream->Release(); return (LRESULT)hShared; } #else IDispatch **idispTemp = (IDispatch**)lParam; *idispTemp = _pbbd->_pautoWB2; return S_OK; #endif } case WM_GETOBJECT: if (OBJID_MENU == (DWORD)lParam) { IAccessible* pacc; IMenuBand* pmb = _GetMenuBand(FALSE); if (pmb && SUCCEEDED(IUnknown_QueryService(pmb, SID_SMenuBandChild, IID_PPV_ARG(IAccessible, &pacc)))) { lRet = LresultFromObject(IID_IAccessible, wParam, pacc); pacc->Release(); return lRet; } } break; default: lRet = _WndProcBSNT5(hwnd, uMsg, wParam, lParam); if (lRet) return lRet; if (_nMBIgnoreNextDeselect == uMsg) { _fIgnoreNextMenuDeselect = TRUE; TraceMsg(TF_MENUBAND, "MenuBand: Shbrowse.cpp received our private MBIgnoreNextDeselect"); break; } else if (GetDDEExecMsg() == uMsg) { ASSERT(lParam && 0 == ((LPNMHDR)lParam)->idFrom); DDEHandleViewFolderNotify(this, _pbbd->_hwnd, (LPNMVIEWFOLDER)lParam); LocalFree((LPNMVIEWFOLDER)lParam); return TRUE; } else if (g_msgMSWheel == uMsg) { // Frame doesn't have scrollbar, let the view have a crack at it (309709) return SendMessage(_pbbd->_hwndView, uMsg, wParam, lParam); } DoDefault: lRet = SUPERCLASS::WndProcBS(hwnd, uMsg, wParam, lParam); if (WM_COMMAND == uMsg) { IUnknown_SetSite(_pcmNsc, NULL); ATOMICRELEASE(_pcmNsc); } return lRet; } return 0; } HRESULT CShellBrowser2::OnSetFocus() { TraceMsg(DM_FOCUS, "csb.osf: hf()=%d itbLast=%d", _HasToolbarFocus(), _get_itbLastFocus()); // forward to whoever had focus last (view or toolbar). i think this // was added for ie4:55511 to fix pblm w/ tabbing away from IE and // then back. note the check of _get_itbLastFocus w/o the usual // _HasToolbarFocus/_FixToolbarFocus magic... // // this used to be in CCB::OSF but that's bogus since in the desktop // case, this means once a deskbar (e.g. address) has focus, we can // never get focus back on the desktop (nt5:167864). if (_get_itbLastFocus() == ITB_VIEW) { // forward it on to view (in basesb) _pbsInner->OnSetFocus(); } else { LPTOOLBARITEM ptbi = _GetToolbarItem(_get_itbLastFocus()); if (ptbi) IUnknown_UIActivateIO(ptbi->ptbar, TRUE, NULL); } return 0; } LRESULT CALLBACK IEFrameWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { LRESULT lResult = 0; CShellBrowser2* psb = (CShellBrowser2*)GetWindowPtr0(hwnd); switch(uMsg) { case WM_NCCREATE: { IETHREADPARAM* piei = (IETHREADPARAM*)((LPCREATESTRUCT)lParam)->lpCreateParams; ASSERT(psb == NULL); if (piei->uFlags & COF_EXPLORE) { CExplorerBrowser_CreateInstance(hwnd, (void **)&psb); } else { CShellBrowser2_CreateInstance(hwnd, (void **)&psb); } if (psb) { SetWindowLongPtr(hwnd, 0, (LONG_PTR)psb); _InitAppGlobals(); // Hack: Let's try only registering dde on iexplorer windows for // shell speed. (ie ignore shell folders) DWORD dwAttr = SFGAO_FOLDER; if ((!(piei->pidl && SUCCEEDED(IEGetAttributesOf(piei->pidl, &dwAttr)) && (dwAttr & SFGAO_FOLDER))) || (piei->uFlags & COF_FIREEVENTONDDEREG)) { // // Tell IEDDE that a new browser window is available. // IEDDE_NewWindow(hwnd); // // Fire the DdeRegistered event if necessary. // if (piei->uFlags & COF_FIREEVENTONDDEREG) { ASSERT(piei->szDdeRegEvent[0]); FireEventSzW(piei->szDdeRegEvent); } } return psb->WndProcBS(hwnd, uMsg, wParam, lParam); } else { return 0; } } case WM_CREATE: { lResult = psb ? psb->WndProcBS(hwnd, uMsg, wParam, lParam) : DefWindowProc(hwnd, uMsg, wParam, lParam); // if we have a psb and WndProc() failed (!lResult), then fall through // and process the WM_NCDESTROY. if (!psb || !lResult) break; if (psb) psb->_OnClose(FALSE); // Fall Thru because we need to clean up since the create failed. // fall through } case WM_NCDESTROY: // // Tell IEDDE that a browser window is no longer available. // IEDDE_WindowDestroyed(hwnd); // WM_NCDESTROY is supposed to be the last message we ever // receive, but let's be paranoid just in case... SetWindowLongPtr(hwnd, 0, (LONG_PTR)0); // psb may be NULL if we failed to create the window. An // Example includes using Start->Run to open a window to // a UNC share that the user doesn't have permissions to see. if (psb) { psb->PutBaseBrowserData()->_hwnd = NULL; if (psb->_dwRegisterWinList) { if (psb->_fMarshalledDispatch) { IShellWindows* psw = WinList_GetShellWindows(TRUE); if (psw) { psw->Revoke(psb->_dwRegisterWinList); psw->Release(); } } else { if (psb->_psw) psb->_psw->Revoke(psb->_dwRegisterWinList); } } ATOMICRELEASE(psb->_psw); psb->_fMarshalledDispatch = 0; psb->_dwRegisterWinList = 0; ATOMICRELEASE(psb->_punkMsgLoop); // Release the message loop if the browser is going away psb->Release(); } break; default: return psb ? psb->WndProcBS(hwnd, uMsg, wParam, lParam) : DefWindowProc(hwnd, uMsg, wParam, lParam); } return lResult; } // *** IShellBrowser methods *** (same as IOleInPlaceFrame) /*---------------------------------------------------------- Purpose: IShellBrowser::InsertMenusSB method */ HRESULT CShellBrowser2::InsertMenusSB(HMENU hmenu, LPOLEMENUGROUPWIDTHS lpMenuWidths) { RIP(IS_VALID_HANDLE(hmenu, MENU)); if (_hmenuTemplate) { HMENU hmenuSrc; if (_get_itbLastFocus() == ITB_VIEW && _pbbd->_uActivateState == SVUIA_ACTIVATE_FOCUS) { hmenuSrc = _hmenuTemplate; } else { hmenuSrc = _hmenuFull; } Shell_MergeMenus(hmenu, hmenuSrc, 0, 0, FCIDM_BROWSERLAST, MM_SUBMENUSHAVEIDS); lpMenuWidths->width[0] = 1; // File lpMenuWidths->width[2] = 2; // Edit, View lpMenuWidths->width[4] = 1; // Help } // Save this away so we can correctly build the menu list object _hmenuBrowser = hmenu; DEBUG_CODE(_DumpMenus(TEXT("InsertMenusSB"), TRUE);) return S_OK; } /*---------------------------------------------------------- Purpose: IShellBrowser::SetMenuSB method */ HRESULT CShellBrowser2::SetMenuSB(HMENU hmenu, HOLEMENU hmenuRes, HWND hwnd) { RIP(NULL == hmenu || IS_VALID_HANDLE(hmenu, MENU)); // A NULL hmenu means to reinstate the container's original menu if (hmenu) { _hmenuCur = hmenu; } else { if (_fRunningInIexploreExe) _hmenuCur = _hmenuPreMerged; else _hmenuCur = _hmenuTemplate; } _fDispatchMenuMsgs = FALSE; _fForwardMenu = FALSE; // Normally _hmenuBrowser is set by the caller of InsertMenusSB. // However, with the actual web browser, InsertMenusSB is never called. // That means _hmenuBrowse is either NULL or non-NULL but invalid. // So in that case assume hmenu is equivalent. This essentially makes // all messages get sent to the frame, which is what we want. HMENU hmenuBrowser; if (!IsMenu(_hmenuBrowser)) // We're calling IsMenu on purpose _hmenuBrowser = NULL; if (NULL != _hmenuBrowser) hmenuBrowser = _hmenuBrowser; else hmenuBrowser = hmenu; _menulist.Set(hmenu, hmenuBrowser); // Was the help menu merged? HMENU hmenuHelp = NULL; if (_pbbd->_pctView) { VARIANTARG vaOut = {0}; if (S_OK == _pbbd->_pctView->Exec(&CGID_ShellDocView, SHDVID_QUERYMERGEDHELPMENU, 0, NULL, &vaOut)) { // Yes; remove it from the list so it isn't accidentally // forwarded on. if (VT_INT_PTR == vaOut.vt) { hmenuHelp = (HMENU)vaOut.byref; ASSERT(IS_VALID_HANDLE(hmenuHelp, MENU)); _menulist.RemoveMenu(hmenuHelp); } VariantClearLazy(&vaOut); vaOut.vt = VT_EMPTY; vaOut.byref = NULL; if (S_OK == _pbbd->_pctView->Exec(&CGID_ShellDocView, SHDVID_QUERYOBJECTSHELPMENU, 0, NULL, &vaOut)) { if (VT_INT_PTR == vaOut.vt) { // Add the object's help submenu to the list so it gets forwarded HMENU hmenuObjHelp = (HMENU)vaOut.byref; ASSERT(IS_VALID_HANDLE(hmenuObjHelp, MENU)); _menulist.AddMenu(hmenuObjHelp); } VariantClearLazy(&vaOut); } } } // 80734: Was the Go To menu taken from the View menu and grafted onto the // main menu by DocHost? The menulist won't detect this graft, so we have // to check ourselves and make sure it's not marked as belonging to the // docobject. // // This test is duplicated in CDocObjectHost::_SetMenu MENUITEMINFO mii; mii.cbSize = sizeof(mii); mii.fMask = MIIM_SUBMENU; if (hmenu && _hmenuBrowser && GetMenuItemInfo(hmenu, FCIDM_MENU_EXPLORE, FALSE, &mii)) { HMENU hmenuGo = mii.hSubMenu; if (GetMenuItemInfo(_hmenuBrowser, FCIDM_MENU_EXPLORE, FALSE, &mii) && mii.hSubMenu == hmenuGo && _menulist.IsObjectMenu(hmenuGo)) { _menulist.RemoveMenu(hmenuGo); } } DEBUG_CODE(_hmenuHelp = hmenuHelp;) if (!_fKioskMode) { if (_fShowMenu) _SetMenu(_hmenuCur); else _SetMenu(NULL); } DEBUG_CODE(_DumpMenus(TEXT("SetMenuSB"), TRUE);); return S_OK; } /*---------------------------------------------------------- Purpose: Remove menus that are shared with other menus from the given browser menu. */ HRESULT CShellBrowser2::RemoveMenusSB(HMENU hmenuShared) { // Generally, there is no need to remove most of the menus because // they were cloned and inserted into this menu. However, the // Favorites menu is an exception because it is shared with // _hmenuFav. return S_OK; } void CShellBrowser2::_ShowHideProgress() { if (_hwndProgress) { UINT uShow = SW_SHOW; if (SendMessage(_hwndProgress, PBM_GETPOS, 0, 0) == 0) uShow = SW_HIDE; ShowWindow(_hwndProgress, uShow); TraceMsg(TF_SHDPROGRESS, "CShellBrowser2::_ShowHideProgress() uShow = %X", uShow); } } HRESULT CShellBrowser2::SendControlMsg(UINT id, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *pret) { HRESULT hres = SUPERCLASS::SendControlMsg(id, uMsg, wParam, lParam, pret); if (id == FCW_PROGRESS) { if (uMsg == PBM_SETRANGE32 || uMsg == PBM_SETPOS) _ShowHideProgress(); if (_ptheater && _ptheater->_hwndProgress) SendMessage(_ptheater->_hwndProgress, uMsg, wParam, lParam); } return hres; } HRESULT CShellBrowser2::_QIExplorerBand(REFIID riid, void **ppvObj) { *ppvObj = NULL; HRESULT hr = E_FAIL; IDeskBar* pdbBar; if (SUCCEEDED(FindToolbar(INFOBAR_TBNAME, IID_PPV_ARG(IDeskBar, &pdbBar))) && pdbBar) { IUnknown* punkBS; if (SUCCEEDED(pdbBar->GetClient(&punkBS))) { IBandSite* pbs; if (SUCCEEDED(punkBS->QueryInterface(IID_PPV_ARG(IBandSite, &pbs)))) { IDeskBand* pdbBand = FindBandByClsidBS(pbs, CLSID_ExplorerBand); if (pdbBand) { hr = pdbBand->QueryInterface(riid, ppvObj); pdbBand->Release(); } pbs->Release(); } punkBS->Release(); } pdbBar->Release(); } return hr; } HRESULT CShellBrowser2::GetControlWindow(UINT id, HWND * lphwnd) { // the defaults HRESULT hres = E_FAIL; *lphwnd = NULL; switch (id) { case FCW_INTERNETBAR: if (_GetITBar() && _GetToolbarItem(ITB_ITBAR)->fShow) hres = _GetITBar()->GetWindow(lphwnd); break; case FCW_TOOLBAR: *lphwnd = _hwndDummyTB; break; case FCW_STATUS: *lphwnd = _hwndStatus; break; case FCW_PROGRESS: if (!_hwndProgress && _hwndStatus) { _hwndProgress = CreateWindowEx(0, PROGRESS_CLASS, NULL, WS_CHILD | WS_CLIPSIBLINGS | PBS_SMOOTH, 0, 0, 1, 1, _hwndStatus, (HMENU)1, HINST_THISDLL, NULL); // we yank off this bit because we REALLY don't want it because // the status bar already draws this for us when we specify rects // // but the progress bar forces this bit on during creation if (_hwndProgress) SHSetWindowBits(_hwndProgress, GWL_EXSTYLE, WS_EX_STATICEDGE, 0); } *lphwnd = _hwndProgress; break; case FCW_TREE: { BOOL fExplorerBandVisible; if (SUCCEEDED(IsControlWindowShown(FCW_TREE, &fExplorerBandVisible)) && fExplorerBandVisible) { IOleWindow* pow; if (SUCCEEDED(_QIExplorerBand(IID_IOleWindow, (void**)&pow))) { pow->GetWindow(lphwnd); pow->Release(); } } } break; } if (*lphwnd) { hres = S_OK; } return hres; } //========================================================================== // //========================================================================== HRESULT CShellBrowser2::SetToolbarItems(LPTBBUTTON pViewButtons, UINT nButtons, UINT uFlags) { LPTBBUTTON pStart= NULL, pbtn= NULL; int nFirstDiff = 0, nTotalButtons = 0; BOOL bVisible = FALSE; if (uFlags & FCT_CONFIGABLE) { return S_OK; } // Allocate buffer for the default buttons plus the ones passed in // pStart = (LPTBBUTTON)LocalAlloc(LPTR, nButtons * sizeof(TBBUTTON)); if (!pStart) return S_OK; pbtn = pStart; nTotalButtons = 0; if (pViewButtons) { int i; for (i = nButtons - 1; i >= 0; --i) { // copy in the callers buttons // pbtn[i] = pViewButtons[i]; // make sure this is properly set to -1. // in win95, we had no strings so extensions couldn't set it, but some didn't initialize to -1 if ((!pbtn[i].iString || (pbtn[i].iString <= (MAX_TB_BUTTONS + NUMBER_SHELLGLYPHS - 1)))) { // We should not set our own shell iString to -1 ASSERT(pbtn[i].iString != pbtn[i].iBitmap); // comment about Hummingbird passing 0xc always COMPILETIME_ASSERT(MAX_TB_BUTTONS + NUMBER_SHELLGLYPHS >= 0xc); pbtn[i].iString = -1; } } pbtn += nButtons; nTotalButtons += nButtons; } if (_pxtb) { // for right now, disable customize for all old style views DWORD dwFlags = VBF_NOCUSTOMIZE; TCHAR szScratch[32]; if (_nTBTextRows == -1) { if (MLLoadString(IDS_SHELL_TB_TEXTROWS, szScratch, ARRAYSIZE(szScratch))) _nTBTextRows = (UINT)StrToInt(szScratch); else _nTBTextRows = 0; } if (_nTBTextRows == 1) dwFlags |= VBF_ONELINETEXT; else if (_nTBTextRows == 2) dwFlags |= VBF_TWOLINESTEXT; _pxtb->SetCommandTarget((IUnknown *)SAFECAST(this, IOleCommandTarget *), &CGID_ShellBrowser, dwFlags); if (_lpPendingButtons) LocalFree(_lpPendingButtons); _lpPendingButtons = (TBBUTTON*)pStart; _nButtonsPending = nTotalButtons; } else { LocalFree(pStart); } return S_OK; } #ifdef DEBUG //--------------------------------------------------------------------------- // Copy the exception info so we can get debug info for Raised exceptions // which don't go through the debugger. void _CopyExceptionInfo(LPEXCEPTION_POINTERS pep) { PEXCEPTION_RECORD per; per = pep->ExceptionRecord; TraceMsg(DM_ERROR, "Exception %x at %#08x.", per->ExceptionCode, per->ExceptionAddress); if (per->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) { // If the first param is 1 then this was a write. // If the first param is 0 then this was a read. if (per->ExceptionInformation[0]) { TraceMsg(DM_ERROR, "Invalid write to %#08x.", per->ExceptionInformation[1]); } else { TraceMsg(DM_ERROR, "Invalid read of %#08x.", per->ExceptionInformation[1]); } } } #else #define _CopyExceptionInfo(x) TRUE #endif #define SVSI_SELFLAGS (SVSI_SELECT|SVSI_FOCUSED|SVSI_DESELECTOTHERS|SVSI_ENSUREVISIBLE) void CShellBrowser2::_AfterWindowCreated(IETHREADPARAM *piei) { // // Let interested people know we are alive // if (piei->uFlags & COF_SELECT) { IShellView* psv = _pbbd->_psv ? _pbbd->_psv : _pbbd->_psvPending; if (psv) psv->SelectItem(piei->pidlSelect, SVSI_SELFLAGS); } // // Keep it hidden if this is the first instance which is started // with "/automation" flag or this object is being created as the // result of our CreateInstance. // if (!_fAutomation && !piei->piehs) { if (_fKioskMode) { // Turn off flag as we need to let the next function set it... _fKioskMode = FALSE; // Hack -1 implies ShowControlWindow((UINT)-1, TRUE); } UINT nCmdShow = piei->nCmdShow; BOOL fSetForeground = FALSE; BOOL fStartTheater = FALSE; // we need to do this setforegroundwindow // because of a bug in user. if the previous thread didn't have // activation, ShowWindow will NOT give us activation even though // it's supposed to switch (nCmdShow) { case SW_SHOWNORMAL: case SW_SHOWMAXIMIZED: case SW_SHOW: fSetForeground = TRUE; break; } if (_fUseIEPersistence) { fStartTheater = SHRegGetBoolUSValue(TEXT("Software\\Microsoft\\Internet Explorer\\Main"), TEXT("FullScreen"), FALSE, FALSE); } if (fStartTheater) { _TheaterMode(TRUE, FALSE); if (fSetForeground) nCmdShow = SW_SHOW; } MSG msg; if (!PeekMessage(&msg, _pbbd->_hwnd, WM_CLOSE, WM_CLOSE, PM_NOREMOVE)) { ShowWindow(_pbbd->_hwnd, nCmdShow); // // AT THIS POINT ALL DDE TRANSACTIONS SHOULD SUCCEED. THE BROWSER // WINDOW WAS ADDED TO THE DDE WINITEM LIST ON WM_NCCREATE, // AUTOMATION WAS REGISTERED AS STARTED ON THE OnCreate, // AND THE WINDOW IS NOW VISIBLE AS A PART OF THE SHOWWINDOW. // 99% OF ALL DDE STARTUP BUGS ARE CAUSED BY SOMEBODY CHECKING FOR // MESSAGES (PEEKMESSAGE, GETMESSAGE, INTERPROC SENDMESSAGE, ETC.) // BEFORE THIS POINT. // if (fSetForeground) SetForegroundWindow(_pbbd->_hwnd); } else { ASSERT(msg.hwnd == _pbbd->_hwnd); } } _SetTitle(NULL); // // Delay register our window now. // Note that we need to do it after SetEvent(piei->piehs->GetHevent()) to // avoid soft dead-lock in OLE, and we need to do it after the // ShowWindow above because this will allow DDE messages to get // sent to us. // // RegisterWindow() shouldnt have been called yet, but if it has, we dont want // to change its registration class from here. zekel 9-SEP-97 // ASSERT(!_fDidRegisterWindow); RegisterWindow(FALSE, (piei->uFlags & COF_EXPLORE) ? SWC_EXPLORER : SWC_BROWSER); // Delay loading accelerators from v_initmembers ASSERT(MLGetHinst()); HACCEL hacc = LoadAccelerators(MLGetHinst(), MAKEINTRESOURCE(ACCEL_MERGE)); ASSERT(hacc); SetAcceleratorMenu(hacc); // Send size so status bar shows SendMessage(_pbbd->_hwnd, WM_SIZE, 0, 0); // delay doing a bunch of registrations // things we don't want our subclass to inherit if (v_InitMembers == CShellBrowser2::v_InitMembers) { // register to get filesys notifications _uFSNotify = RegisterNotify(_pbbd->_hwnd, CWM_FSNOTIFY, NULL, SHELLBROWSER_FSNOTIFY_FLAGS, SHCNRF_ShellLevel | SHCNRF_InterruptLevel, TRUE); } SignalFileOpen(piei->pidl); } // // RegisterWindow() should only be called with Unregister if the caller // wants to insure that the new ShellWindowClass is used. this is used // by CIEFrameAuto to force the browser window in the 3rdParty winlist. // HRESULT CShellBrowser2::RegisterWindow(BOOL fForceReregister, int swc) { if (!_psw) _psw = WinList_GetShellWindows(FALSE); if (_psw) { if (fForceReregister && _fDidRegisterWindow) { _psw->Revoke(_dwRegisterWinList); _fDidRegisterWindow = FALSE; } if (!_fDidRegisterWindow) { // raymondc- HandleToLong should really be HANDLE_PTR or something - Browser folks need to fix the IDL _psw->Register(NULL, HandleToLong(_pbbd->_hwnd), swc, &_dwRegisterWinList); _fDidRegisterWindow = TRUE; _swcRegistered = swc; UpdateWindowList(); } return S_OK; } return E_FAIL; } LRESULT CALLBACK IEFrameWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); void InitializeExplorerClass() { static BOOL fInited = FALSE; if (!fInited) { ENTERCRITICAL; if (!fInited) { WNDCLASS wc = { 0 }; wc.style = CS_BYTEALIGNWINDOW; wc.lpfnWndProc = IEFrameWndProc; wc.cbWndExtra = sizeof(void *); wc.hInstance = HINST_THISDLL; wc.hIcon = LoadIcon(HinstShdocvw(), MAKEINTRESOURCE(ICO_TREEUP)); wc.hCursor = LoadCursor(NULL, IDC_SIZEWE); wc.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1); wc.lpszClassName = c_szExploreClass; RegisterClass(&wc); wc.hIcon = LoadIcon(HinstShdocvw(), MAKEINTRESOURCE(IDI_STATE_NORMAL)); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.lpszClassName = c_szIExploreClass; RegisterClass(&wc); // shell32 is stuck with this id forever since it came out on win95 #define IDI_FOLDEROPEN 5 // open folder wc.hIcon = LoadIcon(HinstShell32(), MAKEINTRESOURCE(IDI_FOLDEROPEN)); wc.lpszClassName = c_szCabinetClass; RegisterClass(&wc); // this needs to be set at the END.. // because otherwise a race condition occurs and some guys run throught the // outter most check and try to create before we're registered. fInited = TRUE; } LEAVECRITICAL; } } // compatability: we need to have the right class name so people can find our window // LPCTSTR _GetExplorerClassName(UINT uFlags) { if (uFlags & COF_EXPLORE) return c_szExploreClass; else if (uFlags & COF_IEXPLORE || WhichPlatform() == PLATFORM_BROWSERONLY) return c_szIExploreClass; else return c_szCabinetClass; } void TimedDispatchMessage(MSG *pmsg) { DWORD dwTime; if (g_dwStopWatchMode & SPMODE_MSGTRACE) dwTime = StopWatch_DispatchTime(TRUE, *pmsg, 0); DispatchMessage(pmsg); if (g_dwStopWatchMode) { if (g_dwStopWatchMode & SPMODE_MSGTRACE) StopWatch_DispatchTime(FALSE, *pmsg, dwTime); if ((g_dwStopWatchMode & SPMODE_SHELL) && (pmsg->message == WM_PAINT)) StopWatch_TimerHandler(pmsg->hwnd, 1, SWMSG_PAINT, pmsg); // Save tick count for paint msg } } void DesktopChannel(); void BrowserThreadProc(IETHREADPARAM* piei) { HMENU hmenu; HWND hwnd; DWORD dwExStyle = WS_EX_WINDOWEDGE; LONG cRefMsgLoop; // the ref count for this thread IUnknown *punkMsgLoop; // the ref object (wraps cRefMsgLoop) for this thread IUnknown *punkRefProcess; // the process ref this thread holds (may be none) #ifdef NO_MARSHALLING THREADWINDOWINFO *lpThreadWindowInfo = InitializeThreadInfoStructs(); if (!lpThreadWindowInfo) goto Done; #endif UINT tidCur = GetCurrentThreadId(); UINT uFlags = piei->uFlags; // Set our priority higher for startup so that we are not starved by background tasks and // other pesky system activity SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL); #ifndef NO_ETW_TRACING // Event trace for windows enable by shlwapi. if (g_dwStopWatchMode & SPMODE_EVENTTRACE) EventTraceHandler(EVENT_TRACE_TYPE_BROWSE_STARTFRAME, NULL); #endif if (g_dwStopWatchMode & (SPMODE_SHELL | SPMODE_BROWSER | SPMODE_JAVA | SPMODE_MSGTRACE)) StopWatch_MarkFrameStart(piei->uFlags & COF_EXPLORE ? " (explore)" : ""); punkRefProcess = piei->punkRefProcess; piei->punkRefProcess = NULL; // we took ownership LPWSTR pszCloseEvent = (piei->uFlags & COF_FIREEVENTONCLOSE) ? StrDupW(piei->szCloseEvent) : NULL; // if we're going to do desktop channel stuff, do it and return #ifdef ENABLE_CHANNELS if (piei->fDesktopChannel) { if (piei->pSplash) { piei->pSplash->Dismiss(); ATOMICRELEASE(piei->pSplash); } if (piei->uFlags & COF_FIREEVENTONDDEREG) { ASSERT(piei->szDdeRegEvent[0]); FireEventSzW(piei->szDdeRegEvent); } DesktopChannel(); goto Done; } #endif / ENABLE_CHANNELS TraceMsg(TF_SHDTHREAD, "BrowserThreadProc() - IE_ThreadProc(%x) just started.", tidCur); InitializeExplorerClass(); if (SUCCEEDED(SHCreateThreadRef(&cRefMsgLoop, &punkMsgLoop))) { if (tidCur == g_tidParking) { SHSetInstanceExplorer(punkMsgLoop); // we are process reference } SHSetThreadRef(punkMsgLoop); } // Set our title temporarily (for people who grab our title, like the SHEnumErrorMessage guy TCHAR szTempTitle[MAX_PATH]; if (piei->uFlags & COF_IEXPLORE) MLLoadString(IDS_TITLE, szTempTitle, ARRAYSIZE(szTempTitle)); else MLLoadString(IDS_CABINET, szTempTitle, ARRAYSIZE(szTempTitle)); // // APPCOMPAT - apps like WebCD require a non-null menu on the // browser. Thankfully USER won't draw a menuband on an empty hmenu. // hmenu = CreateMenu(); dwExStyle |= IS_BIDI_LOCALIZED_SYSTEM() ? dwExStyleRTLMirrorWnd | dwExStyleNoInheritLayout: 0L; hwnd = SHNoFusionCreateWindowEx(dwExStyle, _GetExplorerClassName(piei->uFlags), szTempTitle, WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, hmenu, HINST_THISDLL, piei); if (punkMsgLoop) punkMsgLoop->Release(); // browser (in open state) holds the ref if (piei->pSplash) { piei->pSplash->Dismiss(); ATOMICRELEASE(piei->pSplash); } if (hwnd) { if (g_dwStopWatchMode & SPMODE_SHELL) // Create the timer to start watching for paint messages StopWatch_TimerHandler(hwnd, 0, SWMSG_CREATE, NULL); CShellBrowser2* psb = (CShellBrowser2*)GetWindowPtr0(hwnd); if (psb) { #ifdef NO_MARSHALLING AddFirstBrowserToList(psb); #endif psb->AddRef(); psb->_AfterWindowCreated(piei); SHDestroyIETHREADPARAM(piei); piei = NULL; TraceMsg(TF_SHDTHREAD, "BrowserThreadProc() - IE_ThreadProc(%x) about to start the message loop", tidCur); BOOL fThreadPriorityHasBeenReset = FALSE; while (1) { MSG msg; BOOL fPeek; fPeek = PeekMessage(&msg, NULL, 0, 0, PM_REMOVE); if (fPeek) { #ifndef NO_ETW_TRACING if (g_dwStopWatchMode & SPMODE_EVENTTRACE) { if (msg.message == WM_KEYDOWN) { if (msg.wParam == VK_RETURN) { EventTraceHandler(EVENT_TRACE_TYPE_BROWSE_USERINPUTRET, NULL); } else if (msg.wParam == VK_BACK) { EventTraceHandler(EVENT_TRACE_TYPE_BROWSE_USERINPUTBACK, NULL); } else if (msg.wParam == VK_NEXT) { EventTraceHandler(EVENT_TRACE_TYPE_BROWSE_USERINPUTNEXT, NULL); } else if (msg.wParam == VK_PRIOR) { EventTraceHandler(EVENT_TRACE_TYPE_BROWSE_USERINPUTPRIOR, NULL); } } else if (msg.message == WM_LBUTTONUP) { EventTraceHandler(EVENT_TRACE_TYPE_BROWSE_USERINPUTLBUT, NULL); } } #endif if (g_dwStopWatchMode) StopWatch_CheckMsg(hwnd, msg, uFlags == COF_EXPLORE ? " (explore) " : ""); // Key off of WM_KEYDOWN to start timing #ifdef NO_MARSHALLING CShellBrowser2 *psbOld = psb; CShellBrowser2 *psb = CheckAndForwardMessage(lpThreadWindowInfo, psbOld, msg); if (!psb) psb = psbOld; #endif if (psb->_pbbd->_hwnd && IsWindow(psb->_pbbd->_hwnd)) { // // Directly dispatch WM_CLOSE message to distinguish nested // message loop case. // if ((msg.message == WM_CLOSE) && (msg.hwnd == psb->_pbbd->_hwnd)) { psb->_OnClose(FALSE); continue; } #ifdef NO_MARSHALLING HWND hwnd = GetActiveWindow(); if (!IsNamedWindow(hwnd, TEXT("Internet Explorer_TridentDlgFrame"))) { if (S_OK == psb->v_MayTranslateAccelerator(&msg)) continue; } else { DWORD dwExStyle = GetWindowLong(hwnd, GWL_EXSTYLE); if (dwExStyle & WS_EX_MWMODAL_POPUP) { if (S_OK == psb->v_MayTranslateAccelerator(&msg)) continue; } else { if (msg.message >= WM_KEYFIRST && msg.message <= WM_KEYLAST && (TranslateModelessAccelerator(&msg, hwnd) == S_OK)) continue; } } #else if (S_OK == psb->v_MayTranslateAccelerator(&msg)) continue; #endif } TranslateMessage(&msg); TimedDispatchMessage(&msg); } #ifdef NO_MARSHALLING else if ((cRefMsgLoop == 0) && (lpThreadWindowInfo->cWindowCount == 0)) #else else if (cRefMsgLoop == 0) #endif { TraceMsg(TF_SHDTHREAD, "BrowserThreadProc() - cRefMsgLoop == 0, done"); break; // exit while (1), no more refs on this thread } else { if (!fThreadPriorityHasBeenReset) { fThreadPriorityHasBeenReset = TRUE; // Reset our priority to normal now that we have finished the startup SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL); #ifdef PERF_LOGGING HANDLE hEvent = OpenEvent(EVENT_MODIFY_STATE, FALSE, TEXT("ExplorerWindowIdle")); if (hEvent) { SetEvent(hEvent); CloseHandle(hEvent); } #endif } WaitMessage(); if (g_dwStopWatchMode & SPMODE_MSGTRACE) StopWatch_SetMsgLastLocation(2); } } TraceMsg(TF_SHDTHREAD, "BrowserThreadProc() - IE_ThreadProc(%x) end of message loop", tidCur); psb->Release(); } } else { // Unregister any pending that may be there WinList_Revoke(piei->dwRegister); TraceMsg(TF_WARNING, "BrowserThreadProc() - IE_ThreadProc CreateWindow failed"); } #if defined(ENABLE_CHANNELS) || defined(NO_MARSHALLING) Done: #endif // Make sure we return the thread priority to normal in case this thread is re-used. SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL); if (pszCloseEvent) { FireEventSzW(pszCloseEvent); LocalFree(pszCloseEvent); } SHDestroyIETHREADPARAM(piei); if (punkRefProcess) punkRefProcess->Release(); #ifdef NO_MARSHALLING FreeThreadInfoStructs(); #endif } DWORD CALLBACK BrowserProtectedThreadProc(void *pv) { if (g_dwProfileCAP & 0x00000004) StartCAP(); HRESULT hrInit = OleInitialize(NULL); PostMessage(GetShellWindow(), DTM_SETAPPSTARTCUR, 0, 0); #ifdef DEBUG if (hrInit != S_OK) { TraceMsg(TF_WARNING, "BrowserProtectedThreadProc: OleInitialize returned %x ?!?", hrInit); } #endif ULONG_PTR dwCookie = 0; NT5_ActivateActCtx(NULL, &dwCookie); // Set to inherit the process context #if !defined(FULL_DEBUG) && (!defined(UNIX) || (defined(UNIX) && defined(GOLDEN))) EXCEPTION_RECORD exr; _try { BrowserThreadProc((IETHREADPARAM*)pv); } _except((exr = *((GetExceptionInformation())->ExceptionRecord), _CopyExceptionInfo(GetExceptionInformation()), UnhandledExceptionFilter(GetExceptionInformation()))) { LPCTSTR pszMsg = NULL; // we will try to display a message box to tell the user // that a thread has died... // if (GetExceptionCode() == STATUS_NO_MEMORY) pszMsg = MAKEINTRESOURCE(IDS_EXCEPTIONNOMEMORY); else if (WhichPlatform() == PLATFORM_BROWSERONLY) { pszMsg = MAKEINTRESOURCE(IDS_EXCEPTIONMSG); } // don't show the message box on non-nt systems // older than millennium (with an older shell) // see IE5.5 bug#93165 else if (g_fRunningOnNT || (GetUIVersion() < 5)) { pszMsg = MAKEINTRESOURCE(IDS_EXCEPTIONMSGSH); } if (pszMsg) { MLShellMessageBox(NULL, pszMsg, MAKEINTRESOURCE(IDS_TITLE), MB_ICONEXCLAMATION|MB_SETFOREGROUND); } if (GetExceptionCode() != STATUS_NO_MEMORY) IEWriteErrorLog(&exr); } __endexcept #else // IEUNIX : This exception handler should only be used in Release // version of the product. We are disabling it for debugging purposes. BrowserThreadProc((IETHREADPARAM*)pv); #endif NT5_DeactivateActCtx(dwCookie); if (SUCCEEDED(hrInit)) { OleUninitialize(); } return 0; } // Check if this IETHREADPARAM/LPITEMIDLIST requires launch in a new process // and if so launch it and return TRUE. // BOOL TryNewProcessIfNeeded(LPCITEMIDLIST pidl) { if (pidl && IsBrowseNewProcessAndExplorer() && IsBrowserFrameOptionsPidlSet(pidl, BFO_PREFER_IEPROCESS)) { TCHAR szURL[MAX_URL_STRING]; HRESULT hres = ::IEGetDisplayName(pidl, szURL, SHGDN_FORPARSING); if (SUCCEEDED(hres)) { hres = IENavigateIEProcess(szURL, FALSE); if (SUCCEEDED(hres)) { return TRUE; } } } return FALSE; } BOOL TryNewProcessIfNeeded(IETHREADPARAM * piei) { BOOL bRet = TryNewProcessIfNeeded(piei->pidl); if (bRet) { SHDestroyIETHREADPARAM(piei); } return bRet; } // NOTE: this is a ThreadProc (shdocvw creates this as a thread) // // this takes ownership of piei and will free it // BOOL SHOpenFolderWindow(IETHREADPARAM* piei) { BOOL fSuccess = FALSE; _InitAppGlobals(); CABINETSTATE cs; GetCabState(&cs); // // If "/select" switch is specified, but we haven't splitted // the pidl yet (because the path is passed rather than pidl), // split it here. // if ((piei->uFlags & COF_SELECT) && piei->pidlSelect == NULL) { LPITEMIDLIST pidlLast = ILFindLastID(piei->pidl); // Warning: pidlLast can be NULL if the command line is // sufficiently wacky. E.g., // // explorer /select // if (pidlLast) { piei->pidlSelect = ILClone(pidlLast); pidlLast->mkid.cb = 0; } } if (GetAsyncKeyState(VK_CONTROL) < 0) cs.fNewWindowMode = !cs.fNewWindowMode; // // Check to see if we can reuse the existing window first // OLECMD rgCmds[1] = {0}; rgCmds[0].cmdID = SBCMDID_EXPLORERBAR; BOOL bForceSameWindow = (piei->uFlags & COF_EXPLORE) && SUCCEEDED(IUnknown_QueryStatus(piei->psbCaller, &CGID_Explorer, ARRAYSIZE(rgCmds), rgCmds, NULL)) && (rgCmds[0].cmdf & OLECMDF_LATCHED); if (bForceSameWindow || piei->psbCaller && !(piei->uFlags & COF_CREATENEWWINDOW) && !cs.fNewWindowMode) { if (piei->pidl) { UINT uFlags = SBSP_SAMEBROWSER; if (piei->uFlags & COF_EXPLORE) uFlags |= SBSP_EXPLOREMODE; else uFlags |= SBSP_OPENMODE; if (SUCCEEDED(piei->psbCaller->BrowseObject(piei->pidl, uFlags))) goto ReusedWindow; } } // // Don't look for an existing window if we are opening an explorer. // if (!((piei->uFlags & COF_EXPLORE) || (piei->uFlags & COF_NOFINDWINDOW))) { HWND hwnd; IWebBrowserApp* pwba; HRESULT hres = WinList_FindFolderWindow(piei->pidl, NULL, &hwnd, &pwba); if (hres == S_OK) { ASSERT(pwba); // WinList_FindFolerWindow should not return S_OK if this fails SetForegroundWindow(hwnd); // IE30COMPAT - we need to refresh when we hunt and pick up these windows - zekel 31-JUL-97 // this will happen if we just do a navigate to ourself. this is the // same kind of behavior we see when we do a shellexec of an URL. // // we dont use the pwb from FindFolderWindow because it turns out that RPC will // fail the QI for it when we are being called from another process. this // occurs when IExplore.exe Sends the WM_COPYDATA to the desktop to navigate // a window to an URL that is already there. so instead of using the pwb // we do a CDDEAuto_Navigate(). which actually goes and uses pwb itself. // TCHAR szUrl[MAX_URL_STRING]; if (SUCCEEDED(IEGetNameAndFlags(piei->pidl, SHGDN_FORPARSING, szUrl, SIZECHARS(szUrl), NULL))) { BSTR bstrUrl = SysAllocString(szUrl); if (bstrUrl) { pwba->Navigate(bstrUrl, NULL, NULL, NULL, NULL); SysFreeString(bstrUrl); } } pwba->Release(); if (IsIconic(hwnd)) ShowWindow(hwnd, SW_RESTORE); if (piei->nCmdShow) ShowWindow(hwnd, piei->nCmdShow); goto ReusedWindow; } else if (hres == E_PENDING) goto ReusedWindow; // Assume it will come up sooner or later } // Okay, we're opening up a new window, let's honor // the BrowseNewProcess flag, even though we lose // other info (COF_EXPLORE, etc). // if (TryNewProcessIfNeeded(piei)) return TRUE; if (((piei->uFlags & (COF_INPROC | COF_IEXPLORE)) == (COF_INPROC | COF_IEXPLORE)) && g_tidParking == 0) { // we're starting from iexplore.exe g_tidParking = GetCurrentThreadId(); } if (piei->pidl && IsURLChild(piei->pidl, TRUE)) piei->uFlags |= COF_IEXPLORE; ASSERT(piei->punkRefProcess == NULL); SHGetInstanceExplorer(&piei->punkRefProcess); // pick up the process ref (if any) if (piei->uFlags & COF_INPROC) { BrowserProtectedThreadProc(piei); fSuccess = TRUE; } else { #ifndef NO_MARSHALLING DWORD idThread; HANDLE hThread = CreateThread(NULL, #ifdef DEBUG 0, // on debug builds we inherit the default process stack size (so we can identify excessive stack usage) #else (1024 * 56), // we pre-allocate a 56k stack for browser windows #endif BrowserProtectedThreadProc, piei, CREATE_SUSPENDED, &idThread); if (hThread) { WinList_RegisterPending(idThread, piei->pidl, NULL, &piei->dwRegister); ResumeThread(hThread); CloseHandle(hThread); fSuccess = TRUE; } else { SHDestroyIETHREADPARAM(piei); } #else IEFrameNewWindowSameThread(piei); #endif } return fSuccess; ReusedWindow: SHDestroyIETHREADPARAM(piei); return TRUE; } // // Notes: pidlNew will be freed // STDAPI SHOpenNewFrame(LPITEMIDLIST pidlNew, ITravelLog *ptl, DWORD dwBrowserIndex, UINT uFlags) { HRESULT hres; IETHREADPARAM* piei = SHCreateIETHREADPARAM(NULL, SW_SHOWNORMAL, ptl, NULL); if (piei) { hres = S_OK; if (ptl) piei->dwBrowserIndex = dwBrowserIndex; if (pidlNew) { piei->pidl = pidlNew; pidlNew = NULL; } piei->uFlags = uFlags; if (!TryNewProcessIfNeeded(piei)) { #ifndef NO_MARSHALLING ASSERT(piei->punkRefProcess == NULL); SHGetInstanceExplorer(&piei->punkRefProcess); // pick up the process ref (if any) DWORD idThread; HANDLE hThread = CreateThread(NULL, #ifdef DEBUG 0, // on debug builds we inherit the default process stack size (so we can identify excessive stack usage) #else (1024 * 56), // we pre-allocate a 56k stack for browser windows #endif BrowserProtectedThreadProc, piei, 0, &idThread); if (hThread) { // this handles removing this from the debug memory list of // the opening thread. CloseHandle(hThread); } else { SHDestroyIETHREADPARAM(piei); hres = E_FAIL; } #else IEFrameNewWindowSameThread(piei); #endif } } else hres = E_OUTOFMEMORY; ILFree(pidlNew); return hres; } HRESULT CShellBrowser2::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD rgCmds[], OLECMDTEXT *pcmdtext) { HRESULT hres = SUPERCLASS::QueryStatus(pguidCmdGroup, cCmds, rgCmds, pcmdtext); if (pguidCmdGroup == NULL) { // // If the curretly focused toolbar suppors the IOleCommandTarget // ask it the status of clipboard commands. // actually we should ask *both* ourselves (the active target) // and then the view (the same way our IOCT::Exec does...) // if (_HasToolbarFocus()) { LPTOOLBARITEM ptbi; ptbi = _GetToolbarItem(_get_itbLastFocus()); if (ptbi && ptbi->ptbar) { IOleCommandTarget* pcmd; HRESULT hresT = ptbi->ptbar->QueryInterface( IID_IOleCommandTarget, (void**)&pcmd); if (SUCCEEDED(hresT)) { for (ULONG i = 0; i < cCmds; i++) { switch (rgCmds[i].cmdID) { case OLECMDID_CUT: case OLECMDID_COPY: case OLECMDID_PASTE: pcmd->QueryStatus(pguidCmdGroup, 1, &rgCmds[i], pcmdtext); break; } } pcmd->Release(); } } } } else if (IsEqualGUID(CGID_ShellBrowser, *pguidCmdGroup)) { if (pcmdtext) { ASSERT(cCmds == 1); switch (pcmdtext->cmdtextf) { case OLECMDTEXTF_NAME: { TOOLTIPTEXTA ttt = { NULL }; CHAR *pszBuffer = ttt.szText; CHAR szTemp[MAX_TOOLTIP_STRING]; ttt.hdr.code = TTN_NEEDTEXTA; ttt.hdr.idFrom = rgCmds[0].cmdID; ttt.lpszText = ttt.szText; OnNotify((LPNMHDR)&ttt); if (ttt.hinst) { LoadStringA(ttt.hinst, (UINT) PtrToUlong(ttt.lpszText), szTemp, ARRAYSIZE(szTemp)); pszBuffer = szTemp; } else if (ttt.lpszText) pszBuffer = ttt.lpszText; pcmdtext->cwActual = SHAnsiToUnicode(pszBuffer, pcmdtext->rgwz, pcmdtext->cwBuf); pcmdtext->cwActual -= 1; hres = S_OK; break; } default: hres = E_FAIL; break; } } else { for (ULONG i = 0 ; i < cCmds ; i++) { switch(rgCmds[i].cmdID) { case FCIDM_PREVIOUSFOLDER: if (_ShouldAllowNavigateParent()) rgCmds[i].cmdf |= OLECMDF_ENABLED; else rgCmds[i].cmdf &= OLECMDF_ENABLED; hres = S_OK; break; } } } } else if (IsEqualGUID(CGID_Explorer, *pguidCmdGroup)) { // should fill pcmdtext as well for (ULONG i = 0 ; i < cCmds ; i++) { switch (rgCmds[i].cmdID) { case SBCMDID_SHOWCONTROL: case SBCMDID_DOFAVORITESMENU: case SBCMDID_ACTIVEOBJECTMENUS: case SBCMDID_SETMERGEDWEBMENU: rgCmds[i].cmdf = OLECMDF_ENABLED; // support these unconditionally break; case SBCMDID_DOMAILMENU: rgCmds[i].cmdf = SHIsRegisteredClient(NEWS_DEF_KEY) || SHIsRegisteredClient(MAIL_DEF_KEY) ? OLECMDF_ENABLED : 0; //If go menu is restricted, disable mail menu on toolbar also if (SHRestricted2(REST_GoMenu, NULL, 0)) rgCmds[i].cmdf = 0; break; case SBCMDID_SEARCHBAR: case SBCMDID_FAVORITESBAR: case SBCMDID_HISTORYBAR: case SBCMDID_EXPLORERBAR: case SBCMDID_DISCUSSIONBAND: case SBCMDID_MEDIABAR: { UINT idm; rgCmds[i].cmdf |= OLECMDF_SUPPORTED|OLECMDF_ENABLED; switch (rgCmds[i].cmdID) { case SBCMDID_DISCUSSIONBAND: { // Perf: Avoid calling _InfoCLSIDToIdm unless we have loaded // the band info already because it is very expensive! if (_pbsmInfo && FCIDM_VBBNOHORIZONTALBAR != _idmComm) { idm = _InfoCLSIDToIdm(&CLSID_DiscussionBand); if (idm == -1) { // The discussion band is not registered ClearFlag(rgCmds[i].cmdf, OLECMDF_SUPPORTED|OLECMDF_ENABLED); } else if (idm == _idmComm) { rgCmds[i].cmdf |= OLECMDF_LATCHED; } } else { // // Since the band info has not been loaded or idmComm is FCIDM_VBBNONE, // we know that the discussion band is not up and is not latched. So // we can check the registry instead and avoid defer the cost of // initializing _pbsmInfo // // See if the discussions band is registered for the CATID_CommBand idm = -1; HKEY hkey = NULL; static BOOL fDiscussionBand = -1; // We get called a lot, so only read the registry once. if (-1 == fDiscussionBand) { if (RegOpenKeyEx(HKEY_CLASSES_ROOT, c_szDiscussionBandReg, NULL, KEY_READ, &hkey) == ERROR_SUCCESS) { // We found the discussions band fDiscussionBand = 1; RegCloseKey(hkey); } else { fDiscussionBand = 0; } } if (!fDiscussionBand) { // The discussions band is not registered ClearFlag(rgCmds[i].cmdf, OLECMDF_SUPPORTED|OLECMDF_ENABLED); } } break; } case SBCMDID_SEARCHBAR: idm=FCIDM_VBBSEARCHBAND ; break; case SBCMDID_FAVORITESBAR: idm=FCIDM_VBBFAVORITESBAND; if (SHRestricted2(REST_NoFavorites, NULL, 0)) ClearFlag(rgCmds[i].cmdf, OLECMDF_ENABLED); break; case SBCMDID_HISTORYBAR: idm=FCIDM_VBBHISTORYBAND ; break; case SBCMDID_EXPLORERBAR: idm=FCIDM_VBBEXPLORERBAND ; break; case SBCMDID_MEDIABAR: idm=FCIDM_VBBMEDIABAND ; break; default: ASSERT(FALSE); return E_FAIL; } if (idm == _idmInfo) rgCmds[i].cmdf |= OLECMDF_LATCHED; break; } } } hres = S_OK; } return hres; } // REARCHITECT (980710 adp) should clean up to do consistent routing. this // ad-hoc per-nCmdID stuff is too error-prone. HRESULT CShellBrowser2::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANTARG *pvarargIn, VARIANTARG *pvarargOut) { if (pguidCmdGroup == NULL) { switch (nCmdID) { case OLECMDID_SETTITLE: // NT #282632: This bug is caused when the current IShellView is a web page and // the pending view is a shell folder w/Web View that has certain timing charataristics. // MSHTML from the Web View will fire OLECMDID_SETTITLE with the URL of the // web view template. The problem is that there is a bug in IE4 SI's shell32 // that let that message go to the browser (here), even though the view wasn't // active. Since we don't know who it came from, we forward it down to the current // view who squirls away the title. This title is then given in the Back toolbar // button drop down history. This is hack around the IE4 SI shell32 bug is to kill // that message. -BryanSt TraceMsg(DM_TRACE, "csb.e: SetTitle is called"); break; // continue. // Clipboard commands and common operations will be dispatched // to the currently focused toolbar. case OLECMDID_CUT: case OLECMDID_COPY: case OLECMDID_PASTE: case OLECMDID_DELETE: case OLECMDID_PROPERTIES: if (_HasToolbarFocus()) { LPTOOLBARITEM ptbi; if (ptbi = _GetToolbarItem(_get_itbLastFocus())) { HRESULT hres = IUnknown_Exec(ptbi->ptbar, pguidCmdGroup, nCmdID, nCmdexecopt, pvarargIn, pvarargOut); if (SUCCEEDED(hres)) return hres; } } break; // give the view a chance } } else if (IsEqualGUID(CGID_DefView, *pguidCmdGroup)) { switch (nCmdID) { case DVID_RESETDEFAULT: // 99/02/09 #226140 vtan: Exec command issued from // CFolderOptionsPsx::ResetDefFolderSettings() // when user clicks "Reset All Folders" in folder // options "View" tab. Pass this thru to DefView. ASSERTMSG(nCmdexecopt == OLECMDEXECOPT_DODEFAULT, "nCmdexecopt must be OLECMDEXECOPT_DODEFAULT"); ASSERTMSG(pvarargIn == NULL, "pvarargIn must be NULL"); ASSERTMSG(pvarargOut == NULL, "pvarargOut must be NULL"); IUnknown_Exec(_pbbd->_psv, &CGID_DefView, DVID_RESETDEFAULT, OLECMDEXECOPT_DODEFAULT, NULL, NULL); return(S_OK); break; default: break; } } else if (IsEqualGUID(CGID_Explorer, *pguidCmdGroup)) { switch (nCmdID) { case SBCMDID_MAYSAVEVIEWSTATE: return _fDontSaveViewOptions ? S_FALSE : S_OK; // May need to save out earlier... case SBCMDID_CANCELANDCLOSE: _CancelPendingNavigationAsync(); PostMessage(_pbbd->_hwnd, WM_CLOSE, 0, 0); return S_OK; case SBCMDID_CANCELNAVIGATION: // // Special code to close the window if the very first navigation caused // an asynchronous download (e.g. from athena). // if (!_pbbd->_pidlCur && pvarargIn && pvarargIn->vt == VT_I4 && pvarargIn->lVal == FALSE) { _CancelPendingNavigationAsync(); PostMessage(_pbbd->_hwnd, WM_CLOSE, 0, 0); return S_OK; } break; // fall through case SBCMDID_MIXEDZONE: _UpdateZonesPane(pvarargIn); break; case SBCMDID_ISIEMODEBROWSER: return v_IsIEModeBrowser() ? S_OK : S_FALSE; case SBCMDID_STARTEDFORINTERNET: return _fInternetStart ? S_OK : S_FALSE; case SBCMDID_ISBROWSERACTIVE: return _fActivated ? S_OK : S_FALSE; case SBCMDID_SUGGESTSAVEWINPOS: if (_ShouldSaveWindowPlacement()) { StorePlacementOfWindow(_pbbd->_hwnd); return S_OK; } return S_FALSE; case SBCMDID_ONVIEWMOVETOTOP: if (_ptheater) { return _ptheater->Exec(pguidCmdGroup, nCmdID, nCmdexecopt, pvarargIn, pvarargOut); } return S_FALSE; } } else if (IsEqualGUID(CGID_MenuBandHandler, *pguidCmdGroup)) { switch (nCmdID) { case MBHANDCID_PIDLSELECT: { LPITEMIDLIST pidl = VariantToIDList(pvarargIn); if (pidl) { if (!ILIsEmpty(pidl)) { if (_pidlMenuSelect) KillTimer(_pbbd->_hwnd, SHBTIMER_MENUSELECT); // Opening the favorites' shortcuts can be slow. So set a // timer so we don't open needlessly as the mouse runs over // the menu quickly. if (Pidl_Set(&_pidlMenuSelect, pidl)) { if (!SetTimer(_pbbd->_hwnd, SHBTIMER_MENUSELECT, MENUSELECT_TIME, NULL)) Pidl_Set(&_pidlMenuSelect, NULL); } } ILFree(pidl); } } return S_OK; } } else if (IsEqualGUID(CGID_MenuBand, *pguidCmdGroup)) { switch (nCmdID) { case MBANDCID_EXITMENU: // we're done with the menu band (favorites) // kill the timer // this is to fix bug #61917 where the status bar would get stack // in the simple mode (actually the timer would go off after we // navigated to the page with the proper status bar mode, but then // we would call _DisplayFavoriteStatus that would put it back in // the simple mode) if (_pidlMenuSelect) KillTimer(_pbbd->_hwnd, SHBTIMER_MENUSELECT); return S_OK; } } else if (IsEqualGUID(CGID_FilterObject, *pguidCmdGroup)) { HRESULT hres = E_INVALIDARG; switch (nCmdID) { case PHID_FilterOutPidl: { LPITEMIDLIST pidl = VariantToIDList(pvarargIn); if (pidl) { // We are filtering out everything except folders, shortcuts, and // internet shortcuts DWORD dwAttribs = SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_LINK; // include everthing by default VariantClearLazy(pvarargOut); pvarargOut->vt = VT_BOOL; pvarargOut->boolVal = VARIANT_FALSE; IEGetAttributesOf(pidl, &dwAttribs); // include all non file system objects, folders and links // (non file system things like the Channel folders contents) if (!(dwAttribs & (SFGAO_FOLDER | SFGAO_LINK)) && (dwAttribs & SFGAO_FILESYSTEM)) pvarargOut->boolVal = VARIANT_TRUE; // don't include hres = S_OK; ILFree(pidl); } } break; default: TraceMsg(TF_WARNING, "csb.e: Received unknown CGID_FilterObject cmdid (%d)", nCmdID); break; } return hres; } else if (IsEqualGUID(CGID_ShellDocView, *pguidCmdGroup)) { switch (nCmdID) { // we reflect AMBIENTPROPCHANGE down because this is how iedisp notifies dochost // that an ambient property has changed. we don't need to reflect this down in // cwebbrowsersb because only the top-level iwebbrowser2 is allowed to change props case SHDVID_AMBIENTPROPCHANGE: case SHDVID_PRINTFRAME: case SHDVID_MIMECSETMENUOPEN: case SHDVID_FONTMENUOPEN: if (pvarargIn) { if ((VT_I4 == pvarargIn->vt) && (DISPID_AMBIENT_OFFLINEIFNOTCONNECTED == pvarargIn->lVal)) { VARIANT_BOOL fIsOffline; if (_pbbd->_pautoWB2) { _pbbd->_pautoWB2->get_Offline(&fIsOffline); if (fIsOffline) { // this top level frame just went Offline // - so decr net session count _DecrNetSessionCount(); } else { // this top level frame went online. _IncrNetSessionCount(); } } } } break; } } HRESULT hres = SUPERCLASS::Exec(pguidCmdGroup, nCmdID, nCmdexecopt, pvarargIn, pvarargOut); if (pguidCmdGroup == NULL) { DefaultCommandGroup: switch (nCmdID) { case OLECMDID_REFRESH: // FolderOptions.Advanced refreshes all browser windows _UpdateRegFlags(); _SetTitle(NULL); // maybe "full path in title bar" changed v_ShowHideChildWindows(FALSE); // pass this to the browserbar IDeskBar* pdb; FindToolbar(INFOBAR_TBNAME, IID_PPV_ARG(IDeskBar, &pdb)); if (pdb) { IUnknown_Exec(pdb, pguidCmdGroup, nCmdID, nCmdexecopt, pvarargIn, pvarargOut); pdb->Release(); } hres = S_OK; break; } } else if (IsEqualGUID(CGID_ShellBrowser, *pguidCmdGroup)) { // toolbar buttons we put there ourselves hres = S_OK; // assume accepted switch (nCmdID) { case FCIDM_PREVIOUSFOLDER: v_ParentFolder(); break; case FCIDM_CONNECT: DoNetConnect(_pbbd->_hwnd); break; case FCIDM_DISCONNECT: DoNetDisconnect(_pbbd->_hwnd); break; case FCIDM_GETSTATUSBAR: if (pvarargOut->vt == VT_I4) pvarargOut->lVal = _fStatusBar; break; case FCIDM_SETSTATUSBAR: if (pvarargIn->vt == VT_I4) { _fStatusBar = pvarargIn->lVal; v_ShowHideChildWindows(FALSE); } break; case FCIDM_PERSISTTOOLBAR: _SaveITbarLayout(); break; default: // pass off the nCmdID to the view for processing / translation. DFVCMDDATA cd; cd.pva = pvarargIn; cd.hwnd = _pbbd->_hwnd; cd.nCmdIDTranslated = 0; SendMessage(_pbbd->_hwndView, WM_COMMAND, nCmdID, (LONG_PTR)&cd); if (cd.nCmdIDTranslated) { // We sent the private nCmdID to the view. The view did not // process it (probably because it didn't have the focus), // but instead translated it into a standard OLECMDID for // further processing by the toolbar with the focus. pguidCmdGroup = NULL; nCmdID = cd.nCmdIDTranslated; hres = OLECMDERR_E_NOTSUPPORTED; goto DefaultCommandGroup; } break; } } else if (IsEqualGUID(IID_IExplorerToolbar, *pguidCmdGroup)) { // these are commands to intercept if (_HasToolbarFocus() && _get_itbLastFocus() != ITB_ITBAR) { int idCmd = -1; // certain shell commands we should pick off switch (nCmdID) { case OLECMDID_DELETE: case SFVIDM_FILE_DELETE: idCmd = FCIDM_DELETE; break; case OLECMDID_PROPERTIES: case SFVIDM_FILE_PROPERTIES: idCmd = FCIDM_PROPERTIES; break; case OLECMDID_CUT: case SFVIDM_EDIT_CUT: idCmd = FCIDM_MOVE; break; case OLECMDID_COPY: case SFVIDM_EDIT_COPY: idCmd = FCIDM_COPY; break; case OLECMDID_PASTE: case SFVIDM_EDIT_PASTE: idCmd = FCIDM_PASTE; break; } if (idCmd != -1) { OnCommand(GET_WM_COMMAND_MPS(idCmd, 0, NULL)); return S_OK; } } } else if (IsEqualGUID(CGID_PrivCITCommands, *pguidCmdGroup)) { return IUnknown_Exec(_GetITBar(), pguidCmdGroup, nCmdID, nCmdexecopt, pvarargIn, pvarargOut); } else if (IsEqualGUID(CGID_Explorer, *pguidCmdGroup)) { hres = S_OK; // assume we will get it switch(nCmdID) { case SBCMDID_SETMERGEDWEBMENU: if (!_hmenuPreMerged) _hmenuPreMerged = _MenuTemplate(MENU_PREMERGED, FALSE); if (SHRestricted2W(REST_NoHelpMenu, NULL, 0)) { DeleteMenu(_hmenuPreMerged, FCIDM_MENU_HELP, MF_BYCOMMAND); } SetMenuSB(_hmenuPreMerged, NULL, NULL); if (pvarargOut) { pvarargOut->vt = VT_INT_PTR; pvarargOut->byref = _hmenuPreMerged; } break; case SBCMDID_ACTIVEOBJECTMENUS: _fDispatchMenuMsgs = TRUE; break; case SBCMDID_SENDPAGE: case SBCMDID_SENDSHORTCUT: _SendCurrentPage(nCmdID == SBCMDID_SENDPAGE ? FORCE_COPY : FORCE_LINK); break; case SBCMDID_SEARCHBAR: case SBCMDID_FAVORITESBAR: case SBCMDID_HISTORYBAR: case SBCMDID_EXPLORERBAR: case SBCMDID_DISCUSSIONBAND: case SBCMDID_MEDIABAR: { UINT idm; switch (nCmdID) { case SBCMDID_SEARCHBAR: idm = FCIDM_VBBSEARCHBAND ; break; case SBCMDID_FAVORITESBAR: idm = FCIDM_VBBFAVORITESBAND ; break; case SBCMDID_HISTORYBAR: idm = FCIDM_VBBHISTORYBAND ; break; case SBCMDID_EXPLORERBAR: idm = FCIDM_VBBEXPLORERBAND ; break; case SBCMDID_MEDIABAR: idm = FCIDM_VBBMEDIABAND ; break; // The discussion band maps to one of the dynamic bands case SBCMDID_DISCUSSIONBAND: idm = _InfoCLSIDToIdm(&CLSID_DiscussionBand) ; break; default: idm = -1; break; } if (idm != -1) { // default is toggle (-1) int i = (pvarargIn && EVAL(pvarargIn->vt == VT_I4)) ? pvarargIn->lVal : -1; LPITEMIDLIST pidl = VariantToIDList(pvarargOut); // accepts null variant input _SetBrowserBarState(idm, NULL, i, pidl); ILFree(pidl); // accepts NULL } hres = S_OK; break; } case SBCMDID_SHOWCONTROL: { DWORD dwRet; int iControl, iCmd; if (nCmdexecopt == OLECMDEXECOPT_DODEFAULT && pvarargIn && pvarargIn->vt == VT_I4) { iControl = (int)(short)LOWORD(pvarargIn->lVal); iCmd = (int)(short)HIWORD(pvarargIn->lVal); } else { iControl = (int)(short)LOWORD(nCmdexecopt); iCmd = (HIWORD(nCmdexecopt) ? SBSC_SHOW : SBSC_HIDE); } dwRet = v_ShowControl(iControl, iCmd); if (dwRet == (DWORD)-1) break; if (pvarargOut) { pvarargOut->vt = VT_I4; pvarargOut->lVal = dwRet; } break; } case SBCMDID_DOFAVORITESMENU: case SBCMDID_DOMAILMENU: { HMENU hmenu = NULL; if (nCmdID == SBCMDID_DOFAVORITESMENU) { HMENU hmenuWnd = NULL; IShellMenu* psm; if (SUCCEEDED(_pmb->QueryInterface(IID_PPV_ARG(IShellMenu, &psm)))) { psm->GetMenu(&hmenuWnd, NULL, NULL); psm->Release(); } if (hmenuWnd) { hmenu = SHGetMenuFromID(hmenuWnd, FCIDM_MENU_FAVORITES); } } else hmenu = LoadMenuPopup(MENU_MAILNEWS); if (hmenu) { if (pvarargIn && pvarargIn->vt == VT_I4) { TrackPopupMenu(hmenu, 0, GET_X_LPARAM(pvarargIn->lVal), GET_Y_LPARAM(pvarargIn->lVal), 0, _GetCaptionWindow(), NULL); } if (nCmdID == SBCMDID_DOMAILMENU) DestroyMenu(hmenu); } } break; case SBCMDID_SELECTHISTPIDL: { // remember most recent hist pidl. if we have history band visible, tell it // the hist pidl. if the band is not visible, it is it's responsibility to // query the most recent hist pidl via SBCMDID_GETHISTPIDL // the semantics of the call from UrlStorage is that if we respond S_OK to // to this command, we take ownership of pidl and must ILFree it. // when we call the band, on the other hand, they must ILClone it if they want // to use it outside of the Exec call. if (_pidlLastHist) { ILFree(_pidlLastHist); _pidlLastHist = NULL; } _pidlLastHist = VariantToIDList(pvarargIn); // take ownership if (_poctNsc) { _poctNsc->Exec(pguidCmdGroup, nCmdID, nCmdexecopt, pvarargIn, pvarargOut); } } break; case SBCMDID_GETHISTPIDL: if (pvarargOut) { VariantClearLazy(pvarargOut); if (_pidlLastHist) { InitVariantFromIDList(pvarargOut, _pidlLastHist); } } break; case SBCMDID_UNREGISTERNSCBAND: if (pvarargIn && pvarargIn->vt == VT_UNKNOWN && pvarargIn->punkVal) { if (_poctNsc && SHIsSameObject(_poctNsc, pvarargIn->punkVal)) { ATOMICRELEASE(_poctNsc); IUnknown_SetSite(_pcmNsc, NULL); ATOMICRELEASE(_pcmNsc); } } break; case SBCMDID_REGISTERNSCBAND: ATOMICRELEASE(_poctNsc); IUnknown_SetSite(_pcmNsc, NULL); ATOMICRELEASE(_pcmNsc); if (pvarargIn && pvarargIn->vt == VT_UNKNOWN && pvarargIn->punkVal) { pvarargIn->punkVal->QueryInterface(IID_PPV_ARG(IOleCommandTarget, &_poctNsc)); } break; case SBCMDID_TOOLBAREMPTY: if (pvarargIn && VT_UNKNOWN == pvarargIn->vt && pvarargIn->punkVal) { if (_IsSameToolbar(INFOBAR_TBNAME, pvarargIn->punkVal)) _SetBrowserBarState(_idmInfo, NULL, 0); else if (_IsSameToolbar(COMMBAR_TBNAME, pvarargIn->punkVal)) _SetBrowserBarState(_idmComm, NULL, 0); else _HideToolbar(pvarargIn->punkVal); } break; case SBCMDID_GETTEMPLATEMENU: if (pvarargOut) { pvarargOut->vt = VT_INT_PTR; pvarargOut->byref = (LPVOID)_hmenuTemplate; } break; case SBCMDID_GETCURRENTMENU: if (pvarargOut) { pvarargOut->vt = VT_INT_PTR; pvarargOut->byref = (LPVOID)_hmenuCur; } break; default: // // Note that we should return hres from the super class as-is. // // hres = OLECMDERR_E_NOTSUPPORTED; break; } } else if (IsEqualGUID(CGID_ShellDocView, *pguidCmdGroup)) { switch(nCmdID) { case SHDVID_GETSYSIMAGEINDEX: pvarargOut->vt = VT_I4; pvarargOut->lVal = _GetIconIndex(); hres = (pvarargOut->lVal==-1) ? E_FAIL : S_OK; break; case SHDVID_HELP: if(!SHIsRestricted2W(_pbbd->_hwnd, REST_NoHelpMenu, NULL, 0)) { SHHtmlHelpOnDemandWrap(_pbbd->_hwnd, TEXT("iexplore.chm > iedefault"), HH_DISPLAY_TOPIC, 0, ML_CROSSCODEPAGE); hres = S_OK; } break; case SHDVID_GETBROWSERBAR: { const CLSID *pclsid = _InfoIdmToCLSID(_idmInfo); // kinda strange to (ab-)use checked menu items as // state marker to persist the CLSID between Exec calls (applies also to SHDVID_NAVIGATEBBTOURL below)!! // but that's how both SHDVID_GETBROWSERBAR and SHDVID_NAVIGATEBBTOURL are called // // assume that the currently checked menu points to the explorer bar // this navigate to URL is aimed to. // Currently Trident's NavigateInBand is the only caller // using this command; it calls SHDVID_GETBROWSERBAR first and thus set the _idmInfo IBandSite *pbs; hres = E_FAIL; VariantInit(pvarargOut); _GetBrowserBar(IDBAR_VERTICAL, TRUE, &pbs, pclsid); if (pbs) { IDeskBand *pband = _GetInfoBandBS(pbs, *pclsid); if (pband) { pvarargOut->vt = VT_UNKNOWN; pvarargOut->punkVal = pband; hres = S_OK; } pbs->Release(); } break; } case SHDVID_SHOWBROWSERBAR: { CLSID *pclsid; CLSID guid; if (pvarargIn->vt == VT_BSTR) { if (SUCCEEDED(IUnknown_Exec(_GetITBar(), &CGID_PrivCITCommands, CITIDM_VIEWEXTERNALBAND_BYCLASSID, nCmdexecopt, pvarargIn, NULL))) { hres = S_OK; break; } // external (can marshal) if (!GUIDFromString(pvarargIn->bstrVal, &guid)) return S_OK; // Invalid CLSID; IE5 returned S_OK so I guess it's ok pclsid = &guid; } else if (pvarargIn->vt == VT_INT_PTR) { // internal (can't marshal) ASSERT(0); // dead code? let's make sure... TraceMsg(TF_WARNING, "csb.e: SHDVID_SHOWBROWSERBAR clsid !marshall (!)"); pclsid = (CLSID *) (pvarargIn->byref); } else { ASSERT(0); pclsid = NULL; break; } // enforce mediabar restriction: even though menu and toolbar have MediaBar disabled, resp. removed // user can still launch thru targeting _media or when mediabar was last open explorer bar before restriction is set if ( IsEqualIID(*pclsid, CLSID_MediaBand) && SHRestricted2(REST_No_LaunchMediaBar, NULL, 0) ) { hres = E_ACCESSDENIED; pclsid = NULL; break; } _SetBrowserBarState(-1, pclsid, nCmdexecopt ? 1 : 0); hres = S_OK; break; } case SHDVID_ISBROWSERBARVISIBLE: // Quickly return false if both bars are hidden hres = S_FALSE; if (_idmComm != FCIDM_VBBNOHORIZONTALBAR || _idmInfo != FCIDM_VBBNOVERTICALBAR) { if (pvarargIn->vt == VT_BSTR) { // Get the associated id CLSID clsid; if (GUIDFromString(pvarargIn->bstrVal, &clsid)) { UINT idm = _InfoCLSIDToIdm(&clsid); if (_idmComm == idm || _idmInfo == idm) { // It's visible! hres = S_OK; } } } } return hres; case SHDVID_ISEXPLORERBARVISIBLE: hres = (_idmInfo != FCIDM_VBBNOVERTICALBAR) ? S_OK : S_FALSE; return hres; case SHDVID_NAVIGATEBB: { LPITEMIDLIST pidl = VariantToIDList(pvarargIn); if (pidl) { if (!ILIsEmpty(pidl)) { IBandSite * pbs; const CLSID * pclsid = _InfoIdmToCLSID(_idmInfo); _GetBrowserBar(IDBAR_VERTICAL, TRUE, &pbs, pclsid); if (pbs) { IDeskBand *pband = _GetInfoBandBS(pbs, *pclsid); if (pband) { IBandNavigate *pbn; pband->QueryInterface(IID_PPV_ARG(IBandNavigate, &pbn)); if (pbn) { pbn->Select(pidl); pbn->Release(); } pband->Release(); } pbs->Release(); } hres = S_OK; } ILFree(pidl); } break; } case SHDVID_NAVIGATEBBTOURL: { const CLSID *pclsid = _InfoIdmToCLSID(_idmInfo); if ( IsEqualIID(*pclsid, CLSID_MediaBand) && SHRegGetBoolUSValue(REG_MEDIA_STR, TEXT("SuppressOnlineContent"), FALSE, FALSE)) { hres = E_FAIL; break; } LPITEMIDLIST pidl; hres = IEParseDisplayNameWithBCW(CP_ACP, V_BSTR(pvarargIn), NULL, &pidl); if (!hres && pidl && !ILIsEmpty(pidl)) { // see comments in SHDVID_GETBROWSERBAR above! // // assume that the currently checked menu points to the explorer bar // this navigate to URL is aimed to. // Currently Trident's NavigateInBand is the only caller // using this command; it calls SHDVID_GETBROWSERBAR first and thus set the _idmInfo IBandSite *pbs; _GetBrowserBar(IDBAR_VERTICAL, TRUE, &pbs, pclsid); if (pbs) { IDeskBand *pband = _GetInfoBandBS(pbs, *pclsid); if (pband) { // // See if we can use ISearchBandTBHelper which has a "truer" navigate // method. // ISearchBandTBHelper * pSearchBandTBHelper = NULL; pband->QueryInterface(IID_ISearchBandTBHelper, (void**)&pSearchBandTBHelper); if (pSearchBandTBHelper) { pSearchBandTBHelper->NavigateToPidl(pidl); pSearchBandTBHelper->Release(); } else { // // Probably a different band. See if it implements // IBandNavigate // IBandNavigate * pbn = NULL; pband->QueryInterface(IID_PPV_ARG(IBandNavigate, &pbn)); if (pbn) { pbn->Select(pidl); pbn->Release(); } pband->Release(); } } pbs->Release(); } ILFree(pidl); } break; } case SHDVID_CLSIDTOIDM: ASSERT(pvarargIn && pvarargIn->vt == VT_BSTR && pvarargOut); CLSID clsid; GUIDFromString(pvarargIn->bstrVal, &clsid); pvarargOut->vt = VT_I4; pvarargOut->lVal = _InfoCLSIDToIdm(&clsid); hres = S_OK; break; } } else if (IsEqualGUID(CGID_Theater, *pguidCmdGroup)) { if (_ptheater) hres = _ptheater->Exec(pguidCmdGroup, nCmdID, nCmdexecopt, pvarargIn, pvarargOut); } else if (IsEqualGUID(CGID_ExplorerBarDoc, *pguidCmdGroup)) { // These are commands that should be applied to all the explorer bar bands. for example // to reflect font size changes to the search band. they should be applied to the // contained doc object, changing guid to CGID_MSTHML _ExecAllBands(pguidCmdGroup, nCmdID, nCmdexecopt, pvarargIn, pvarargOut); } else if (IsEqualGUID(CGID_DocHostCmdPriv, *pguidCmdGroup)) { switch(nCmdID) { // This command is sent by Trident when // navigating in a shell view. // case DOCHOST_DOCHYPERLINK: // Sent by Trident when in a shell view. hres = E_FAIL; if (VT_BSTR == V_VT(pvarargIn)) { LPITEMIDLIST pidl = NULL; hres = IEParseDisplayNameWithBCW(CP_ACP, V_BSTR(pvarargIn), NULL, &pidl); if (pidl) { hres = BrowseObject(pidl, SBSP_SAMEBROWSER); ILFree(pidl); } } break; default: break; } } return hres; } //*** _IsSameToolbar -- does punkBar have specified name? // ENTRY/EXIT // fRet TRUE if matches, o.w. FALSE // BOOL CShellBrowser2::_IsSameToolbar(LPWSTR wszBarName, IUnknown *punkBar) { BOOL fRet = FALSE; IUnknown *punk; HRESULT hres = FindToolbar(wszBarName, IID_PPV_ARG(IUnknown, &punk)); ASSERT((hres == S_OK) == (punk != NULL)); if (punk) { if (SHIsSameObject(punkBar, punk)) { fRet = TRUE; } punk->Release(); } return fRet; } STDAPI SHGetWindowTitle(LPCITEMIDLIST pidl, LPTSTR pszFullName, DWORD cchSize) { CABINETSTATE cs; GetCabState(&cs); return SHTitleFromPidl(pidl, pszFullName, cchSize, cs.fFullPathTitle); } // pwszName - The Name of the URL, not // limited in size, but the result will // be truncated if the imput is too long. // // The title will be generated by taking the // title of the HTML page (pszName) and appending // the name of the browser to the end in the // following format: // "HTML_TITLE - BROWSER_NAME", like: // "My Web Page - Microsoft Internet Explorer" void CShellBrowser2::_SetTitle(LPCWSTR pwszName) { TCHAR szTitle[MAX_BROWSER_WINDOW_TITLE]; TCHAR szFullName[MAX_PATH]; BOOL fNotDisplayable = FALSE; if (!pwszName && _fTitleSet) { // if the content has once set our title, // don't revert to our own mocked up name return; } else if (pwszName) { _fTitleSet = TRUE; } BOOL fDisplayable = SHIsDisplayable(pwszName, g_fRunOnFE, g_bRunOnNT5); if (pwszName && fDisplayable) { StringCchCopy(szFullName, ARRAYSIZE(szFullName), pwszName); // truncation ok SHCleanupUrlForDisplay(szFullName); } else if (_pbbd->_pidlCur) { SHGetWindowTitle(_pbbd->_pidlCur, szFullName, ARRAYSIZE(szFullName)); } else if (_pbbd->_pidlPending) { SHGetWindowTitle(_pbbd->_pidlPending, szFullName, ARRAYSIZE(szFullName)); } else szFullName[0] = 0; // Before adding on the app title truncate the szFullName so that if it is // really long then when the app title " - Microsoft Internet Explorer" is // appended it fits. // // Used to be 100, but that wasn't quite enough to display default title. // ASSERT(96 <= ARRAYSIZE(szFullName)); SHTruncateString(szFullName, 96); // any more than 60 is useless anyways if (szFullName[0]) { TCHAR szBuf[MAX_URL_STRING]; v_GetAppTitleTemplate(szBuf, ARRAYSIZE(szBuf), szFullName); // truncation ok since this is for display only StringCchPrintf(szTitle, ARRAYSIZE(szTitle), szBuf, szFullName); } else if (_fInternetStart) { _GetAppTitle(szTitle, ARRAYSIZE(szTitle)); } else szTitle[0] = 0; SendMessage(_pbbd->_hwnd, WM_SETTEXT, 0, (LPARAM)szTitle); } void _SetWindowIcon (HWND hwnd, HICON hIcon, BOOL bLarge) { HICON hOldIcon; // // If the shell window is RTL mirrored, then flip the icon now, // before inserting them into the system cache, so that they end up // normal (not mirrrored) on the shell. This is mainly a concern for // 3rd party components. [samera] // if (IS_PROCESS_RTL_MIRRORED()) { SHMirrorIcon(&hIcon, NULL); } hOldIcon = (HICON)SendMessage(hwnd, WM_SETICON, bLarge, (LPARAM)hIcon); if (hOldIcon && (hOldIcon != hIcon)) { DestroyIcon(hOldIcon); } } void _WindowIconFromImagelist(HWND hwndMain, int nIndex, BOOL bLarge) { HIMAGELIST himlSysLarge = NULL; HIMAGELIST himlSysSmall = NULL; Shell_GetImageLists(&himlSysLarge, &himlSysSmall); // if we're using the def open icon or if extracting fails, // use the icon we've already created. HICON hIcon = ImageList_ExtractIcon(g_hinst, bLarge ? himlSysLarge : himlSysSmall, nIndex); if (hIcon) _SetWindowIcon(hwndMain, hIcon, bLarge); } int CShellBrowser2::_GetIconIndex(void) { int iSelectedImage = -1; if (_pbbd->_pidlCur) { if (_pbbd->_pctView) // we must check! { VARIANT var = {0}; HRESULT hresT = _pbbd->_pctView->Exec(&CGID_ShellDocView, SHDVID_GETSYSIMAGEINDEX, 0, NULL, &var); if (SUCCEEDED(hresT)) { if (var.vt==VT_I4) { iSelectedImage= var.lVal; } else { ASSERT(0); VariantClearLazy(&var); } } } if (iSelectedImage==-1) { // // Put Optimization here. // IShellFolder *psfParent; LPCITEMIDLIST pidlChild; if (SUCCEEDED(IEBindToParentFolder(_pbbd->_pidlCur, &psfParent, &pidlChild))) { // set the small one first to prevent user stretch blt on the large one SHMapPIDLToSystemImageListIndex(psfParent, pidlChild, &iSelectedImage); psfParent->Release(); } } } return iSelectedImage; } bool CShellBrowser2::_IsExplorerBandVisible (void) // 99/02/10 #254171 vtan: This function determines whether // the explorer band is visible. This class should not really // care but it needs to know to change the window's icon. // This is a hack and should be moved or re-architected. // 99/02/12 #292249 vtan: Re-worked algorithm to use // IBandSite::QueryBand and IPersistStream::GetClassID to // recognize the explorer band. Note that the old routine // used IDeskBand's inclusion of IOleWindow to get the HWND // and use the Win32 API IsWindowVisible(). // 99/06/25 #359477 vtan: Put this code back. // IsControlWindowShown uses QueryStatus for the explorer // band which doesn't work when v_SetIcon is called. The // band is NOT considered latched and therefore not visible. { IDeskBar *pIDeskBar; bool bVisible = false; HRESULT hResult = FindToolbar(INFOBAR_TBNAME, IID_PPV_ARG(IDeskBar, &pIDeskBar)); if (SUCCEEDED(hResult) && (pIDeskBar != NULL)) { UINT uiToolBar; uiToolBar = _FindTBar(pIDeskBar); if (uiToolBar != static_cast(-1)) { LPTOOLBARITEM pToolBarItem; pToolBarItem = _GetToolbarItem(uiToolBar); if ((pToolBarItem != NULL) && pToolBarItem->fShow) // check this state { IUnknown *pIUnknown; hResult = pIDeskBar->GetClient(reinterpret_cast(&pIUnknown)); if (SUCCEEDED(hResult) && (pIUnknown != NULL)) { IBandSite *pIBandSite; hResult = pIUnknown->QueryInterface(IID_IBandSite, reinterpret_cast(&pIBandSite)); if (SUCCEEDED(hResult) && (pIBandSite != NULL)) { UINT uiBandIndex; DWORD dwBandID; uiBandIndex = 0; hResult = pIBandSite->EnumBands(uiBandIndex, &dwBandID); while (SUCCEEDED(hResult)) { DWORD dwState; IDeskBand *pIDeskBand; dwState = 0; hResult = pIBandSite->QueryBand(dwBandID, &pIDeskBand, &dwState, NULL, 0); if (SUCCEEDED(hResult)) { CLSID clsid; hResult = IUnknown_GetClassID(pIDeskBand, &clsid); if (SUCCEEDED(hResult) && IsEqualGUID(clsid, CLSID_ExplorerBand)) bVisible = ((dwState & BSSF_VISIBLE) != 0); // and this state pIDeskBand->Release(); hResult = pIBandSite->EnumBands(++uiBandIndex, &dwBandID); } } pIBandSite->Release(); } pIUnknown->Release(); } } } pIDeskBar->Release(); } return(bVisible); } void CShellBrowser2::v_SetIcon() { if (_IsExplorerBandVisible()) { #define IDI_STFLDRPROP 46 // Explorer tree view pane is visible - use the magnifying glass icon HICON hIcon = reinterpret_cast(LoadImage(HinstShell32(), MAKEINTRESOURCE(IDI_STFLDRPROP), IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 0)); _SetWindowIcon(_pbbd->_hwnd, hIcon, ICON_SMALL); hIcon = reinterpret_cast(LoadImage(HinstShell32(), MAKEINTRESOURCE(IDI_STFLDRPROP), IMAGE_ICON, GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CXICON), 0)); _SetWindowIcon(_pbbd->_hwnd, hIcon, ICON_BIG); } else { // Otherwise use whatever icon it really should be int iSelectedImage = _GetIconIndex(); if (iSelectedImage != -1) { _WindowIconFromImagelist(_pbbd->_hwnd, iSelectedImage, ICON_SMALL); _WindowIconFromImagelist(_pbbd->_hwnd, iSelectedImage, ICON_BIG); } } } HRESULT CShellBrowser2::SetTitle(IShellView * psv, LPCWSTR lpszName) { // If the pending view had it's title set immediately and waits // in pending state for a while. And if the current view has script updating // the title. Then the current title will be displayed after the navigate // is complete. I added psv to fix this problem to CBaseBrowser2, but I // didn't fix it here. [mikesh] // // Don't set title if view is still pending (or you'll show unrated titles) // Figure out which object is changing. if (SHIsSameObject(_pbbd->_psv, psv)) { _SetTitle(lpszName); } SUPERCLASS::SetTitle(psv, lpszName); return S_OK; } HRESULT CShellBrowser2::UpdateWindowList(void) { if (_psw) { WinList_NotifyNewLocation(_psw, _dwRegisterWinList, _pbbd->_pidlCur); } return S_OK; } HRESULT CShellBrowser2::SetFlags(DWORD dwFlags, DWORD dwFlagMask) { if (dwFlagMask & BSF_THEATERMODE) _TheaterMode(dwFlags & BSF_THEATERMODE, TRUE); if (dwFlagMask & BSF_RESIZABLE) SHSetWindowBits(_pbbd->_hwnd, GWL_STYLE, WS_SIZEBOX, (dwFlags & BSF_RESIZABLE) ? WS_SIZEBOX : 0); if (dwFlagMask & BSF_CANMAXIMIZE) SHSetWindowBits(_pbbd->_hwnd, GWL_STYLE, WS_MAXIMIZEBOX, (dwFlags & BSF_CANMAXIMIZE) ? WS_MAXIMIZEBOX : 0); if ((dwFlagMask & BSF_UISETBYAUTOMATION) && (dwFlags & BSF_UISETBYAUTOMATION)) { _fDontSaveViewOptions = TRUE; _fUISetByAutomation = TRUE; // to hide any visible browser bar //REARCHITECT this will be removed when explorer bars become 1st class toolbars _SetBrowserBarState(_idmInfo, NULL, 0); _SetBrowserBarState(_idmComm, NULL, 0); } return SUPERCLASS::SetFlags(dwFlags, dwFlagMask); } HRESULT CShellBrowser2::GetFlags(DWORD *pdwFlags) { DWORD dwFlags; SUPERCLASS::GetFlags(&dwFlags); if (_fUISetByAutomation) dwFlags |= BSF_UISETBYAUTOMATION; if (_fNoLocalFileWarning) dwFlags |= BSF_NOLOCALFILEWARNING; if (_ptheater) dwFlags |= BSF_THEATERMODE; *pdwFlags = dwFlags; return S_OK; } DWORD CShellBrowser2::v_ShowControl(UINT iControl, int iCmd) { int iShowing = -1; int nWhichBand; switch (iControl) { case FCW_STATUS: iShowing = (_fStatusBar ? SBSC_SHOW : SBSC_HIDE); if (iCmd != SBSC_QUERY && (iShowing != iCmd)) { _fStatusBar = !_fStatusBar; // let itbar know that a change has occurred IUnknown_Exec(_GetITBar(), &CGID_PrivCITCommands, CITIDM_STATUSCHANGED, 0, NULL, NULL); v_ShowHideChildWindows(FALSE); } break; case FCW_INTERNETBAR: { LPTOOLBARITEM ptbi = _GetToolbarItem(ITB_ITBAR); iShowing = (ptbi->fShow ? SBSC_SHOW : SBSC_HIDE); if (iCmd != SBSC_QUERY && (iShowing != iCmd)) { ptbi->fShow = !ptbi->fShow; v_ShowHideChildWindows(FALSE); } } break; case FCW_ADDRESSBAR: case FCW_TOOLBAND: case FCW_LINKSBAR: case FCW_MENUBAR: switch(iControl) { case FCW_ADDRESSBAR: nWhichBand = CITIDM_SHOWADDRESS; break; case FCW_TOOLBAND: nWhichBand = CITIDM_SHOWTOOLS; break; case FCW_LINKSBAR: nWhichBand = CITIDM_SHOWLINKS; break; case FCW_MENUBAR: nWhichBand = CITIDM_SHOWMENU; break; } if (iCmd != SBSC_QUERY) { IUnknown_Exec(_GetITBar(), &CGID_PrivCITCommands, nWhichBand, (iCmd == SBSC_SHOW), NULL, NULL); } break; default: break; } return iShowing; } HRESULT CShellBrowser2::ShowControlWindow(UINT id, BOOL fShow) { switch (id) { case (UINT)-1: // Set into Kiosk mode... if (BOOLIFY(_fKioskMode) != fShow) { _fKioskMode = fShow; if (_fKioskMode) { _wndpl.length = sizeof(WINDOWPLACEMENT); GetWindowPlacement(_pbbd->_hwnd, &_wndpl); SHSetWindowBits(_pbbd->_hwnd, GWL_STYLE, WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|WS_MAXIMIZEBOX, 0); SHSetWindowBits(_pbbd->_hwnd, GWL_EXSTYLE, WS_EX_WINDOWEDGE, 0); _SetMenu(NULL); LPTOOLBARITEM ptbi = _GetToolbarItem(ITB_ITBAR); if (ptbi) { ptbi->fShow = FALSE; } HMONITOR hmon = MonitorFromRect(&_wndpl.rcNormalPosition, MONITOR_DEFAULTTONEAREST); RECT rcMonitor; GetMonitorRect(hmon, &rcMonitor); SetWindowPos(_pbbd->_hwnd, NULL, rcMonitor.top, rcMonitor.left, RECTWIDTH(rcMonitor), RECTHEIGHT(rcMonitor), SWP_NOZORDER); } else { if (_fShowMenu) _SetMenu(_hmenuCur); else _SetMenu(NULL); SHSetWindowBits(_pbbd->_hwnd, GWL_STYLE, WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|WS_MAXIMIZEBOX, WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|WS_MAXIMIZEBOX); SHSetWindowBits(_pbbd->_hwnd, GWL_EXSTYLE, WS_EX_WINDOWEDGE, WS_EX_WINDOWEDGE); SetWindowPlacement(_pbbd->_hwnd, &_wndpl); } // Let window manager know to recalculate things... v_ShowHideChildWindows(FALSE); SetWindowPos(_pbbd->_hwnd, NULL, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE|SWP_FRAMECHANGED); } break; case FCW_INTERNETBAR: case FCW_STATUS: case FCW_ADDRESSBAR: v_ShowControl(id, fShow ? SBSC_SHOW : SBSC_HIDE); break; case FCW_MENUBAR: if (BOOLIFY(_fShowMenu) != BOOLIFY(fShow)) { _fShowMenu = BOOLIFY(fShow); if (_fShowMenu) { _SetMenu(_hmenuCur); } else { _SetMenu(NULL); } // Let window manager know to recalculate things... v_ShowControl(id, fShow ? SBSC_SHOW : SBSC_HIDE); // Let ITBar know whether to allow selection of menu bar or no IUnknown_Exec(_GetITBar(), &CGID_PrivCITCommands, CITIDM_DISABLESHOWMENU, !_fShowMenu, NULL, NULL); SetWindowPos(_pbbd->_hwnd, NULL, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE|SWP_FRAMECHANGED); } break; default: return E_INVALIDARG; // Not one of the ones we support... } return S_OK; } BOOL CShellBrowser2::_ShouldAllowNavigateParent() { LPCITEMIDLIST pidl = ILIsRooted(_pbbd->_pidlCur) ? ILGetNext(_pbbd->_pidlCur) : _pbbd->_pidlCur; return !ILIsEmpty(pidl); } HRESULT CShellBrowser2::IsControlWindowShown(UINT id, BOOL *pfShown) { switch (id) { case (UINT)-1: // Set into Kiosk mode... *pfShown = _fKioskMode; break; case FCW_INTERNETBAR: *pfShown = _GetToolbarItem(ITB_ITBAR)->fShow; break; case FCW_STATUS: *pfShown = _fStatusBar; break; case FCW_MENUBAR: *pfShown = _fShowMenu; break; case FCW_TREE: { BOOL fShown; OLECMD rgCmds[1] = {0}; rgCmds[0].cmdID = SBCMDID_EXPLORERBAR; QueryStatus(&CGID_Explorer, ARRAYSIZE(rgCmds), rgCmds, NULL); fShown = (rgCmds[0].cmdf & OLECMDF_LATCHED); if (pfShown != NULL) *pfShown = fShown; break; } case FCW_ADDRESSBAR: { OLECMD rgcmd[] = { { CITIDM_VIEWTOOLS, 0 }, { CITIDM_VIEWADDRESS, 0 } }; if (_GetToolbarItem(ITB_ITBAR)->fShow) IUnknown_QueryStatus(_GetITBar(), &CGID_PrivCITCommands, ARRAYSIZE(rgcmd), rgcmd, NULL); *pfShown = rgcmd[1].cmdf & OLECMDF_ENABLED ? TRUE : FALSE; break; } default: return E_INVALIDARG; // Not one of the ones we support... } return S_OK; } HRESULT CShellBrowser2::SetReferrer(LPITEMIDLIST pidl) { // // this is only used when we create a new window, and // we need some sort of ZoneCrossing context. // Pidl_Set(&_pidlReferrer, pidl); return (_pidlReferrer || !pidl) ? S_OK :E_FAIL; } HRESULT CShellBrowser2::_CheckZoneCrossing(LPCITEMIDLIST pidl) { HRESULT hr = S_OK; // // NOTE - right now we only handle having one or the other - zekel 8-AUG-97 // we should only have pidlReferrer if we have been freshly // created. if we decide to use it on frames that already exist, // then we need to decide whether we should show pidlCur or pidlReferrer. // by default we give Referrer preference. // AssertMsg((!_pidlReferrer && !_pbbd->_pidlCur) || (_pidlReferrer && !_pbbd->_pidlCur) || (!_pidlReferrer && _pbbd->_pidlCur), TEXT("REVIEW: should this be allowed?? -zekel")); LPITEMIDLIST pidlRef = _pidlReferrer ? _pidlReferrer : _pbbd->_pidlCur; // // Call InternetConfirmZoneCrossingA API only if this is the top-level // browser (not a browser control) AND there is a current page. // if (pidlRef) { HRESULT hresT = S_OK; // Get the URL of the current page. WCHAR szURLPrev[MAX_URL_STRING]; const WCHAR c_szURLFile[] = L"file:///c:\\"; // dummy one LPCWSTR pszURLPrev = c_szURLFile; // assume file: // We should get the display name first and then only use // the default value if the szURLPrev doesn't have a scheme. // Also do this for szURLNew below. This will fix Folder Shortcuts // especially to Web Folders. We also need to use the pidlTarget // Folder Shortcut pidl. if (IsURLChild(pidlRef, FALSE)) { hresT = ::IEGetDisplayName(pidlRef, szURLPrev, SHGDN_FORPARSING); pszURLPrev = szURLPrev; } if (SUCCEEDED(hresT)) { // Get the URL of the new page. WCHAR szURLNew[MAX_URL_STRING]; LPCWSTR pszURLNew = c_szURLFile; if (IsURLChild(pidl, FALSE)) { hresT = ::IEGetDisplayName(pidl, szURLNew, SHGDN_FORPARSING); pszURLNew = szURLNew; } if (pszURLPrev != pszURLNew && SUCCEEDED(hresT)) { // HACK: This API takes LPTSTR instead of LPCTSTR. DWORD err = InternetConfirmZoneCrossing(_pbbd->_hwnd, (LPWSTR)pszURLPrev, (LPWSTR) pszURLNew, FALSE); hr = HRESULT_FROM_WIN32(err); TraceMsg(DM_ZONE, "CSB::_CheckZoneCrossing InetConfirmZoneXing %hs %hs returned %d", pszURLPrev, pszURLNew, err); if (FAILED(hr) && (HRESULT_FROM_WIN32(ERROR_CANCELLED) != hr) && (E_OUTOFMEMORY != hr)) { // We only need to investigate an error if it is unexpected. Out of memory and // a user cancelling the dialog are valid. TraceMsg(DM_ERROR, "CSB::_CheckZoneCrossing ICZC returned error (%d)", err); } } else { TraceMsg(DM_ZONE, "CSB::_CheckZoneCrossing IEGetDisplayName(pidl) failed %x", hresT); } } else { TraceMsg(DM_ZONE, "CSB::_CheckZoneCrossing IEGetDisplayName(pidlRef) failed %x", hresT); } } SetReferrer(NULL); return hr; } BOOL CShellBrowser2::v_IsIEModeBrowser() { // // if we didnt register the window or if it is not registered as 3rdparty, // then it is allowed to be an IEModeBrowser. // return (!_fDidRegisterWindow || (_swcRegistered != SWC_3RDPARTY)) && (_fInternetStart || (_pbbd->_pidlCur && IsURLChild(_pbbd->_pidlCur, TRUE))); } // IServiceProvider::QueryService STDMETHODIMP CShellBrowser2::QueryService(REFGUID guidService, REFIID riid, void **ppvObj) { if (IsEqualGUID(guidService, SID_SExplorerToolbar)) { LPTOOLBARITEM ptbi = _GetToolbarItem(ITB_ITBAR); if (ptbi->ptbar) { return ptbi->ptbar->QueryInterface(riid, ppvObj); } } else if (IsEqualGUID(guidService, SID_SMenuBandHandler) || IsEqualGUID(guidService, SID_SHostProxyFilter)) { return QueryInterface(riid, ppvObj); } return SUPERCLASS::QueryService(guidService, riid, ppvObj); } HRESULT CShellBrowser2::EnableModelessSB(BOOL fEnable) { HRESULT hres = SUPERCLASS::EnableModelessSB(fEnable); // // We don't want to leave the frame window disabled if a control left // us disabled because of its bug. Instead, we'll put a warning dialog // box -- IDS_CLOSEANYWAY. (SatoNa) // #if 0 EnableMenuItem(GetSystemMenu(_pbbd->_hwnd, FALSE), SC_CLOSE, (S_OK == _DisableModeless()) ? (MF_BYCOMMAND | MF_GRAYED) : (MF_BYCOMMAND| MF_ENABLED)); #endif return hres; } LPCITEMIDLIST CShellBrowser2::_GetPidl() { LPCITEMIDLIST pidl = _pbbd->_pidlNewShellView; if (pidl == NULL) pidl = _pbbd->_pidlPending; if (pidl == NULL) pidl = _pbbd->_pidlCur; return pidl; } BOOL CShellBrowser2::_DoesPidlRoam(LPCITEMIDLIST pidl) { WCHAR szPath[MAX_PATH]; BOOL fRet = SHGetPathFromIDList(pidl, szPath); if (fRet) { fRet = PathIsUNC(szPath); } return fRet; } HRESULT CShellBrowser2::_CreateFakeNilPidl(LPITEMIDLIST *ppidl) { IShellFolder *psfDesktop; HRESULT hr = SHGetDesktopFolder(&psfDesktop); if (SUCCEEDED(hr)) { IBindCtx *pbc; hr = BindCtx_CreateWithMode(STGM_CREATE, &pbc); if (SUCCEEDED(hr)) { // the new "nil" clsid hr = psfDesktop->ParseDisplayName(NULL, pbc, L"::{cce6191f-13b2-44fa-8d14-324728beef2c}", NULL, ppidl, NULL); pbc->Release(); } psfDesktop->Release(); } return hr; } BOOL CShellBrowser2::_IsPageInternet(LPCITEMIDLIST pidl) { BOOL fInternet = FALSE; if (((NULL == pidl) && IsEqualCLSID(_clsidThis, CLSID_InternetExplorer)) || IsBrowserFrameOptionsPidlSet(pidl, BFO_BROWSER_PERSIST_SETTINGS)) { fInternet = TRUE; } return fInternet; } HRESULT CShellBrowser2::_GetPropertyBag(LPCITEMIDLIST pidl, DWORD dwFlags, REFIID riid, void** ppv) { HRESULT hr; if (_IsPageInternet(pidl)) { LPITEMIDLIST pidlIE = IEGetInternetRootID(); if (pidlIE) { hr = SHGetViewStatePropertyBag(pidlIE, VS_BAGSTR_EXPLORER, dwFlags, riid, ppv); ILFree(pidlIE); } else { hr = E_OUTOFMEMORY; } } else if (!pidl || _fNilViewStream) { // the old-style save-to-stream code faked up a "nil" location in the case of NULL. // additionally if we loaded from this fake stream we had to save to it later. // the search window actually relies on this behavior since it doesnt get its // pidl for navigation until the window is already up. // it's too late to change the way search initializes its view window and the // solution is nontrivial anyway, so mimic the old behavior here. LPITEMIDLIST pidlNil; hr = _CreateFakeNilPidl(&pidlNil); if (SUCCEEDED(hr)) { hr = SHGetViewStatePropertyBag(pidlNil, VS_BAGSTR_EXPLORER, dwFlags, riid, ppv); ILFree(pidlNil); } _fNilViewStream = TRUE; } else { if (_DoesPidlRoam(pidl)) { dwFlags |= SHGVSPB_ROAM; } hr = SHGetViewStatePropertyBag(pidl, VS_BAGSTR_EXPLORER, dwFlags, riid, ppv); } return hr; } HRESULT CShellBrowser2::GetPropertyBag(DWORD dwFlags, REFIID riid, void** ppv) { LPCITEMIDLIST pidl = _GetPidl(); return _GetPropertyBag(pidl, dwFlags, riid, ppv); } HRESULT CShellBrowser2::GetViewStateStream(DWORD grfMode, IStream **ppstm) // 99/02/05 #226140 vtan: DefView doesn't perist the dwDefRevCount // like ShellBrowser does. When DefView asks ShellBrowser for the // view state stream ShellBrowser would blindly return the stream // (implemented in the super class CCommonBrowser). In order to // ensure the stream's validity the method is now replaced with // this code which verifies the dwDefRevCount matches. If there // is a mismatch the function bails with an error otherwise it // calls the regularly scheduled program (super CCommonBrowser). // This will have to be revisited when separating frame // state from view state. { HRESULT hResult; IStream* pIStream; LPCITEMIDLIST pIDL; pIDL = _GetPidl(); pIStream = v_GetViewStream(pIDL, STGM_READ, L"CabView"); if (pIStream != NULL) { CABSH cabinetStateHeader; hResult = _FillCabinetStateHeader(pIStream, &cabinetStateHeader); pIStream->Release(); if (SUCCEEDED(hResult) && ((cabinetStateHeader.fMask & CABSHM_REVCOUNT) != 0) && (g_dfs.dwDefRevCount != cabinetStateHeader.dwRevCount)) { *ppstm = NULL; return(E_FAIL); } } return(SUPERCLASS::GetViewStateStream(grfMode, ppstm)); } LRESULT CALLBACK CShellBrowser2::DummyTBWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { CShellBrowser2* pSB = (CShellBrowser2*)GetWindowPtr0(hwnd); // GetWindowLong(hwnd, 0) LRESULT lRes = 0L; if (uMsg < WM_USER) return(::DefWindowProcWrap(hwnd, uMsg, wParam, lParam)); else { switch (uMsg) { case TB_ADDBITMAP: pSB->_pxtb->AddBitmap(&CGID_ShellBrowser, BITMAP_NORMAL, (UINT)wParam, (TBADDBITMAP*)lParam, &lRes, RGB(192,192,192)); pSB->_pxtb->AddBitmap(&CGID_ShellBrowser, BITMAP_HOT, (UINT)wParam, (TBADDBITMAP*)lParam, &lRes, RGB(192,192,192)); break; default: if (pSB->_pxtb) pSB->_pxtb->SendToolbarMsg(&CGID_ShellBrowser, uMsg, wParam, lParam, &lRes); return lRes; } } return lRes; } // When a view adds buttons with no text, the CInternet toolbar may call back and ask // for the tooltip strings. Unfortunately, at that time _pbbd->_hwndView is not yet set and therefore // the tooltip texts will not be set. // // So, to get around that, we do not add the buttons if there is no _pbbd->_hwndView (see ::SetToolbarItem) // The CBaseBrowser2's ::_SwitchActivationNow() is the one that sets the _pbbd->_hwndView. So when this hwnd is // set then we add the buttons // // We send the WM_NOTIFYFORMAT because when CInternetToolbar::AddButtons calls back with the WM_NOTIFYs // for the tooltips, we need to know whether or not the view is UNICODE or not. HRESULT CShellBrowser2::_SwitchActivationNow() { ASSERT(_pbbd->_psvPending); #if 0 // if we have a progress control, make sure it's off before we switch activation if (_hwndProgress) SendControlMsg(FCW_PROGRESS, PBM_SETRANGE32, 0, 0, NULL); #endif SUPERCLASS::_SwitchActivationNow(); // need to do this as close to the assign of _pbbd->_hwndView as possible _fUnicode = (SendMessage (_pbbd->_hwndView, WM_NOTIFYFORMAT, (WPARAM)_pbbd->_hwnd, NF_QUERY) == NFR_UNICODE); if (_lpButtons) { LocalFree(_lpButtons); _lpButtons = NULL; _nButtons = 0; } if (_lpPendingButtons) { _lpButtons = _lpPendingButtons; _nButtons = _nButtonsPending; _lpPendingButtons = NULL; _nButtonsPending = 0; if ((_pxtb) && (_pbbd->_hwndView)) _pxtb->AddButtons(&CGID_ShellBrowser, _nButtons, _lpButtons); } return S_OK; } #ifdef DEBUG /*---------------------------------------------------------- Purpose: Dump the menu handles for this browser. Optionally breaks after dumping handles. */ void CShellBrowser2::_DumpMenus( IN LPCTSTR pszMsg, IN BOOL bBreak) { if (IsFlagSet(g_dwDumpFlags, DF_DEBUGMENU)) { ASSERT(pszMsg); TraceMsg(TF_ALWAYS, "CShellBrowser2: Dumping menus for %#08x %s", (void *)this, pszMsg); TraceMsg(TF_ALWAYS, " _hmenuTemplate = %x, _hmenuFull = %x, _hmenuBrowser = %x", _hmenuTemplate, _hmenuFull, _hmenuBrowser); TraceMsg(TF_ALWAYS, " _hmenuCur = %x, _hmenuPreMerged = %x, _hmenuHelp = %x", _hmenuCur, _hmenuPreMerged, _hmenuHelp); _menulist.Dump(pszMsg); if (bBreak && IsFlagSet(g_dwBreakFlags, BF_ONDUMPMENU)) DebugBreak(); } } #endif HRESULT CShellBrowser2::SetBorderSpaceDW(IUnknown* punkSrc, LPCBORDERWIDTHS pborderwidths) { return SUPERCLASS::SetBorderSpaceDW(punkSrc, pborderwidths); } // // This is a helper member of CBaseBroaser class (non-virtual), which // returns the effective client area. We get this rectangle by subtracting // the status bar area from the real client area. // HRESULT CShellBrowser2::_GetEffectiveClientArea(LPRECT lprectBorder, HMONITOR hmon) { static const int s_rgnViews[] = {1, 0, 1, FCIDM_STATUS, 0, 0}; // n.b. do *not* call SUPER/_psbInner ASSERT(hmon == NULL); GetEffectiveClientRect(_pbbd->_hwnd, lprectBorder, (LPINT)s_rgnViews); return S_OK; } // Should we return more informative return values? // "Browser Helper Objects" BOOL CShellBrowser2::_LoadBrowserHelperObjects(void) { BOOL bRet = FALSE; BOOL bNoExplorer = FALSE; HKEY hkey; // We shouldn't load browser extensions if we're in fail-safe mode, or if the user asked us to disable these extensions/ // In the future, we should allow disabling on a per-extension basis (when not in safe mode) if ((!SHRegGetBoolUSValue(TEXT("SOFTWARE\\Microsoft\\Internet Explorer\\Main"), TEXT("Enable Browser Extensions"), FALSE, TRUE)) || (GetSystemMetrics(SM_CLEANBOOT)!=0)) { return TRUE; } if (_pbbd->_pautoWB2 && RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGSTR_PATH_EXPLORER TEXT("\\Browser Helper Objects"), 0, KEY_ENUMERATE_SUB_KEYS, &hkey) == ERROR_SUCCESS) { TCHAR szGUID[64]; DWORD cb = ARRAYSIZE(szGUID); for (int i = 0; RegEnumKeyEx(hkey, i, szGUID, &cb, NULL, NULL, NULL, NULL) == ERROR_SUCCESS; i++) { // If we're not in IEXPLORE's process // if (!_fRunningInIexploreExe) { // Check to see if there's a "NoExplorer" value // bNoExplorer = (ERROR_SUCCESS == SHGetValue(hkey, szGUID, TEXT("NoExplorer"), NULL, NULL, NULL)); } // If we're in IEXPLORE.EXE or we're in EXPLORER.EXE but there's no "NoExplorer" value, then // go ahead and load the BHO if (_fRunningInIexploreExe || !bNoExplorer) { CLSID clsid; IObjectWithSite *pows; if (GUIDFromString(szGUID, &clsid) && !(SHGetObjectCompatFlags(NULL, &clsid) & OBJCOMPATF_UNBINDABLE) && SUCCEEDED(CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IObjectWithSite, &pows)))) { pows->SetSite(_pbbd->_pautoWB2); // give the poinetr to IWebBrowser2 SA_BSTRGUID strClsid; // now register this object so that it can be found through automation. SHTCharToUnicode(szGUID, strClsid.wsz, ARRAYSIZE(strClsid.wsz)); strClsid.cb = lstrlenW(strClsid.wsz) * sizeof(WCHAR); VARIANT varUnknown = {0}; varUnknown.vt = VT_UNKNOWN; varUnknown.punkVal = pows; _pbbd->_pautoWB2->PutProperty(strClsid.wsz, varUnknown); pows->Release(); // Instead of calling variantClear() bRet = TRUE; } } cb = ARRAYSIZE(szGUID); } RegCloseKey(hkey); } return bRet; } HRESULT CShellBrowser2::OnViewWindowActive(IShellView * psv) { _pbsInner->SetActivateState(SVUIA_ACTIVATE_FOCUS); return SUPERCLASS::OnViewWindowActive(psv); } HRESULT CShellBrowser2::_PositionViewWindow(HWND hwnd, LPRECT prc) { if (hwnd == _hwndDelayedSize) { _fHaveDelayedSize = TRUE; _rcDelayedSize = *prc; } else { RECT rc = *prc; if (_ptheater) { InflateRect(&rc, GetSystemMetrics(SM_CXEDGE), GetSystemMetrics(SM_CYEDGE)); } SetWindowPos(hwnd, NULL, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, SWP_NOZORDER | SWP_NOACTIVATE); } return S_OK; } HRESULT CShellBrowser2::OnFocusChangeIS(IUnknown* punkSrc, BOOL fSetFocus) { if (fSetFocus && _ptheater && SHIsSameObject(punkSrc, _GetITBar())) { _ptheater->Exec(&CGID_Theater, THID_TOOLBARACTIVATED, 0, NULL, NULL); } return SUPERCLASS::OnFocusChangeIS(punkSrc, fSetFocus); } HRESULT CShellBrowser2::Offline(int iCmd) { HRESULT hresIsOffline = SUPERCLASS::Offline(iCmd); if (iCmd == SBSC_TOGGLE) { VARIANTARG var = {0}; if (_pbbd->_pctView && SUCCEEDED(_pbbd->_pctView->Exec(&CGID_Explorer, SBCMDID_GETPANE, PANE_OFFLINE, NULL, &var)) && V_UI4(&var) != PANE_NONE) { SendControlMsg(FCW_STATUS, SB_SETICON, V_UI4(&var), (hresIsOffline == S_OK) ? (LPARAM) OfflineIcon() : NULL, NULL); if (hresIsOffline == S_OK) { InitTitleStrings(); SendControlMsg(FCW_STATUS, SB_SETTIPTEXT, V_UI4(&var), (LPARAM) g_szWorkingOfflineTip, NULL); } } } return hresIsOffline; } HRESULT CShellBrowser2::_FreshenComponentCategoriesCache(BOOL bForceUpdate) { CATID catids[2] ; ULONG cCatids = 0 ; catids[0] = CATID_InfoBand ; catids[1] = CATID_CommBand ; // Check if our CATIDs are cached... if (!bForceUpdate) { for(ULONG i=0; i< ARRAYSIZE(catids); i++) { if (S_OK != SHDoesComCatCacheExist(catids[i], TRUE)) { bForceUpdate = TRUE ; break ; } } } if (bForceUpdate) { // Create an event for the comcat task to signal when it's // done. We need to do this because sometimes the task hasn't // finished by the time the user opens the "Explorer Bars" // submenu, and so they won't see the Bloomberg bar (for // example) that they just installed unless we wait for the task // to complete. if (_hEventComCat == NULL) _hEventComCat = CreateEvent(NULL, FALSE, FALSE, NULL); return SHWriteClassesOfCategories(ARRAYSIZE(catids), catids, 0, NULL, TRUE, FALSE /*no wait*/, _hEventComCat) ; } return S_FALSE ; } void CShellBrowser2::_QueryHKCRChanged() { ASSERT(g_fRunningOnNT && GetUIVersion() >= 5); // In an integrated installation >= v5 on NT, we have the benefit // of an HKCR change notification. Posting this message will cause // the desktop to check to see if HKCR was modified recently; if so, // the _SetupAppRan handler will execute in the desktop process. // This causes, among other evil, freshening of our component categories cache. // it is ok that this is isnt synchronous because the update // is async regardless. PostMessage(GetShellWindow(), DTM_QUERYHKCRCHANGED, QHKCRID_VIEWMENUPOPUP, (LPARAM)NULL) ; }