|
|
#include "priv.h"
#include "hlframe.h"
#include "dochost.h"
#include "bindcb.h"
#include "iface.h"
#include "resource.h"
#include "idhidden.h"
#include "shdocfl.h"
const ITEMIDLIST s_idNull = { {0} }; extern HRESULT VariantClearLazy(VARIANTARG *pvarg); LPWSTR URLFindExtensionW(LPCWSTR pszURL, int * piLen);
#define DM_CACHETRACE 0
#define DM_ZONECROSSING 0
#define NAVMSG3(psz, x, y) TraceMsg(0, "NAV::%s %x %x", psz, x, y)
#define PAINTMSG(psz,x) TraceMsg(0, "TraceMsgPAINT::%s %x", psz, x)
#define JMPMSG(psz, psz2) TraceMsg(0, "TraceMsgCDOV::%s %s", psz, psz2)
#define JMPMSG2(psz, x) TraceMsg(0, "TraceMsgCDOV::%s %x", psz, x)
#define DOFMSG(psz) TraceMsg(0, "TraceMsgDOF::%s", psz)
#define DOFMSG2(psz, x) TraceMsg(0, "TraceMsgDOF::%s %x", psz, x)
#define URLMSG(psz) TraceMsg(0, "TraceMsgDOF::%s", psz)
#define URLMSG2(psz, x) TraceMsg(0, "TraceMsgDOF::%s %x", psz, x)
#define URLMSG3(psz, x, y) TraceMsg(0, "TraceMsgDOF::%s %x %x", psz, x, y)
#define BSCMSG(psz, i, j) TraceMsg(0, "TraceMsgBSC::%s %x %x", psz, i, j)
#define BSCMSG3(psz, i, j, k) TraceMsg(0, "TraceMsgBSC::%s %x %x %x", psz, i, j, k)
#define BSCMSG4(psz, i, j, k, l) TraceMsg(0, "TraceMsgBSC::%s %x %x %x %x", psz, i, j, k, l)
#define BSCMSGS(psz, sz) TraceMsg(0, "TraceMsgBSC::%s %s", psz, sz)
#define OIPSMSG(psz) TraceMsg(0, "TraceMsgOIPS::%s", psz)
#define OIPSMSG3(psz, sz, p) TraceMsg(0, "TraceMsgOIPS::%s %s,%x", psz, sz,p)
#define VIEWMSG(psz) TraceMsg(0, "CDOV::%s", psz)
#define VIEWMSG2(psz,xx) TraceMsg(0, "CDOV::%s %x", psz,xx)
#define CACHEMSG(psz, d) TraceMsg(0, "CDocObjectCtx::%s %d", psz, d)
#define OPENMSG(psz) TraceMsg(0, "OPENING %s", psz)
#define OPENMSG2(psz, x) TraceMsg(0, "OPENING %s %x", psz, x)
#define HFRMMSG(psz) TraceMsg(0, "HFRM::%s", psz)
#define HFRMMSG2(psz, x, y) TraceMsg(0, "HFRM::%s %x %x", psz, x, y)
#define MNKMSG(psz, psz2) TraceMsg(0, "MNK::%s (%s)", psz, psz2)
#define CHAINMSG(psz, x) TraceMsg(0, "CHAIN::%s %x", psz, x)
#define SHVMSG(psz, x, y) TraceMsg(0, "SHV::%s %x %x", psz, x, y)
#define HOMEMSG(psz, psz2, x) TraceMsg(0, "HOME::%s %s %x", psz, psz2, x)
#define SAVEMSG(psz, x) TraceMsg(0, "SAVE::%s %x", psz, x)
#define PERFMSG(psz, x) TraceMsg(TF_SHDPERF, "PERF::%s %d msec", psz, x)
// this saves the view information for this shell view class
typedef struct { UINT cbSize;
BOOL fCoolbar:1; BOOL fToolbar:1; BOOL fStatusbar:1;
} IEVIEWINFO;
class CDocObjectView : /* Group 1 */ public IShellView2, public IDropTarget , public IViewObject, public IAdviseSink , public IOleCommandTarget , public IDocViewSite , public IPrivateOleObject , public IPersistFolder , public IServiceProvider { protected: CDocObjectHost* _pdoh; IDocHostObject* _pdho;
UINT _cRef; IShellFolder *_psf; IShellBrowser* _psb; IOleCommandTarget* _pctShellBrowser; FOLDERSETTINGS _fs; LPITEMIDLIST _pidl; LPTSTR _pszLocation; UINT _uiCP;
IShellView * _psvPrev;
// Advisory connection
IAdviseSink *_padvise; DWORD _advise_aspect; DWORD _advise_advf;
BOOL _fInHistory : 1; BOOL _fSaveViewState : 1; BOOL _fIsGet : 1; BOOL _fCanCache : 1; BOOL _fCanCacheFetched : 1; BOOL _fPrevViewIsDocView : 1; BOOL _fSelfDragging : 1; // DocObject is the drag source
SYSTEMTIME _stLastRefresh; HWND _hwndParent;
UINT _uState; // DragContext
DWORD _dwDragEffect;
~CDocObjectView();
void _RestoreViewSettings(); void _SaveViewState(); void _GetViewSettings(IEVIEWINFO* pievi); int _ShowControl(UINT idControl, int idCmd); void _CreateDocObjHost(IShellView * psvPrev); void _CompleteDocHostPassing(IShellView *psvPrev, HRESULT hres); BOOL _CanUseCache(); void _SetLastRefreshTime() { GetSystemTime(&_stLastRefresh); };
void _ConnectHostSink(); void _DisconnectHostSink();
public: CDocObjectView(LPCITEMIDLIST pidl, IShellFolder *psf);
// *** IUnknown methods ***
STDMETHODIMP QueryInterface(REFIID riid, void ** ppvObj); STDMETHODIMP_(ULONG) AddRef(void) ; STDMETHODIMP_(ULONG) Release(void);
// *** IOleWindow methods ***
STDMETHODIMP GetWindow(HWND * lphwnd); STDMETHODIMP ContextSensitiveHelp(BOOL fEnterMode);
// *** IShellView methods ***
STDMETHODIMP TranslateAccelerator(LPMSG lpmsg); STDMETHODIMP EnableModelessSV(BOOL fEnable); STDMETHODIMP UIActivate(UINT uState); STDMETHODIMP Refresh();
STDMETHODIMP CreateViewWindow(IShellView *lpPrevView, LPCFOLDERSETTINGS lpfs, IShellBrowser * psb, RECT * prcView, HWND *phWnd); STDMETHODIMP DestroyViewWindow(); STDMETHODIMP GetCurrentInfo(LPFOLDERSETTINGS lpfs); STDMETHODIMP AddPropertySheetPages(DWORD dwReserved, LPFNADDPROPSHEETPAGE lpfn, LPARAM lparam); STDMETHODIMP SaveViewState(); STDMETHODIMP SelectItem(LPCITEMIDLIST pidlItem, UINT uFlags); STDMETHODIMP GetItemObject(UINT uItem, REFIID riid, void **ppv);
STDMETHODIMP GetView(SHELLVIEWID* pvid, ULONG uView) ; STDMETHODIMP CreateViewWindow2(LPSV2CVW2_PARAMS lpParams) ; STDMETHODIMP HandleRename(LPCITEMIDLIST pidl) ; STDMETHODIMP SelectAndPositionItem(LPCITEMIDLIST pidlItem, UINT uFlags, POINT *ppt) { return E_NOTIMPL; }
// IViewObject
STDMETHODIMP Draw(DWORD, LONG, void *, DVTARGETDEVICE *, HDC, HDC, const RECTL *, const RECTL *, BOOL (*)(ULONG_PTR), ULONG_PTR); STDMETHODIMP GetColorSet(DWORD, LONG, void *, DVTARGETDEVICE *, HDC, LOGPALETTE **); STDMETHODIMP Freeze(DWORD, LONG, void *, DWORD *); STDMETHODIMP Unfreeze(DWORD); STDMETHODIMP SetAdvise(DWORD, DWORD, IAdviseSink *); STDMETHODIMP GetAdvise(DWORD *, DWORD *, IAdviseSink **);
// IAdviseSink
STDMETHODIMP_(void) OnDataChange(FORMATETC *, STGMEDIUM *); STDMETHODIMP_(void) OnViewChange(DWORD dwAspect, LONG lindex); STDMETHODIMP_(void) OnRename(IMoniker *); STDMETHODIMP_(void) OnSave(); STDMETHODIMP_(void) OnClose();
// IOleCommandTarget
STDMETHODIMP QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD rgCmds[], OLECMDTEXT *pcmdtext); STDMETHODIMP Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANTARG *pvarargIn, VARIANTARG *pvarargOut);
// IDropTarget
STDMETHODIMP DragEnter( IDataObject *pdtobj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
STDMETHODIMP DragOver( DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
STDMETHODIMP DragLeave(void);
STDMETHODIMP Drop( IDataObject *pdtobj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
// IDocViewSite
STDMETHODIMP OnSetTitle(VARIANTARG *pvTitle);
// IPrivateOleObject
STDMETHODIMP SetExtent( DWORD dwDrawAspect, SIZEL *psizel); STDMETHODIMP GetExtent( DWORD dwDrawAspect, SIZEL *psizel);
// IPersist methods
STDMETHODIMP GetClassID(CLSID *pclsid);
// IPersistFolder methods
STDMETHODIMP Initialize(LPCITEMIDLIST pidl);
// IServiceProvider methods
STDMETHODIMP QueryService(REFGUID guidService, REFIID riid, void ** ppvObj); };
//--------------------------------------------------------------------------
// Detecting a memory leak
//--------------------------------------------------------------------------
CDocObjectView::~CDocObjectView() { // just in case
DestroyViewWindow();
if (_pidl) { ILFree(_pidl); _pidl = NULL; }
ATOMICRELEASE(_psf);
if (_pszLocation) { LocalFree(_pszLocation); _pszLocation = NULL; }
ATOMICRELEASE(_padvise);
ATOMICRELEASE(_psvPrev);
TraceMsg(TF_SHDLIFE, "dtor CDocObjectView(%x) being destructed", this); }
CDocObjectView::CDocObjectView(LPCITEMIDLIST pidl, IShellFolder* psf) : _psf(psf), _cRef(1) { TraceMsg(TF_SHDLIFE, "ctor CDocObjectView(%x) being constructed", this);
_dwDragEffect = DROPEFFECT_NONE; if (pidl) { _pidl = ILClone(pidl);
if (_pidl) { #ifndef UNIX
WCHAR wszPath[MAX_URL_STRING]; #else
WCHAR wszPath[MAX_URL_STRING] = TEXT(""); #endif
if(IEILGetFragment(_pidl, wszPath, SIZECHARS(wszPath))) { _pszLocation = StrDup(wszPath); }
_uiCP = IEILGetCP(_pidl); } }
ASSERT(psf); if (_psf) { _psf->AddRef(); } }
HRESULT CDocObjectView_Create(IShellView** ppvOut, IShellFolder * psf, LPCITEMIDLIST pidl) { *ppvOut = new CDocObjectView(pidl, psf); return (*ppvOut) ? S_OK : E_OUTOFMEMORY; }
HRESULT CDocObjectView::GetWindow(HWND * lphwnd) { *lphwnd = NULL; if (_pdoh) return _pdoh->GetWindow(lphwnd); return S_OK; }
HRESULT CDocObjectView::ContextSensitiveHelp(BOOL fEnterMode) { // NOTES: This is optional
return E_NOTIMPL; // As specified in Kraig's document (optional)
}
// IShellView::TranslateAccelerator
// From Browser -> DocView -> DocObject
HRESULT CDocObjectView::TranslateAccelerator(LPMSG lpmsg) { HRESULT hres = S_FALSE; if (_pdoh) hres = _pdoh->_xao.TranslateAccelerator(lpmsg);
if (hres == S_FALSE && lpmsg->message == WM_KEYDOWN) { HWND hwndFocus = GetFocus(); HWND hwndView = NULL;
if(_pdoh) //WARNING ZEKEL i found this NULL
_pdoh->GetWindow(&hwndView);
if (hwndView && IsChildOrSelf(hwndView, hwndFocus) == S_OK) {
switch (lpmsg->wParam) {
case VK_BACK: TranslateMessage(lpmsg); DispatchMessage(lpmsg); hres = NOERROR; break;
} } }
return hres; }
// IShellView::EnableModelessSV
// From Browser -> DocView -> DocObject
HRESULT CDocObjectView::EnableModelessSV(BOOL fEnable) { HRESULT hres = S_OK; // We have no modeless window to be enabled/disabled
TraceMsg(0, "sdv TR - ::EnableModelessSV(%d) called", fEnable); if (_pdoh) { hres = _pdoh->_xao.EnableModeless(fEnable); TraceMsg(0, "sdv TR - _piact->EnableModeless returned %x", hres); } return hres; }
HRESULT CDocObjectView::UIActivate(UINT uState) { HRESULT hres = E_FAIL;
if (_pdoh) { hres = _pdoh->UIActivate(uState, _fPrevViewIsDocView); }
_uState = uState; return hres; }
HRESULT CDocObjectView::Refresh() { if (_pdoh) { VARIANT v = {0}; v.vt = VT_I4; v.lVal = OLECMDIDF_REFRESH_NO_CACHE; // send this to exec so that it will update last refresh time.
// all refresh to dochost should go through our own exec
return Exec(NULL, OLECMDID_REFRESH, OLECMDEXECOPT_PROMPTUSER, &v, NULL); }
return S_OK; }
// Return:
// S_OK: It is a folder shortcut and ppidlTarget is filled out if provided.
// S_FALSE: It is not a folder shortcut and ppidlTarget is filled with NULL if provided.
// FAILED: An error occured trying to detect.
//
// Don't use this function if there is a better way. Look into using
// IBrowserFrameOptions. -BryanSt
HRESULT IsFolderShortcutPidl(IN LPCITEMIDLIST pidl) { IShellFolder * psf = NULL; HRESULT hr = IEBindToObject(pidl, &psf); if (SUCCEEDED(hr)) { IShellLinkA * psl;
hr = psf->QueryInterface(IID_PPV_ARG(IShellLinkA, &psl)); if (SUCCEEDED(hr)) { hr = S_OK; psl->Release(); } else hr = S_FALSE; // It's not a folder shortcut.
psf->Release(); }
return hr; }
// WARNING: This function explicitely creates URLMON monikers
// because that's what the caller needs. Some NSEs will
// support IShellFolder::BindToObject(IMoniker)
// but this function doesn't use that logic intentionally.
//
STDAPI _URLMONMonikerFromPidl(LPCITEMIDLIST pidl, IMoniker** ppmk, BOOL* pfFileProtocol) { TCHAR szPath[MAX_URL_STRING]; HRESULT hres = E_UNEXPECTED;
*ppmk = NULL; *pfFileProtocol = FALSE; MNKMSG(TEXT("_URLMONMonikerFromPidl"), TEXT("called"));
AssertMsg((S_OK != IsFolderShortcutPidl(pidl)), TEXT("We shouldn't get Folder Shortcuts here because we don't deref them to get the target. And we should never need to."));
// Is this a child of the "Internet Explorer" name space?
if (!IsURLChild(pidl, TRUE)) { // No, so we want to get the display name to use to
// create the moniker. We will try to turn it into
// an URL if it isn't already an URL.
// NOTE: We don't try IEBindToObject(pidl, IID_IMoniker)
// because the caller requires that this
// IMoniker come from URLMON.
HRESULT hrTemp = SHGetPathFromIDList(pidl, szPath);
AssertMsg(SUCCEEDED(hrTemp), TEXT("_URLMONMonikerFromPidl() failed SHGetPathFromIDList() which is really bad because we probably won't be able to create a moniker from it. We will try to create a URLMON moniker below.")); if (SUCCEEDED(hrTemp)) { // this should never be a fully qualified URL
DWORD cchPath = ARRAYSIZE(szPath);
ASSERT(URL_SCHEME_INVALID == GetUrlScheme(szPath)); if(SUCCEEDED(hres = UrlCreateFromPath(szPath, szPath, &cchPath, 0))) { MNKMSG(TEXT("_URLMONMonikerFromPidl Creating File Moniker"), szPath); }
*pfFileProtocol = TRUE; }
} else { // Yes so we are guaranteed this is from the "Internet Explorer"
// name space so remove Fragment hidden itemID.
// We do this because we navigate to the fragment later,
// after the page is downloaded. This is also needed
// for delegates of the IE name space. (FTP is one example of
// a delegate).
ASSERT(pidl); ASSERT(!ILIsEmpty(_ILNext(pidl))); // Make sure it's not the start page URL.
LPITEMIDLIST pidlClone = ILClone(pidl); if (pidlClone) { // we dont want to pass the fragment into URLMON
// so we pull it off before calling into GDN.
// Note that pidlClone needs to be the pidlTarget
// of folder shortcuts or the dislpay name will
// be the file system path of the folder shortcut
// if at the top level.
ILRemoveHiddenID(pidlClone, IDLHID_URLFRAGMENT); IEGetDisplayName(pidlClone, szPath, SHGDN_FORPARSING); hres = S_OK; ILFree(pidlClone); } }
if (SUCCEEDED(hres)) { if (szPath[0]) { hres = MonikerFromString(szPath, ppmk); } else { ASSERT(FALSE); hres = E_UNEXPECTED; } }
return hres; }
HRESULT CDocObjectView::HandleRename(LPCITEMIDLIST pidl) { return E_NOTIMPL; }
HRESULT CDocObjectView::CreateViewWindow(IShellView *psvPrev, LPCFOLDERSETTINGS lpfs, IShellBrowser * psb, RECT * prcView, HWND *phWnd) { SV2CVW2_PARAMS cParams;
cParams.cbSize = SIZEOF(SV2CVW2_PARAMS); cParams.psvPrev = psvPrev; cParams.pfs = lpfs; cParams.psbOwner = psb; cParams.prcView = prcView; cParams.pvid = NULL;
HRESULT hres = CreateViewWindow2(&cParams);
*phWnd = cParams.hwndView; IOleWindow *pOleWindow;
// need top level frame available for D&D
HRESULT hr = IUnknown_QueryService(_psb, SID_STopLevelBrowser, IID_PPV_ARG(IOleWindow, &pOleWindow)); if(SUCCEEDED(hr)) { ASSERT(pOleWindow); pOleWindow->GetWindow(&_hwndParent); pOleWindow->Release(); } return(hres); }
void CDocObjectView::_CompleteDocHostPassing(IShellView * psvPrev, HRESULT hresBinding) { BOOL fPassedSV = FALSE;
// If there was a previous shell view, see if it was our class.
//
if (psvPrev) { CDocObjectView * pdovPrev;
HRESULT hres = psvPrev->QueryInterface(CLSID_CDocObjectView, (void **)&pdovPrev); if (SUCCEEDED(hres)) { // Previous shell view is also an instance of CDocObjectView,
// Remember that for optimization later.
//
_fPrevViewIsDocView = TRUE;
// it was, and we have the same doc host as they do.
// we've succeeded in taking over, so null them out if we
// succeeeded in our bind. null ourselves out if we failed
//
if (pdovPrev->_pdoh == _pdoh) { if (SUCCEEDED(hresBinding)) { pdovPrev->_DisconnectHostSink(); // just in case
_ConnectHostSink(); // just in case
ATOMICRELEASET(pdovPrev->_pdoh, CDocObjectHost); } else { _DisconnectHostSink(); // unhook
pdovPrev->_ConnectHostSink(); // kick other guy
ATOMICRELEASET(_pdoh, CDocObjectHost); }
fPassedSV = TRUE; }
pdovPrev->Release(); } }
if (!fPassedSV) { if (FAILED(hresBinding)) { DestroyViewWindow(); } } }
BOOL CDocObjectView::_CanUseCache() { // NOTE: this function is more like _DontHaveToHitTheNet()
// the name is legacy from the objectcache.
if (!_fCanCacheFetched) { _fCanCache = TRUE; _fCanCacheFetched = TRUE; _fIsGet = TRUE;
IServiceProvider *psp; _psb->QueryInterface(IID_PPV_ARG(IServiceProvider, &psp)); if (psp) { IBindStatusCallback *pbsc; if (SUCCEEDED(GetTopLevelBindStatusCallback(psp, &pbsc))) { BINDINFO binfo; ZeroMemory(&binfo, sizeof(BINDINFO)); binfo.cbSize = sizeof(BINDINFO);
DWORD grfBINDF = BINDF_ASYNCHRONOUS;
HRESULT hr = pbsc->GetBindInfo(&grfBINDF, &binfo); if (SUCCEEDED(hr)) { if (grfBINDF & (BINDF_GETNEWESTVERSION | BINDF_RESYNCHRONIZE)) { _fCanCache = FALSE; }
_fIsGet = (binfo.dwBindVerb == BINDVERB_GET); ReleaseBindInfo(&binfo); }
pbsc->Release(); } // I believe that failing to get the Bindstatuscallback should
// not happen since we no longer use the object cache.
// and if it does, then we no that we didnt have to repost
// or something similar
psp->Release(); } }
return _fCanCache; }
void CDocObjectView::_ConnectHostSink() { if (_pdoh) { IAdviseSink *pSink;
if (FAILED(_pdoh->GetAdvise(NULL, NULL, &pSink))) pSink = NULL;
if (pSink != (IAdviseSink *)this) _pdoh->SetAdvise(DVASPECT_CONTENT, ADVF_PRIMEFIRST, this);
if (pSink) pSink->Release(); } }
void CDocObjectView::_DisconnectHostSink() { IAdviseSink *pSink;
// paranoia: only blow away the advise sink if it is still us
if (_pdoh && SUCCEEDED(_pdoh->GetAdvise(NULL, NULL, &pSink)) && pSink) { if (pSink == (IAdviseSink *)this) _pdoh->SetAdvise(0, 0, NULL);
pSink->Release(); }
OnViewChange(DVASPECT_CONTENT, -1); }
#if 0
BOOL _SameLocations(LPSTR pszLoc1, LPSTR pszLoc2) { // if they're both the same pointer (null)
// or if they both exist and have the same string, then
// they are the same location
if (pszLoc1 == pszLoc2 || (pszLoc1 && pszLoc2 && !lstrcmp(pszLoc1, pszLoc2))) { return TRUE; }
return FALSE; } #endif
//
// This function either (1) Create a new CDocObjectHost or (2) reuse it from
// the previous view. If also returns the DisplayName of previous moniker.
//
void CDocObjectView::_CreateDocObjHost(IShellView * psvPrev) { BOOL fWindowOpen = FALSE;
// if there was a previous shell view, see if it was our class.
if (psvPrev) { CDocObjectView * pdovPrev = NULL;
HRESULT hres = psvPrev->QueryInterface(CLSID_CDocObjectView, (void **)&pdovPrev);
if (SUCCEEDED(hres)) { CDocObjectHost * pPrevDOH = pdovPrev->_pdoh;
ASSERT(_psb); ASSERT(_psb == pdovPrev->_psb);
// find out if we should be saving the view state when we close
// if the one we're coming from says yes, then we'll take over that
// job instead of them.
//
_fSaveViewState = pdovPrev->_fSaveViewState; pdovPrev->_fSaveViewState = FALSE;
//
// if this is a local anchor navigation,
// we treat it substantially differently.
// we can reuse the DOH and the OLE Object that
// it holds. - zekel - 31-JUL-97
//
// WARNING: we should not reuse these objects for any other
// reason than a local anchor (fragment) navigation.
// we used to be a lot more lenient about reusing the DOH
// but i think this was mostly because of the old object cache.
//
// we check for equal pidls so that we know we are on
// the same URL. we require that _pszLocation be set.
// this is for Netscape compat. this means that anytime
// we get a navigate to ourself it will refresh completely
// if there was no fragment. we also check to make sure that
// the binding does not require us to hit the net for
// this request.
//
// 08-11-1999 (scotrobe): We now reuse the DOH if the
// hosted document has indicated that it knows how to
// navigate on its own.
//
if (_pidl && pdovPrev->_pidl && pPrevDOH && (pPrevDOH->_fDocCanNavigate || ( _pszLocation && IEILIsEqual(_pidl, pdovPrev->_pidl, TRUE) && _CanUseCache()))) { IBrowserService *pbs;
if (SUCCEEDED(_psb->QueryInterface(IID_PPV_ARG(IBrowserService, &pbs)))) { DWORD dwFlags = 0;
// If the document doesn't know how to navigate, then this may
// mean that this navigation was delegated from the document.
// In that case, if we have gotten this far, that means that
// _pszLocation is set. If it is and this is a delegated navigation
// (i.e., the navigation wasn't due to a link in a non-html document)
// we must create a new document.
//
if (!pPrevDOH->_fDocCanNavigate) { pbs->GetFlags(&dwFlags); }
if (!(dwFlags & BSF_DELEGATEDNAVIGATION)) { //
// if SetHistoryObject() fails, then that means there is already
// an object there for us to use. this means that we should
// not treat this as a local anchor navigation. and
// we shouldnt reuse the DOH even though the pidl is identical
//
// TRUE is passed to SetHistoryObject even if this is not a
// local anchor. In the case that this is not a local anchor,
// the document (Trident) handles the navigation. Therefore,
// the document will take care of updating the travel log and
// the fIsLocalAnchor flag is ignored.
//
if (SUCCEEDED(pbs->SetHistoryObject(pPrevDOH->_pole, !pPrevDOH->_fDocCanNavigate ? TRUE : FALSE))) { TraceMsg(TF_TRAVELLOG, "CDOV::CreateDocObjHost reusing current DOH on local anchor navigate"); //
// we cant update in ActivateNow because at that point
// we have already switched the dochost over to the new
// (reused) view. so we need to update the entry now
//
// The fact that the hosted document can navigate on its own,
// implies that it will take care of updating the travel log.
//
if (!pPrevDOH->_fDocCanNavigate) { ITravelLog * ptl;
pbs->GetTravelLog(&ptl); if (ptl) { ptl->UpdateEntry(pbs, TRUE); ptl->Release(); } }
pdovPrev->_DisconnectHostSink(); // we will connect below
// same target! pass the docobj host
_pdoh = pPrevDOH; _pdoh->AddRef();
if (_pdoh->_fDocCanNavigate) { _pdoh->OnInitialUpdate(); }
if ((_pdoh->_dwAppHack & BROWSERFLAG_SUPPORTTOP) && !_pszLocation) { // if there's no location for us to go to, and
// we're traversing in the same document,
// assume top.
//
_pszLocation = StrDup(TEXT("#top")); _uiCP = CP_ACP; } }
pbs->Release(); } } }
// In the case where we are opening a non-html mime type
// in a new window, we need to pass the _fWindowOpen
// flag from the previous docobject host to the new
// docobject host. This is needed so that if we are opening
// a file outside of IE in a new window, we'll know to close
// the newly created IE afterwards.
// The problem is that there isn't really a good place to
// clear this flag since it has to remain set from one
// instance of the docobject host to the next. This causes
// us to get into the situation where we'll close the browser
// window if we click on a link to a file that opens outside
// of IE after opening a new window for an html file.
// The bottom line is that we only need to pass this flag to
// the new docobject host if we opening an non-html mime type
// in a new window.
//
if (!_pdoh && pPrevDOH && pPrevDOH->_fDelegatedNavigation) { fWindowOpen = pPrevDOH->_fWindowOpen; }
//
// FEATURE: We should take care of _pibscNC as well
// to 'chain' the IBindStatusCallback.
//
pdovPrev->Release(); } }
// if we didn't pass the docobj host, create a new one and
// pass the doc context
if (!_pdoh) { ASSERT(_psb);
_pdoh = new CDocObjectHost(fWindowOpen);
// Reset host navigation flag in the browser
//
IUnknown_Exec(_psb, &CGID_DocHostCmdPriv, DOCHOST_DOCCANNAVIGATE, 0, NULL, NULL); }
if (_pdoh) { _ConnectHostSink(); } }
extern HRESULT TargetQueryService(IUnknown *punk, REFIID riid, void **ppvObj);
HRESULT CDocObjectView::CreateViewWindow2(LPSV2CVW2_PARAMS lpParams) { HRESULT hres = S_OK; IShellView * psvPrev = lpParams->psvPrev; LPCFOLDERSETTINGS lpfs = lpParams->pfs; IShellBrowser * psb = lpParams->psbOwner; RECT * prcView = lpParams->prcView; HWND UNALIGNED * phWnd = &lpParams->hwndView;
if (_pdoh || !_pidl) { *phWnd = NULL; ASSERT(0); return E_UNEXPECTED; }
_fs = *lpfs;
ASSERT(_psb==NULL);
_psb = psb; psb->AddRef();
ASSERT(_pctShellBrowser==NULL);
_psb->QueryInterface(IID_IOleCommandTarget, (void **)&_pctShellBrowser);
//if somebody that is not a ShellBrowser (like the FileOpenBrowser)
// tries to use us, we want to block them. we will fault later on
// if we dont have the right stuff.
if (!_pctShellBrowser) return E_UNEXPECTED;
// prime the cache bit. this needs to be done while we're *the* guy navigating.
// otherwise, if we ask later when there's a different pending navigation,
// we'll get his info
_CanUseCache(); _SetLastRefreshTime();
// Either create a new CDocObjectHost or reuse it from the previous view
// and set it in _pdoh.
_CreateDocObjHost(psvPrev);
if (!_pdoh || !_pdoh->InitHostWindow(this, psb, prcView)) { ATOMICRELEASE(_psb); _pctShellBrowser->Release(); _pctShellBrowser = NULL; return E_OUTOFMEMORY; }
_pdoh->GetWindow(phWnd);
ASSERT(NULL == _pdho);
_pdoh->QueryInterface(IID_IDocHostObject, (void **)&_pdho);
IMoniker* pmk = NULL; BOOL fFileProtocol; hres = ::_URLMONMonikerFromPidl(_pidl, &pmk, &fFileProtocol);
if (SUCCEEDED(hres) && EVAL(pmk)) { hres = _pdoh->SetTarget(pmk, _uiCP, _pszLocation, _pidl, psvPrev, fFileProtocol); _psvPrev = psvPrev;
if (_psvPrev) _psvPrev->AddRef();
#ifdef NON_NATIVE_FRAMES
_CompleteDocHostPassing(psvPrev, hres); #endif
pmk->Release(); }
return hres; }
void CDocObjectView::_GetViewSettings(IEVIEWINFO* pievi) { DWORD dwType, dwSize;
// REVIEW: Currently, we have on setting for all docobj class views
// (everything hosted by shdocvw). we may want to subclassify them by clsid
// of the docobj or maybe special case mshtml...
dwSize = sizeof(IEVIEWINFO); if (SHGetValueGoodBoot(HKEY_CURRENT_USER, TEXT("Software\\Microsoft\\Internet Explorer\\Main"), TEXT("ViewSettings"), &dwType, (PBYTE)pievi, &dwSize) == ERROR_SUCCESS) { if (pievi->cbSize != sizeof(IEVIEWINFO)) { goto DefaultInfo; }
} else { DefaultInfo:
// can't count on 0 init because registry could have read stuff, but
// of the wrong size (corruption)
pievi->fToolbar = FALSE; pievi->fCoolbar = TRUE; pievi->fStatusbar = TRUE; } }
void CDocObjectView::_SaveViewState() { IEVIEWINFO ievi; int id;
// First ask up if it is ok for us to save view state. If we get the return value of
// S_FALSE bail as we were told no.
if (_pctShellBrowser && (_pctShellBrowser->Exec(&CGID_Explorer, SBCMDID_MAYSAVEVIEWSTATE, 0, NULL, NULL) == S_FALSE)) return;
// first load to preserve things we're not going to set
_GetViewSettings(&ievi);
ievi.cbSize = sizeof(ievi);
id = _ShowControl(FCW_STATUS, SBSC_QUERY); // bail if it's not supported
if (id == -1) return; ievi.fStatusbar = (id == SBSC_SHOW);
id = _ShowControl(FCW_TOOLBAR, SBSC_QUERY); if (id != -1) { // this is allowed to fail if toolbar isn't supported (ie30 case)
ievi.fToolbar = (id == SBSC_SHOW); }
id = _ShowControl(FCW_INTERNETBAR, SBSC_QUERY); if (id != -1) { // this is allowed to fail if coolbar isn't supported
ievi.fCoolbar = (id == SBSC_SHOW); }
SHSetValue(HKEY_CURRENT_USER, TEXT("Software\\Microsoft\\Internet Explorer\\Main"), TEXT("ViewSettings"), REG_BINARY, (const BYTE *)&ievi, sizeof(ievi)); }
int CDocObjectView::_ShowControl(UINT idControl, int idCmd) { VARIANTARG var;
VariantInit(&var); var.vt = VT_I4; var.lVal = MAKELONG(idControl, idCmd);
if (_pctShellBrowser && SUCCEEDED(_pctShellBrowser->Exec(&CGID_Explorer, SBCMDID_SHOWCONTROL, OLECMDEXECOPT_DODEFAULT, &var, &var))) return var.lVal;
return -1; }
HRESULT CDocObjectView::DestroyViewWindow() { ATOMICRELEASE(_pdho);
if (_pdoh) { BOOL fDestroyHost = TRUE;
if (_psb && _pdoh->_pwb) { DWORD dwFlags;
_pdoh->_pwb->GetFlags(&dwFlags);
if (dwFlags & BSF_HTMLNAVCANCELED) { IShellView * psvCur;
HRESULT hr = _psb->QueryActiveShellView(&psvCur); if (S_OK == hr) { CDocObjectView * pdovCur;
hr = psvCur->QueryInterface(CLSID_CDocObjectView, (void**)&pdovCur); if (S_OK == hr) { ASSERT(this != pdovCur);
if (_pdoh == pdovCur->_pdoh) { fDestroyHost = FALSE; }
pdovCur->Release(); }
psvCur->Release(); } } }
if (fDestroyHost) { TraceMsg(DM_WARNING, "CDocObjectView::DestroyViewWindow(): Destroying Host Window");
_DisconnectHostSink();
if (_fSaveViewState) _SaveViewState();
_pdoh->DestroyHostWindow(); }
ATOMICRELEASET(_pdoh, CDocObjectHost); }
ATOMICRELEASE(_pctShellBrowser);
// Note that we should release _psb at the very end.
ATOMICRELEASE(_psb);
return S_OK; }
HRESULT CDocObjectView::GetCurrentInfo(LPFOLDERSETTINGS lpfs) { *lpfs = _fs; return S_OK; }
HRESULT CDocObjectView::AddPropertySheetPages(DWORD dwReserved, LPFNADDPROPSHEETPAGE lpfn, LPARAM lParam) { if (_pdoh) return _pdoh->AddPages(lpfn, lParam);
return E_FAIL; }
HRESULT CDocObjectView::SaveViewState() { // No viewsate to be saved
return S_OK; }
HRESULT CDocObjectView::SelectItem(LPCITEMIDLIST pidlItem, UINT uFlags) { // No item
return E_FAIL; }
//
// IShellView::GetItemObject
//
// For this IShellView object, the only valid uItem is SVGIO_BACKGROUND,
// which allows the browser to access an interface pointer to the
// currently active document object.
//
// Notes:
// The browser should be aware that IShellView::CreateViewWindow might be
// asynchronous. This method will fail with E_FAIL if the document is not
// instanciated yet.
//
HRESULT CDocObjectView::GetItemObject(UINT uItem, REFIID riid, void **ppv) { HRESULT hres = E_INVALIDARG; *ppv = NULL; // assumes error
switch(uItem) { case SVGIO_BACKGROUND: if (_pdoh) { if (_pdoh->_pole) { hres = _pdoh->_pole->QueryInterface(riid, ppv); break; } else if (_pdoh->_punkPending) { hres = _pdoh->_punkPending->QueryInterface(riid, ppv); break; } }
// fall through on the else's
default: hres = E_FAIL; break; } return hres; }
HRESULT CDocObjectView::DragEnter(IDataObject *pdtobj, DWORD grfKeyState, POINTL ptl, DWORD *pdwEffect) { _fSelfDragging = FALSE;
//
// Check if this is a self-dragging or not.
//
if (_pdoh && _pdoh->_pmsot) { VARIANT var = { 0 }; HRESULT hresT = _pdoh->_pmsot->Exec( &CGID_ShellDocView, SHDVID_ISDRAGSOURCE, 0, NULL, &var); if (SUCCEEDED(hresT) && var.vt==VT_I4 && var.lVal) { _fSelfDragging = TRUE; } VariantClearLazy(&var); }
ASSERT(pdtobj); _DragEnter(_hwndParent, ptl, pdtobj); _dwDragEffect = CommonDragEnter(pdtobj, grfKeyState, ptl);
return DragOver(grfKeyState, ptl, pdwEffect); }
HRESULT CDocObjectView::DragOver(DWORD grfKeyState, POINTL ptl, DWORD *pdwEffect) { *pdwEffect &= _dwDragEffect; _DragMove(_hwndParent, ptl); if (_fSelfDragging && _pdoh && _pdoh->_hwnd) { RECT rc; GetClientRect(_pdoh->_hwnd, &rc); POINT ptMap = { ptl.x, ptl.y }; MapWindowPoints(HWND_DESKTOP, _pdoh->_hwnd, &ptMap, 1); if (PtInRect(&rc, ptMap)) { *pdwEffect = DROPEFFECT_NONE; } }
return S_OK; }
HRESULT CDocObjectView::DragLeave(void) { DAD_DragLeave(); return S_OK; }
HRESULT CDocObjectView::Drop(IDataObject *pdtobj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) { LPITEMIDLIST pidlTarget; HRESULT hr = SHPidlFromDataObject(pdtobj, &pidlTarget, NULL, 0); if (SUCCEEDED(hr)) { ASSERT(pidlTarget); if((!ILIsWeb(pidlTarget) && _pdoh && SHIsRestricted2W(_pdoh->_hwnd, REST_NOFILEURL, NULL, 0)) || (_pdoh && !IEIsLinkSafe(_pdoh->_hwnd, pidlTarget, ILS_NAVIGATE))) { ILFree(pidlTarget); hr = E_ACCESSDENIED; } else { DWORD flags = GetKeyState(VK_CONTROL) < 0 ? (SBSP_NEWBROWSER | SBSP_ABSOLUTE) : (SBSP_SAMEBROWSER | SBSP_ABSOLUTE); hr = _psb->BrowseObject(pidlTarget, flags); HFRMMSG2(TEXT("::Drop _psb->BrowseObject returned"), hr, 0); ILFree(pidlTarget); } } if (SUCCEEDED(hr)) { *pdwEffect &= _dwDragEffect; }
DAD_DragLeave(); return hr; }
ULONG CDocObjectView::AddRef() { _cRef++; TraceMsg(TF_SHDREF, "CDocObjectView(%x)::AddRef called new _cRef=%d", this, _cRef); return _cRef; }
ULONG CDocObjectView::Release() { _cRef--; TraceMsg(TF_SHDREF, "CDocObjectView(%x)::Release called new _cRef=%d", this, _cRef);
if (_cRef > 0) return _cRef;
delete this; return 0; }
HRESULT CDocObjectView::GetView(SHELLVIEWID* pvid, ULONG uView) { return E_NOTIMPL; }
#ifdef DEBUG
#define _AddRef(psz) { ++_cRef; TraceMsg(TF_SHDREF, "CDocObjectView(%x)::QI(%s) is AddRefing _cRef=%d", this, psz, _cRef); }
#else
#define _AddRef(psz) ++_cRef
#endif
HRESULT CDocObjectView::QueryInterface(REFIID riid, void ** ppvObj) { HRESULT hres;
static const QITAB qit[] = { QITABENT(CDocObjectView, IShellView2), QITABENTMULTI(CDocObjectView, IShellView, IShellView2), QITABENTMULTI(CDocObjectView, IOleWindow, IShellView2), QITABENT(CDocObjectView, IDropTarget), QITABENT(CDocObjectView, IViewObject), QITABENT(CDocObjectView, IAdviseSink), QITABENT(CDocObjectView, IOleCommandTarget), QITABENT(CDocObjectView, IDocViewSite), QITABENT(CDocObjectView, IPrivateOleObject ), QITABENT(CDocObjectView, IPersistFolder), QITABENTMULTI(CDocObjectView, IPersist, IPersistFolder), QITABENT(CDocObjectView, IServiceProvider), { 0 }, };
hres = QISearch(this, qit, riid, ppvObj);
if (S_OK != hres) { if (IsEqualIID(riid, CLSID_CDocObjectView)) { *ppvObj = (void*)this; _AddRef(TEXT("CLSID_CDocObjectView")); return S_OK; } }
return hres; }
/// ***** IViewObject ******
HRESULT CDocObjectView::GetColorSet(DWORD dwAspect, LONG lindex, void *pvAspect, DVTARGETDEVICE *ptd, HDC hicTargetDev, LOGPALETTE **ppColorSet) { if (_pdoh) { return _pdoh->GetColorSet(dwAspect, lindex, pvAspect, ptd, hicTargetDev, ppColorSet); }
if (ppColorSet) *ppColorSet = NULL;
return S_FALSE; }
HRESULT CDocObjectView::Freeze(DWORD, LONG, void *, DWORD *pdwFreeze) { return E_NOTIMPL; }
HRESULT CDocObjectView::Unfreeze(DWORD) { return E_NOTIMPL; }
HRESULT CDocObjectView::SetAdvise(DWORD dwAspect, DWORD advf, IAdviseSink *pSink) { if (dwAspect != DVASPECT_CONTENT) return DV_E_DVASPECT;
if (advf & ~(ADVF_PRIMEFIRST | ADVF_ONLYONCE)) return E_INVALIDARG;
if (pSink != _padvise) { ATOMICRELEASE(_padvise);
_padvise = pSink;
if (_padvise) _padvise->AddRef(); }
if (_padvise) { _advise_aspect = dwAspect; _advise_advf = advf;
if (advf & ADVF_PRIMEFIRST) OnViewChange(dwAspect, -1); } else _advise_aspect = _advise_advf = 0;
return S_OK; }
HRESULT CDocObjectView::GetAdvise(DWORD *pdwAspect, DWORD *padvf, IAdviseSink **ppSink) { if (pdwAspect) *pdwAspect = _advise_aspect;
if (padvf) *padvf = _advise_advf;
if (ppSink) { if (_padvise) _padvise->AddRef();
*ppSink = _padvise; }
return S_OK; }
HRESULT CDocObjectView::Draw(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DVTARGETDEVICE *ptd, HDC hicTargetDev, HDC hdcDraw, const RECTL *lprcBounds, const RECTL *lprcWBounds, BOOL (*pfnContinue)(ULONG_PTR), ULONG_PTR dwContinue) { if (_pdoh) { return _pdoh->Draw(dwDrawAspect, lindex, pvAspect, ptd, hicTargetDev, hdcDraw, lprcBounds, lprcWBounds, pfnContinue, dwContinue); }
return OLE_E_BLANK; }
// IAdviseSink
void CDocObjectView::OnDataChange(FORMATETC *, STGMEDIUM *) { }
void CDocObjectView::OnViewChange(DWORD dwAspect, LONG lindex) { dwAspect &= _advise_aspect;
if (dwAspect && _padvise) { IAdviseSink *pSink = _padvise; IUnknown *punkRelease;
if (_advise_advf & ADVF_ONLYONCE) { punkRelease = pSink; _padvise = NULL; _advise_aspect = _advise_advf = 0; } else punkRelease = NULL;
pSink->OnViewChange(dwAspect, lindex);
if (punkRelease) punkRelease->Release(); } }
void CDocObjectView::OnRename(IMoniker *) { }
void CDocObjectView::OnSave() { }
void CDocObjectView::OnClose() { //
// the doc object host went away so tell anybody above what happened
//
OnViewChange(_advise_aspect, -1); }
HRESULT CDocObjectView::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD rgCmds[], OLECMDTEXT *pcmdtext) { HRESULT hres = OLECMDERR_E_UNKNOWNGROUP;
if (_pdho && _pdoh) hres = _pdho->QueryStatusDown(pguidCmdGroup, cCmds, rgCmds, pcmdtext);
return hres; }
HRESULT CDocObjectView::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANTARG *pvarargIn, VARIANTARG *pvarargOut) { HRESULT hres = OLECMDERR_E_UNKNOWNGROUP;
if (!pguidCmdGroup) { switch (nCmdID) { case OLECMDID_REFRESH: _SetLastRefreshTime(); break;
default: break; } } else if (IsEqualGUID(CGID_ShellDocView, *pguidCmdGroup)) { switch(nCmdID) { case SHDVID_UPDATEDOCHOSTSTATE: if (_pdoh) { DOCHOSTUPDATEDATA * pdhud;
ASSERT(pvarargIn && pvarargIn->vt == VT_PTR); pdhud = (DOCHOSTUPDATEDATA *) V_BYREF(pvarargIn); return _pdoh->_UpdateState(pdhud->_pidl, pdhud->_fIsErrorUrl); } return S_OK;
case SHDVID_COMPLETEDOCHOSTPASSING: _CompleteDocHostPassing(_psvPrev, S_OK); ATOMICRELEASE(_psvPrev);
return S_OK;
case SHDVID_NAVSTART: if (_pdoh) { _pdoh->_Init(); } return S_OK;
default: break; } }
// only forward on if we aren't 'stolen'.
// FEATURE ie4: clean this up to steal _pdho along w/ _pdoh.
if (_pdho && _pdoh) hres = _pdho->ExecDown(pguidCmdGroup, nCmdID, nCmdexecopt, pvarargIn, pvarargOut);
// REVIEW: if _pdoh->ExecDown fails && pguidCmdGroup==NULL && nCmdID is
// OLECMDID_STOP or OLECMDID_REFRESH, then we are lying
// by returning a failure error code.
return hres; }
HRESULT CDocObjectView::OnSetTitle(VARIANTARG *pvTitle) { return E_NOTIMPL; }
HRESULT CDocObjectView::SetExtent( DWORD dwDrawAspect, SIZEL *psizel) { if ( _pdoh && _pdoh->GetOleObject() ) { return _pdoh->GetOleObject()->SetExtent( dwDrawAspect, psizel ); }
return E_NOTIMPL; }
HRESULT CDocObjectView::GetExtent( DWORD dwDrawAspect, SIZEL *psizel) { if ( _pdoh && _pdoh->GetOleObject() ) { return _pdoh->GetOleObject()->GetExtent( dwDrawAspect, psizel ); }
return E_NOTIMPL; }
HRESULT CDocObjectView::GetClassID(CLSID *pclsid) { if (pclsid) { *pclsid = CLSID_CDocObjectView; return S_OK; } return E_INVALIDARG; }
HRESULT CDocObjectView::Initialize(LPCITEMIDLIST pidl) { HRESULT hres = E_OUTOFMEMORY;
LPITEMIDLIST pidlClone = ILClone(pidl); if (pidlClone) { IShellFolder* psf; if (SUCCEEDED(IEBindToObject(_pidl, &psf))) { ILFree(_pidl); ATOMICRELEASE(_psf);
_pidl = pidlClone; _psf = psf;
hres = S_OK; } else { ILFree(pidlClone); } }
return hres; }
HRESULT CDocObjectView::QueryService(REFGUID guidService, REFIID riid, void **ppvObj) { if( _pdoh && IsEqualGUID(guidService, IID_IElementNamespaceTable) ) { return _pdoh->QueryService( guidService, riid, ppvObj); } else return E_FAIL; }
|