[BROWSEUI] Save/Restore ShellBrowser bar states (#7035)

Save/Restore the state of the ShellBrowser toolbar/addressbar/statusbar.

Windows shares the state of the Go button and the locked state between Explorer and Internet Explorer but the bar states are not shared.

Notes:
- Seems to fix CORE-17236.
- The stream layout does not match Windows so it uses a different name. The toolbar customize dialog needs to be fixed before it makes sense trying to save the toolbar state and the layout of other bands.

CORE-17236
This commit is contained in:
Whindmar Saksit 2024-06-21 19:17:13 +02:00 committed by GitHub
parent 75db8c633a
commit 674136bcd0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 141 additions and 22 deletions

View file

@ -75,6 +75,19 @@ TODO:
extern HRESULT WINAPI SHBindToFolder(LPCITEMIDLIST path, IShellFolder **newFolder);
struct ITBARSTATE
{
static const UINT SIG = ('R' << 0) | ('O' << 8) | ('S' << 16) | (('i' ^ 't' ^ 'b') << 24);
UINT cbSize;
UINT Signature; // Note: Windows has something else here (12 bytes)
UINT StdToolbar : 1;
UINT Addressbar : 1;
UINT Linksbar : 1;
UINT Throbber : 1; // toastytech.com/files/throboff.html
UINT Menubar : 1; // ..\Explorer\Advanced\AlwaysShowMenus for NT6?
// Note: Windows 8/10 stores the Ribbon state in ..\Explorer\Ribbon
};
HRESULT IUnknown_RelayWinEvent(IUnknown * punk, HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *theResult)
{
CComPtr<IWinEventHandler> menuWinEventHandler;
@ -614,6 +627,7 @@ CInternetToolbar::CInternetToolbar()
fToolbarWindow = NULL;
fAdviseCookie = 0;
pSettings = NULL;
fIgnoreChanges = FALSE;
}
CInternetToolbar::~CInternetToolbar()
@ -893,6 +907,7 @@ HRESULT STDMETHODCALLTYPE CInternetToolbar::ShowDW(BOOL fShow)
return hResult;
}
#if 0 // Why should showing the IDockingWindow change all bands? Related to CORE-17236
if (fMenuBar)
{
hResult = IUnknown_ShowDW(fMenuBar, fShow);
@ -918,6 +933,7 @@ HRESULT STDMETHODCALLTYPE CInternetToolbar::ShowDW(BOOL fShow)
if (FAILED_UNEXPECTEDLY(hResult))
return hResult;
}
#endif
return S_OK;
}
@ -1001,6 +1017,14 @@ HRESULT STDMETHODCALLTYPE CInternetToolbar::GetClassID(CLSID *pClassID)
return S_OK;
}
HRESULT CInternetToolbar::SetDirty()
{
if (fIgnoreChanges)
return S_OK;
IUnknown_Exec(fSite, CGID_ShellBrowser, IDM_NOTIFYITBARDIRTY, 0, NULL, NULL);
return S_OK;
}
HRESULT STDMETHODCALLTYPE CInternetToolbar::IsDirty()
{
return E_NOTIMPL;
@ -1008,12 +1032,35 @@ HRESULT STDMETHODCALLTYPE CInternetToolbar::IsDirty()
HRESULT STDMETHODCALLTYPE CInternetToolbar::Load(IStream *pStm)
{
return E_NOTIMPL;
fIgnoreChanges = TRUE;
HRESULT hr = InitNew();
ITBARSTATE state;
if (SUCCEEDED(hr))
{
hr = S_FALSE;
ULONG cb = sizeof(state);
if (pStm->Read(&state, cb, &cb) == S_OK && state.Signature == state.SIG)
{
SetBandVisibility(ITBBID_MENUBAND, state.Menubar);
SetBandVisibility(ITBBID_TOOLSBAND, state.StdToolbar);
SetBandVisibility(ITBBID_ADDRESSBAND, state.Addressbar);
//SetBandVisibility(ITBBID_?, state.Linksbar);
//SetBandVisibility(ITBBID_?, state.Throbber);
hr = S_OK;
}
}
fIgnoreChanges = FALSE;
return hr;
}
HRESULT STDMETHODCALLTYPE CInternetToolbar::Save(IStream *pStm, BOOL fClearDirty)
{
return E_NOTIMPL;
ITBARSTATE state = { sizeof(state), state.SIG };
state.Menubar = IsBandVisible(ITBBID_MENUBAND) == S_OK;
state.StdToolbar = IsBandVisible(ITBBID_TOOLSBAND) == S_OK;
state.Addressbar = IsBandVisible(ITBBID_ADDRESSBAND) == S_OK;
state.Linksbar = FALSE;
return pStm->Write(&state, sizeof(state), NULL);
}
HRESULT STDMETHODCALLTYPE CInternetToolbar::GetSizeMax(ULARGE_INTEGER *pcbSize)
@ -1080,24 +1127,34 @@ HRESULT CInternetToolbar::IsBandVisible(int BandID)
return (bandInfo.fStyle & RBBS_HIDDEN) ? S_FALSE : S_OK;
}
HRESULT CInternetToolbar::ToggleBandVisibility(int BandID)
HRESULT CInternetToolbar::SetBandVisibility(int BandID, int Show)
{
int index = (int)SendMessage(fMainReBar, RB_IDTOINDEX, BandID, 0);
REBARBANDINFOW bandInfo = {sizeof(REBARBANDINFOW), RBBIM_STYLE | RBBIM_CHILD};
if (!SendMessage(fMainReBar, RB_GETBANDINFOW, index, (LPARAM)&bandInfo))
return E_FAIL;
REBARBANDINFOW bandInfo = {sizeof(REBARBANDINFOW), RBBIM_STYLE};
SendMessage(fMainReBar, RB_GETBANDINFOW, index, (LPARAM)&bandInfo);
if (bandInfo.fStyle & RBBS_HIDDEN)
if (Show < 0)
bandInfo.fStyle ^= RBBS_HIDDEN; // Toggle
else if (Show)
bandInfo.fStyle &= ~RBBS_HIDDEN;
else
bandInfo.fStyle |= RBBS_HIDDEN;
bandInfo.fMask &= ~RBBIM_CHILD;
::ShowWindow(bandInfo.hwndChild, (bandInfo.fStyle & RBBS_HIDDEN) ? SW_HIDE : SW_SHOW); // CORE-17236
SendMessage(fMainReBar, RB_SETBANDINFOW, index, (LPARAM)&bandInfo);
ReserveBorderSpace(0);
SetDirty();
return S_OK;
}
HRESULT CInternetToolbar::ToggleBandVisibility(int BandID)
{
return SetBandVisibility(BandID, -1);
}
HRESULT STDMETHODCALLTYPE CInternetToolbar::QueryStatus(const GUID *pguidCmdGroup,
ULONG cCmds, OLECMD prgCmds[ ], OLECMDTEXT *pCmdText)
{
@ -1685,7 +1742,6 @@ LRESULT CInternetToolbar::OnContextMenu(UINT uMsg, WPARAM wParam, LPARAM lParam,
if (hitTestInfo.iBand == -1)
return 0;
pSettings->Load();
rebarBandInfo.cbSize = sizeof(rebarBandInfo);
rebarBandInfo.fMask = RBBIM_ID;
SendMessage(fMainReBar, RB_GETBANDINFOW, hitTestInfo.iBand, (LPARAM)&rebarBandInfo);
@ -1930,3 +1986,19 @@ LRESULT CInternetToolbar::OnSettingsChange(UINT uMsg, WPARAM wParam, LPARAM lPar
return 0;
}
HRESULT CInternetToolbar::GetStream(UINT StreamFor, DWORD Stgm, IStream **ppS)
{
WCHAR path[MAX_PATH];
LPCWSTR subkey = NULL;
switch (StreamFor)
{
case ITBARSTREAM_SHELLBROWSER: subkey = L"ShellBrowser"; break;
case ITBARSTREAM_WEBBROWSER: subkey = L"WebBrowser"; break;
case ITBARSTREAM_EXPLORER: subkey = L"Explorer"; break;
default: return E_INVALIDARG;
}
wsprintfW(path, L"Software\\Microsoft\\Internet Explorer\\Toolbar\\%s", subkey);
*ppS = SHOpenRegStream2W(HKEY_CURRENT_USER, path, L"RosITBarLayout", Stgm); // ROS prefix until we figure out the correct format
return *ppS ? S_OK : E_FAIL;
}

View file

@ -20,6 +20,10 @@
#pragma once
#define ITBARSTREAM_SHELLBROWSER 0
#define ITBARSTREAM_WEBBROWSER 1
#define ITBARSTREAM_EXPLORER 2
static const int gSearchCommandID = 1003;
static const int gFoldersCommandID = 1004;
static const int gMoveToCommandID = FCIDM_SHVIEW_MOVETO;
@ -93,6 +97,7 @@ public:
POINT fStartPosition;
LONG fStartHeight;
ShellSettings *pSettings;
BOOL fIgnoreChanges;
public:
CInternetToolbar();
virtual ~CInternetToolbar();
@ -104,9 +109,13 @@ public:
HRESULT CommandStateChanged(bool newValue, int commandID);
HRESULT CreateAndInitBandProxy();
HRESULT IsBandVisible(int BandID);
HRESULT SetBandVisibility(int BandID, int Show);
HRESULT ToggleBandVisibility(int BandID);
HRESULT SetState(const GUID *pguidCmdGroup, long commandID, OLECMD* pcmd);
void RefreshLockedToolbarState();
HRESULT SetDirty();
static HRESULT GetStream(UINT StreamFor, DWORD Stgm, IStream **ppS);
public:
// *** IInputObject specific methods ***

View file

@ -73,6 +73,7 @@
/* Random id for band close button, feel free to change it */
#define IDM_BASEBAR_CLOSE 0xA200
#define IDM_NOTIFYITBARDIRTY 0xA239 /* Arbitrary id */
/* User-installed explorer band IDs according to API Monitor traces */
#define IDM_EXPLORERBAND_BEGINCUSTOM 0xA240

View file

@ -35,6 +35,7 @@ void ShellSettings::Load()
void CabinetStateSettings::Load()
{
this->cLength = sizeof(CABINETSTATE);
ReadCabinetState(this, this->cLength);
/* Overrides */

View file

@ -351,8 +351,10 @@ public:
HRESULT UpdateUpState();
void UpdateGotoMenu(HMENU theMenu);
void UpdateViewMenu(HMENU theMenu);
HRESULT IsInternetToolbarBandShown(UINT ITId);
void RefreshCabinetState();
void UpdateWindowTitle();
void SaveITBarLayout();
/* // *** IDockingWindowFrame methods ***
STDMETHOD(AddToolbar)(IUnknown *punkSrc, LPCWSTR pwszItem, DWORD dwAddFlags) override;
@ -771,19 +773,11 @@ HRESULT CShellBrowser::Initialize()
if (FAILED_UNEXPECTEDLY(hResult))
return hResult;
// TODO: create settingsStream from registry entry
//if (settingsStream.p)
//{
// hResult = persistStreamInit->Load(settingsStream);
// if (FAILED_UNEXPECTEDLY(hResult))
// return hResult;
//}
//else
{
hResult = persistStreamInit->InitNew();
if (FAILED_UNEXPECTEDLY(hResult))
return hResult;
}
CComPtr<IStream> pITBarStream;
hResult = CInternetToolbar::GetStream(ITBARSTREAM_EXPLORER, STGM_READ, &pITBarStream);
hResult = SUCCEEDED(hResult) ? persistStreamInit->Load(pITBarStream) : persistStreamInit->InitNew();
if (FAILED_UNEXPECTEDLY(hResult))
return hResult;
hResult = IUnknown_ShowDW(clientBar, TRUE);
if (FAILED_UNEXPECTEDLY(hResult))
@ -2136,6 +2130,9 @@ HRESULT STDMETHODCALLTYPE CShellBrowser::Exec(const GUID *pguidCmdGroup, DWORD n
{
case 40994:
return NavigateToParent();
case IDM_NOTIFYITBARDIRTY:
SaveITBarLayout();
break;
}
}
else if (IsEqualIID(*pguidCmdGroup, CGID_IExplorerToolbar))
@ -2383,7 +2380,7 @@ HRESULT STDMETHODCALLTYPE CShellBrowser::QueryService(REFGUID guidService, REFII
return this->QueryInterface(riid, ppvObject);
if (IsEqualIID(guidService, SID_SProxyBrowser))
return this->QueryInterface(riid, ppvObject);
if (IsEqualIID(guidService, SID_IExplorerToolbar))
if (IsEqualIID(guidService, SID_IExplorerToolbar) && fClientBars[BIInternetToolbar].clientBar.p)
return fClientBars[BIInternetToolbar].clientBar->QueryInterface(riid, ppvObject);
if (IsEqualIID(riid, IID_IShellBrowser))
return this->QueryInterface(riid, ppvObject);
@ -2495,6 +2492,9 @@ HRESULT STDMETHODCALLTYPE CShellBrowser::ShowControlWindow(UINT id, BOOL fShow)
return S_OK;
case FCW_TREE:
return Exec(&CGID_Explorer, SBCMDID_EXPLORERBARFOLDERS, 0, NULL, NULL);
case FCW_ADDRESSBAR:
return IUnknown_Exec(fClientBars[BIInternetToolbar].clientBar,
CGID_PrivCITCommands, ITID_ADDRESSBANDSHOWN, 0, NULL, NULL);
}
return E_NOTIMPL;
}
@ -2515,6 +2515,10 @@ HRESULT STDMETHODCALLTYPE CShellBrowser::IsControlWindowShown(UINT id, BOOL *pfS
shown = cmd.cmdf & OLECMDF_LATCHED;
break;
}
case FCW_ADDRESSBAR:
hr = IsInternetToolbarBandShown(ITID_ADDRESSBANDSHOWN);
shown = hr == S_OK;
break;
default:
hr = E_NOTIMPL;
}
@ -2526,6 +2530,14 @@ HRESULT STDMETHODCALLTYPE CShellBrowser::IsControlWindowShown(UINT id, BOOL *pfS
return SUCCEEDED(hr) ? (shown ? S_OK : S_FALSE) : hr;
}
HRESULT CShellBrowser::IsInternetToolbarBandShown(UINT ITId)
{
OLECMD cmd = { ITId };
HRESULT hr = IUnknown_QueryStatus(fClientBars[BIInternetToolbar].clientBar,
CGID_PrivCITCommands, 1, &cmd, NULL);
return SUCCEEDED(hr) ? (cmd.cmdf & OLECMDF_LATCHED) ? S_OK : S_FALSE : hr;
}
HRESULT STDMETHODCALLTYPE CShellBrowser::IEGetDisplayName(LPCITEMIDLIST pidl, LPWSTR pwszName, UINT uFlags)
{
return E_NOTIMPL;
@ -3986,3 +3998,25 @@ void CShellBrowser::UpdateWindowTitle()
if (SUCCEEDED(IEGetNameAndFlags(fCurrentDirectoryPIDL, flags, title, _countof(title), NULL)))
SetWindowText(title);
}
void CShellBrowser::SaveITBarLayout()
{
if (!gCabinetState.fSaveLocalView)
return;
#if 0 // If CDesktopBrowser aggregates us, skip saving
FOLDERSETTINGS fs;
if (fCurrentShellView && SUCCEEDED(fCurrentShellView->GetCurrentInfo(&fs)) && (fs.fFlags & FWF_DESKTOP))
return;
#endif
CComPtr<IPersistStreamInit> pPSI;
CComPtr<IStream> pITBarStream;
if (!fClientBars[BIInternetToolbar].clientBar.p)
return;
HRESULT hr = fClientBars[BIInternetToolbar].clientBar->QueryInterface(IID_PPV_ARG(IPersistStreamInit, &pPSI));
if (FAILED(hr))
return;
if (FAILED(hr = CInternetToolbar::GetStream(ITBARSTREAM_EXPLORER, STGM_WRITE, &pITBarStream)))
return;
pPSI->Save(pITBarStream, TRUE);
}

View file

@ -25,6 +25,8 @@
extern "C" {
#endif /* defined(__cplusplus) */
#define FCW_ADDRESSBAR 9 // GetControlWindow/IsControlWindowShown
// Name is IETHREADPARAM according to symbols / mangled function names
#ifdef _WIN64
typedef struct IEThreadParamBlock