1607 lines
46 KiB
C++
1607 lines
46 KiB
C++
#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;
|
|
}
|