windows-nt/Source/XPSP1/NT/shell/shdocvw/fldset.cpp
2020-09-26 16:20:57 +08:00

472 lines
14 KiB
C++

#include "priv.h"
#include "fldset.h"
#define IShellView_CreateViewWindow(_pi, _piPrev, _pfs, _psb, _prc, _phw) \
(_pi)->CreateViewWindow(_piPrev, _pfs, _psb, _prc, _phw)
#define IShellView2_GetView(_pi, _pv, _flg) \
(_pi)->GetView(_pv, _flg)
#define IShellView2_CreateViewWindow2(_pi, _cParams) \
(_pi)->CreateViewWindow2(_cParams)
#define IUnknown_QueryInterface(_pu, _riid, _pi) \
(_pu)->QueryInterface(_riid, (LPVOID*)_pi)
#define IUnknown_AddRef(_pu) (_pu)->AddRef()
#define IUnknown_Release(_pu) (_pu)->Release()
typedef struct CViewSet
{
HDSA _dsaViews;
} CViewSet;
CViewSet* CViewSet_New()
{
CViewSet* pThis = (CViewSet*)LocalAlloc(LPTR, SIZEOF(CViewSet));
if (!pThis)
{
return(NULL);
}
pThis->_dsaViews = DSA_Create(SIZEOF(SHELLVIEWID), 8);
if (!pThis->_dsaViews)
{
LocalFree(pThis);
pThis = NULL;
}
return(pThis);
}
int CViewSet_Add(CViewSet* that, SHELLVIEWID const* pvid)
{
return(DSA_AppendItem(that->_dsaViews, (LPVOID)pvid));
}
void CViewSet_Delete(CViewSet* that)
{
DSA_Destroy(that->_dsaViews);
that->_dsaViews = NULL;
LocalFree((HLOCAL)that);
that = NULL;
}
void CViewSet_GetDefaultView(CViewSet* that, SHELLVIEWID* pvid)
{
DSA_GetItem(that->_dsaViews, 0, (LPVOID)pvid);
}
void CViewSet_SetDefaultView(CViewSet* that, SHELLVIEWID const* pvid)
{
DSA_SetItem(that->_dsaViews, 0, (LPVOID)pvid);
}
// PERF: A linear search for the view
BOOL CViewSet_IsViewSupported(CViewSet* that, SHELLVIEWID const* pvid)
{
int i;
// Only go down to 1 since item 0 is the default view
for (i=DSA_GetItemCount(that->_dsaViews)-1; i>=1; --i)
{
if (0 == memcmp(pvid, DSA_GetItemPtr(that->_dsaViews, i),
SIZEOF(SHELLVIEWID)))
{
return(TRUE);
}
}
return(FALSE);
}
// PERF: a linear check
BOOL CViewSet_IsSame(CViewSet* that, CViewSet* pThatView)
{
int iView = DSA_GetItemCount(pThatView->_dsaViews);
if (DSA_GetItemCount(that->_dsaViews) != iView)
{
return(FALSE);
}
for (--iView; iView>=1; --iView)
{
if (!CViewSet_IsViewSupported(that,
(SHELLVIEWID const*)DSA_GetItemPtr(pThatView->_dsaViews, iView)))
{
return(FALSE);
}
}
return(TRUE);
}
BOOL CShellViews_Init(CShellViews* that)
{
if (that->_dpaViews)
{
return(TRUE);
}
{
HDPA dpaViews = DPA_Create(4);
if (!dpaViews)
{
return(FALSE);
}
{
CViewSet* pCommViews = CViewSet_New();
if (!pCommViews)
{
DPA_Destroy(dpaViews);
dpaViews = NULL;
return(FALSE);
}
// The first one is the last known view for that set
CViewSet_Add(pCommViews, &VID_LargeIcons);
CViewSet_Add(pCommViews, &VID_LargeIcons);
CViewSet_Add(pCommViews, &VID_SmallIcons);
CViewSet_Add(pCommViews, &VID_Thumbnails);
CViewSet_Add(pCommViews, &VID_List );
CViewSet_Add(pCommViews, &VID_Details );
CViewSet_Add(pCommViews, &VID_Tile );
if (0 != DPA_InsertPtr(dpaViews, 0, pCommViews))
{
CViewSet_Delete(pCommViews);
DPA_Destroy(dpaViews);
dpaViews = NULL;
return(FALSE);
}
that->_dpaViews = dpaViews;
return(TRUE);
}
}
}
void CShellViews_GetDefaultView(CShellViews* that, UINT uViewSet,
SHELLVIEWID* pvid)
{
CViewSet* pViewSet = (CViewSet*)DPA_GetPtr(that->_dpaViews, uViewSet);
if (!pViewSet)
{
pViewSet = (CViewSet*)DPA_GetPtr(that->_dpaViews, 0);
if (!pViewSet)
{
*pvid = VID_LargeIcons;
return;
}
}
CViewSet_GetDefaultView(pViewSet, pvid);
}
void CShellViews_SetDefaultView(CShellViews* that, UINT uViewSet,
SHELLVIEWID const* pvid)
{
CViewSet* pViewSet = (CViewSet*)DPA_GetPtr(that->_dpaViews, uViewSet);
if (!pViewSet)
{
return;
}
CViewSet_SetDefaultView(pViewSet, pvid);
}
// PERF: a linear search for the view set
int CShellViews_Add(CShellViews* that, CViewSet* pThisView, BOOL *pbNew)
{
int iViewSet;
*pbNew = FALSE;
for (iViewSet=0; ; ++iViewSet)
{
CViewSet* pThatView = (CViewSet*)DPA_GetPtr(that->_dpaViews, iViewSet);
if (!pThatView)
{
break;
}
if (CViewSet_IsSame(pThatView, pThisView))
{
// Found the same set; delete the one passed in and hand back the
// existing one
CViewSet_Delete(pThisView);
return(iViewSet);
}
}
// I guess we didn't find it
iViewSet = DPA_AppendPtr(that->_dpaViews, (LPVOID)pThisView);
if (iViewSet < 0)
{
CViewSet_Delete(pThisView);
return(0);
}
*pbNew = TRUE;
return(iViewSet);
}
BOOL CShellViews_IsViewSupported(CShellViews* that, UINT uViewSet,
SHELLVIEWID const*pvid)
{
CViewSet* pViewSet = (CViewSet*)DPA_GetPtr(that->_dpaViews, uViewSet);
if (!pViewSet)
{
return(FALSE);
}
return(CViewSet_IsViewSupported(pViewSet, pvid));
}
int DPA_CViewSet_DeleteCallback(LPVOID p, LPVOID d)
{
if (p)
CViewSet_Delete((CViewSet*)p);
return 1;
}
void CShellViews_Delete(CShellViews* that)
{
if (that && that->_dpaViews)
{
DPA_DestroyCallback(that->_dpaViews, DPA_CViewSet_DeleteCallback, 0);
that->_dpaViews = NULL;
}
}
BOOL FileCabinet_GetDefaultViewID2(FOLDERSETDATABASE* that, SHELLVIEWID* pvid)
{
if (CShellViews_Init(&that->_cViews))
{
CShellViews_GetDefaultView(&that->_cViews, that->_iViewSet, pvid);
return(TRUE);
}
return(FALSE);
}
HRESULT FileCabinet_CreateViewWindow2(IShellBrowser* psb, FOLDERSETDATABASE* that, IShellView *psvNew,
IShellView *psvOld, RECT *prcView, HWND *phWnd)
{
SHELLVIEWID vid, vidOld, vidRestore;
IShellView2 *psv2New;
CViewSet *pThisView;
DWORD dwViewPriority;
BOOL bCalledSV2 = FALSE;
HRESULT hres = S_OK; // init to avoid a bogus C4701 warning
if (!CShellViews_Init(&that->_cViews))
{
// Can't do anything with view sets; just do the old thing
goto OldStyle;
}
// Default to whatever the last "old-style" view is
CShellViews_GetDefaultView(&that->_cViews, 0, &vidOld);
if (psvOld)
{
IShellView2 *psv2Old;
if (SUCCEEDED(IUnknown_QueryInterface(psvOld, IID_IShellView2,
&psv2Old)))
{
// Try to get the current view
if (NOERROR == IShellView2_GetView(psv2Old, &vidOld, SV2GV_CURRENTVIEW))
{
CShellViews_SetDefaultView(&that->_cViews, that->_iViewSet, &vidOld);
}
IUnknown_Release(psv2Old);
}
else
{
// Get the view ID from the folder settings
ViewIDFromViewMode(that->_fld._fs.ViewMode, &vidOld);
CShellViews_SetDefaultView(&that->_cViews, 0, &vidOld);
}
}
pThisView = CViewSet_New();
if (!pThisView)
{
goto OldStyle;
}
if (SUCCEEDED(IUnknown_QueryInterface(psvNew, IID_IShellView2, &psv2New)))
{
SHELLVIEWID vidFolderDefault;
if (NOERROR == IShellView2_GetView(psv2New, &vidFolderDefault, SV2GV_DEFAULTVIEW))
{
// we can now make up a view set for that folder
if (CViewSet_Add(pThisView, &vidFolderDefault) >= 0)
{
int iViewSet;
UINT uView;
BOOL bNew;
// NOTE: This usage of IShellView2::GetView is not documented in MSDN...
for (uView=0; NOERROR==IShellView2_GetView(psv2New, &vid, uView);
++uView)
{
CViewSet_Add(pThisView, &vid);
}
// Add that view set. we will get an existing view set if it is
// a duplicate
iViewSet = CShellViews_Add(&that->_cViews, pThisView, &bNew);
// This is now owned by CShellViews
pThisView = NULL;
//
// Here is where we decide which view we want to use.
//
// Start with what came from the FOLDERSETDATABASE, then see if
// anyone else has a higher VIEW_PRIORITY_XXX that would override this one.
vidRestore = that->_fld._vidRestore;
dwViewPriority = that->_fld._dwViewPriority;
// ToddB, 8-18-99:
// When we set the _fld._dwViewPriority in WebBrowserOc::Load(IPropertyBag *...) we want that ViewID to stick
// around. Only failing the CShellViews_IsViewSupported call below should set a different view. Even then
// we want to go back to this view on the next navigate. To accomplish this we need to keep the priority of
// that view at what it was originally set to. This can be done by removing the following line of code:
//
// that->_fld._dwViewPriority = VIEW_PRIORITY_NONE;
//
// However, its possible that the line of code above was there for a good reason. I suspect that line was
// originally added simply as a precaution or because the meaning of _vidRestore was not clearly defined in
// relation to navigation inside a WebBrowserOC. I'm leaving the line here and commented out just in case.
// If any new bugs arise about changing the view window and getting the wrong view I would look here first.
// Make sure that what we got is a supported view
if (!CShellViews_IsViewSupported(&that->_cViews, iViewSet, &vidRestore))
{
// Oops, that view isn't supported by this shell ext.
// Set the priority to NONE so that one of the others will override it.
dwViewPriority = VIEW_PRIORITY_NONE;
}
DWORD cbSize;
DWORD dwValue;
DWORD dwShellExtPriority;
cbSize = SIZEOF(dwValue);
if (ERROR_SUCCESS == SHGetValue(HKEY_CURRENT_USER,
TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced"),
TEXT("ClassicViewState"), NULL, &dwValue, &cbSize)
&& dwValue)
{
// We want to inherit from the previous folder if at all possible
// Otherwise, we will use the new shell extended view.
// To do this, we set the shell ext view priority lower than inherit
dwShellExtPriority = VIEW_PRIORITY_SHELLEXT_ASBACKUP;
}
else
{
dwShellExtPriority = VIEW_PRIORITY_SHELLEXT;
}
// Let the shell ext select the view if it has higher priority than
// what we already have, and it is supported as well.
if (dwViewPriority <= dwShellExtPriority &&
((GetUIVersion() >= 5) || (vidFolderDefault != VID_LargeIcons)) && // downlevel browser assumes VID_LargeIcons means "default"
CShellViews_IsViewSupported(&that->_cViews, iViewSet, &vidFolderDefault))
{
// shell extension is more important
vidRestore = vidFolderDefault;
dwViewPriority = dwShellExtPriority;
}
// Maybe we can inherit it from the previous view...
if (dwViewPriority <= VIEW_PRIORITY_INHERIT &&
psvOld &&
bNew &&
CShellViews_IsViewSupported(&that->_cViews, iViewSet, &vidOld))
{
// We just navigated from another shell view. Use the same view as the last
// folder.
vidRestore = vidOld;
dwViewPriority = VIEW_PRIORITY_INHERIT;
}
// We're getting really desperate now...
if (dwViewPriority <= VIEW_PRIORITY_DESPERATE)
{
// Try the last view for the folders current viewset.
CShellViews_GetDefaultView(&that->_cViews, iViewSet, &vidRestore);
dwViewPriority = VIEW_PRIORITY_DESPERATE;
}
// All finished trying to figure out what view to use
ASSERT(dwViewPriority > VIEW_PRIORITY_NONE);
// assure webview no in vid, it is persisted in shellstate now.
{
SV2CVW2_PARAMS cParams =
{
SIZEOF(SV2CVW2_PARAMS),
psvOld,
&that->_fld._fs,
psb,
prcView,
&vidRestore,
NULL,
} ;
hres = IShellView2_CreateViewWindow2(psv2New, &cParams);
bCalledSV2 = TRUE;
*phWnd = cParams.hwndView;
}
if (SUCCEEDED(hres))
{
that->_iViewSet = iViewSet;
}
}
}
IUnknown_Release(psv2New);
}
if (pThisView)
{
CViewSet_Delete(pThisView);
}
if (bCalledSV2)
{
return(hres);
}
OldStyle:
that->_iViewSet = 0;
return IShellView_CreateViewWindow(psvNew, psvOld, &that->_fld._fs, (IShellBrowser*)psb, prcView, phWnd);
}