Windows2000/private/shell/shdocvw/dochost.cpp.1475
2020-09-30 17:12:32 +02:00

9554 lines
297 KiB
Plaintext

//
// NOTES:
//
// This is the code which enables the explorer hosting (being a container)
// a DocObject (a super set of OLE in-place object). In a nut shell, this
// code creates an object (class CDocObjectHost) which can be plugged into
// the explorer's right pane (by supporting IShellView) is also a DocObject
// container (by supporting IOleClientSite, IOleInPlaceSite, ...).
//
// This CDocObjectHost directly supports following interfaces:
//
// Group 1 (to be plugged in):
// IShellView, IDropTarget
// Group 2 (to be a Doc site):
// IOleClientSite, IOleDocumentSite
// Group 3 (to be a View Site)
// IOleInPlaceSite
//
// It also supports following interfaces indirectly via contained object,
// CDocObjectFrame.
//
// IOleInPlaceFrame, IOleCommandTarget
//
// The reason we export them separately is because we may need to return
// a different hwnd for GetWindow method. The CDocObjectHost object always
// returns hwnd of the view window, but the CDocObjectFrame returns hwnd
// of the explorer in case the explorer support IOleInPlaceUIWindow.
//
// It also supports following interface indirectly via contained object,
// CProxyActiveObject.
//
// IOleInPlaceActiveObject
//
//
// --------------------------------------------------------
// Explorer (browser)
// --------------------------------------------------------
// ^ | |
// | | |
// ISB (+IOIUI) ISV IOIAO
// | | |
// | V |
// ----------------------------V---------------------------
// CDocObjectHost CProxyActiveObject CDocObjectFrame
// ----------------------------------------------^---------
// ^ | |
// | | |
// IOCS/IOIPS/IMDS IO/IOIPO/IMV/IMCT IOIUI/IOIF/IMCT
// | | |
// | V |
// --------------------------------------------------------
// DocObject (Doc + View)
// --------------------------------------------------------
//
#include "priv.h"
#include "dochost.h"
#include "ppages.h"
#include "helpids.h"
#include "bindcb.h"
#include "url.h"
#include "basesb.h"
extern "C" const IID IID_IHTMLWindow2;
#ifdef FEATURE_PICS
#include <ratings.h>
#endif
#define DM_ZONECROSSING 0
#define DM_SAVEASHACK DM_TRACE
#define DM_MIMEMAPPING 0
#define DM_SELFASC TF_SHDBINDING
#define DM_ACCEPTHEADER 0
#define DM_DEBUGTFRAME 0
#define DM_DOCHOSTUIHANDLER 0
// WARNING: Never define it in shipping product.
#ifdef DEBUG
// #define TEST_DELAYED_SHOWMSOVIEW
#endif
void CShdAdviseSink_Advise(IBrowserService* pwb, IOleObject* pole);
UINT MayOpenSafeOpenDialog(HWND hwndOwner, LPCTSTR pszFileClass, LPCTSTR pszURL);
int CmpSystemtime(SYSTEMTIME *pst1, SYSTEMTIME *pst2);
HRESULT MungeUrlForSearch(LPWSTR pwzOut, LPWSTR wzURL, LPSTR wzFormat);
HRESULT _SetSearchInfo (IServiceProvider *psp, DWORD dwIndex, BOOL fAllowSearch, BOOL fContinueSearch, BOOL fSentToEngine);
HRESULT _GetSearchInfo (IServiceProvider *psp, LPDWORD pdwIndex, LPBOOL pfAllowSearch, LPBOOL pfContinueSearch, LPBOOL pfSentToEngine);
LONG _GetSearchFormatString(DWORD dwIndex, LPSTR psz, DWORD cbpsz);
HRESULT GetSearchKeys (LPDWORD pdwSearchForExtensions, LPDWORD pdwDo404Search);
// macros
#define DO_SEARCH_ON_STATUSCODE(x) ((x == 0) || (x == HTTP_STATUS_NOT_FOUND) || (x == HTTP_STATUS_BAD_GATEWAY) || (x == HTTP_STATUS_GATEWAY_TIMEOUT))
#define SHOULD_DO_SEARCH(x,y) (y || (x && x != DONE_SUFFIXES))
// from shbrowse.cpp
BOOL IsRegistered(LPCTSTR pszReg);
#ifdef DEBUG
extern DWORD g_dwPerf;
#endif
// This is for determining if the user has been requested to connect to the net
BOOL g_bUserHasBeenPromptedToConnect = FALSE;
// chrisfra - added for ITargetFrame support
#include "htiface.h"
// #include "..\shell32\fstreex.h" // for IDFOLDER
// HACK:
struct IDFOLDERA
{
WORD cb;
BYTE bFlags;
};
typedef IDFOLDERA* LPIDFOLDERA;
const ITEMIDLIST s_idNull = { {0} };
//
// Icons are globally shared among multiple threads.
//
HICON g_hiconSSL = NULL;
HICON g_hiconOffline = NULL;
HICON g_ahiconState[IDI_STATE_LAST-IDI_STATE_FIRST+1] = { NULL };
//
//
//
#define SEARCHPREFIX L"? "
#define SEARCHPREFIXSIZE sizeof(SEARCHPREFIX)
#define SEARCHPREFIXLENGTH 2
// Registry values for automatically sending request to search engine
#define NEVERSEARCH 0
#define PROMPTSEARCH 1
#define ALWAYSSEARCH 2
// Values for automatically scanning common net suffixes
#define NO_SUFFIXES 0
#define SCAN_SUFFIXES 1
#define DONE_SUFFIXES 2
// OpenUIURL is just a wrapper for OpenUI, calling CreateURLMoniker() if the
// caller only has an URL.
extern HRESULT CDownLoad_OpenUIURL(LPCWSTR pwszURL, IBindCtx *pbc, LPWSTR pwzHeaders, BOOL fSync,BOOL fSaveAs=FALSE, BOOL fSafe=FALSE, DWORD dwVerb=BINDVERB_GET, DWORD grfBINDF=(BINDF_ASYNCHRONOUS | BINDF_PULLDATA), BINDINFO* pbinfo=NULL);
extern void CDownLoad_OpenUI(IMoniker* pmk, IBindCtx *pbc, BOOL fSync, BOOL fSaveAs=FALSE, BOOL fSafe=FALSE, LPWSTR pwzHeaders = NULL, DWORD dwVerb=BINDVERB_GET, DWORD grfBINDF = (BINDF_ASYNCHRONOUS | BINDF_PULLDATA), BINDINFO* pbinfo = NULL);
extern BOOL __cdecl _FormatMessage(LPCSTR szTemplate, LPSTR szBuf, UINT cchBuf, ...);
#ifdef FEATURE_PICS
#include "asyncrat.h"
#endif
#ifndef UNICODE
#define LPIDFOLDER LPIDFOLDERA
#endif
extern "C" const TCHAR c_szCLSID[];
#define MAX_STATUS_SIZE 128
//
// Set this flag if we are going to use IHlinkBrowseContext in HLINK.DLL
// #define HLINK_EXTRA
//
//
// GUID for very private interfaces
//
#define INITGUID
#include <initguid.h>
#include <htmlguid.h>
DEFINE_GUID(CLSID_CDocObjAssoc, 0xF44FE460L, 0x9CF9, 0x11CF, 0x99, 0xD3, 0x00, 0xAA, 0x00, 0x4A, 0xE8, 0x37);
DEFINE_GUID(IID_IMimeInfo, 0xF77459A0L, 0xBF9A, 0x11cf, 0xBA, 0x4E, 0x00, 0xC0, 0x4F, 0xD7, 0x08, 0x16);
// from dochost.h -- they need to be defined somewhere
DEFINE_GUID(IID_IDocHostObject, 0x67431840L, 0xC511, 0x11CF, 0x89, 0xA9, 0x00, 0xA0, 0xC9, 0x05, 0x41, 0x29);
DEFINE_GUID(IID_IDocViewSite, 0x87D605E0L, 0xC511, 0x11CF, 0x89, 0xA9, 0x00, 0xA0, 0xC9, 0x05, 0x41, 0x29);
#define DM_CACHETRACE 0
#define DM_BINDAPPHACK TF_SHDAPPHACK
#define DM_OBJCACHE 0
#define DM_ADVISE TF_SHDLIFE
#define DM_APPHACK DM_WARNING
#define NAVMSG3(psz, x, y) DebugMsg(0, TEXT("shdv NAV::%s %x %x"), psz, x, y)
#define PAINTMSG(psz,x) DebugMsg(0, TEXT("shd TR-PAINT::%s %x"), psz, x)
#define JMPMSG(psz, psz2) DebugMsg(0, TEXT("shd TR-CDOV::%s %s"), psz, psz2)
#define JMPMSG2(psz, x) DebugMsg(0, TEXT("shd TR-CDOV::%s %x"), psz, x)
#define DOFMSG(psz) DebugMsg(0, TEXT("shd TR-DOF::%s"), psz)
#define DOFMSG2(psz, x) DebugMsg(0, TEXT("shd TR-DOF::%s %x"), psz, x)
#define URLMSG(psz) DebugMsg(TF_SHDBINDING, TEXT("shd TR-DOF::%s"), psz)
#define URLMSG2(psz, x) DebugMsg(TF_SHDBINDING, TEXT("shd TR-DOF::%s %x"), psz, x)
#define URLMSG3(psz, x, y) DebugMsg(TF_SHDBINDING, TEXT("shd TR-DOF::%s %x %x"), psz, x, y)
#define BSCMSG(psz, i, j) DebugMsg(TF_SHDBINDING, TEXT("shd TR-BSC::%s %x %x"), psz, i, j)
#define BSCMSG3(psz, i, j, k) DebugMsg(0, TEXT("shd TR-BSC::%s %x %x %x"), psz, i, j, k)
#define BSCMSG4(psz, i, j, k, l) DebugMsg(0, TEXT("shd TR-BSC::%s %x %x %x %x"), psz, i, j, k, l)
#define BSCMSGS(psz, sz) DebugMsg(0, TEXT("shd TR-BSC::%s %s"), psz, sz)
#define OIPSMSG(psz) DebugMsg(0, TEXT("shd TR-OIPS::%s"), psz)
#define OIPSMSG3(psz, sz, p) DebugMsg(0, TEXT("shd TR-OIPS::%s %s,%x"), psz, sz,p)
#define VIEWMSG(psz) DebugMsg(0, TEXT("sdv TR CDOV::%s"), psz)
#define VIEWMSG2(psz,xx) DebugMsg(0, TEXT("sdv TR CDOV::%s %x"), psz,xx)
#define OPENMSG(psz) DebugMsg(TF_SHDBINDING, TEXT("shd OPENING %s"), psz)
#define OPENMSG2(psz, x) DebugMsg(TF_SHDBINDING, TEXT("shd OPENING %s %x"), psz, x)
#define HFRMMSG(psz) DebugMsg(0, TEXT("shd HFRM::%s"), psz)
#define HFRMMSG2(psz, x, y) DebugMsg(0, TEXT("shd HFRM::%s %x %x"), psz, x, y)
#define MNKMSG(psz, psz2) DebugMsg(0, TEXT("shd MNK::%s (%s)"), psz, psz2)
#define CHAINMSG(psz, x) DebugMsg(0, TEXT("shd CHAIN::%s %x"), psz, x)
#define SHVMSG(psz, x, y) DebugMsg(0, TEXT("shd SHV::%s %x %x"), psz, x, y)
#define HOMEMSG(psz, psz2, x) DebugMsg(TF_SHDNAVIGATE, TEXT("shd HOME::%s %s %x"), psz, psz2, x)
#define SAVEMSG(psz, x) DebugMsg(0, TEXT("shd SAVE::%s %x"), psz, x)
#define PERFMSG(psz, x) DebugMsg(TF_SHDPERF, TEXT("PERF::%s %d msec"), psz, x)
//Gets the current display name in wide char
HRESULT CDocObjectHost::_GetCurrentPageW(LPOLESTR * ppszDisplayName)
{
HRESULT hres = E_FAIL;
Assert(_pmkCur);
*ppszDisplayName = NULL;
if (_pmkCur) {
IBindCtx* pbc;
hres = CreateBindCtx(0, &pbc);
if (SUCCEEDED(hres))
{
hres = _pmkCur->GetDisplayName(pbc, NULL, ppszDisplayName);
pbc->Release();
}
}
return hres;
}
HRESULT CDocObjectHost::_GetCurrentPage(LPTSTR szBuf, UINT cchMax)
{
HRESULT hres = E_FAIL;
szBuf[0] = 0;
LPOLESTR pszDisplayName;
hres = _GetCurrentPageW(&pszDisplayName);
if (SUCCEEDED(hres))
{
#ifdef UNICODE
lstrcpyn(szBuf, pszDisplayName, cchMax);
#else
WideCharToMultiByte(CP_ACP, 0, pszDisplayName, -1,
szBuf, cchMax, NULL, NULL);
#endif
OleFree(pszDisplayName);
}
return hres;
}
void CDocObjectHost_GetCurrentPage(LPARAM that, LPTSTR szBuf, UINT cchMax)
{
CDocObjectHost* pdoh = (CDocObjectHost*)that;
pdoh->_GetCurrentPage(szBuf, cchMax);
}
inline void CDocObjectHost::CBindStatusCallback::_RegisterObjectParam(IBindCtx* pbc)
{
// pbc->RegisterObjectParam(L"BindStatusCallback", this);
HRESULT hres = RegisterBindStatusCallback(pbc, this, 0, 0);
BSCMSG3(TEXT("_RegisterObjectParam returned"), hres, this, pbc);
}
inline void CDocObjectHost::CBindStatusCallback::_RevokeObjectParam(IBindCtx* pbc)
{
// pbc->RevokeObjectParam(L"BindStatusCallback");
HRESULT hres = RevokeBindStatusCallback(pbc, this);
AssertMsg(SUCCEEDED(hres), TEXT("shd URLMON bug??? RevokeBindStatusCallback failed %x"), hres);
BSCMSG3(TEXT("_RevokeObjectParam returned"), hres, this, pbc);
}
//========================================================================
// CDocObjectHost members
//========================================================================
CDocObjectHost::CDocObjectHost() : _cRef(1), _uState(SVUIA_DEACTIVATE)
{
DllAddRef();
DebugMsg(TF_SHDLIFE, TEXT("ctor CDocObjectHost %x"), this);
DebugMsg(DM_DEBUGTFRAME, TEXT("ctor CDocObjectHost %x, %x"), this, &_bsc);
// Initialize proxy objects (which are contained)
_dof.Initialize(this);
_xao.Initialize(this);
#ifdef HLINK_EXTRA
HRESULT hres = HlinkCreateBrowseContext(NULL, IID_IHlinkBrowseContext, (LPVOID*)&_pihlbc);
DebugMsg(0, TEXT("sdv TR CDOV::constructor HlinkCreateBrowseContext returned %x"), hres);
#endif // HLINK_EXTRA
#ifdef FEATURE_PICS
_fPicsAccessAllowed = 1; /* assume no ratings checks unless we download */
_fbPicsWaitFlags = 0;
::_RefPicsQueries(); /* we'll free PICS async query list when last dochost is destroyed */
#endif
}
CDocObjectHost::~CDocObjectHost()
{
Assert(_pole==NULL); // to catch extra release.
Assert(_psp==NULL); // to cache extra release.
Assert(_hwnd==NULL);
Assert(_pmsoc==NULL);
Assert(_pmsot==NULL);
Assert(_pmsov==NULL);
if (_dt._pdtDoc) {
Assert(0);
ATOMICRELEASE(_dt._pdtDoc);
}
if (_dt._pdtFrame) {
Assert(0);
ATOMICRELEASE(_dt._pdtFrame);
}
#ifdef HLINK_EXTRA
Assert(_phls == NULL);
if (_pihlbc) {
ATOMICRELEASE(_pihlbc);
}
#endif // HLINK_EXTRA
#ifdef FEATURE_PICS
if (_pRatingDetails) {
::RatingFreeDetails(_pRatingDetails);
_pRatingDetails = NULL;
}
if (_dwPicsSerialNumber) {
::_RemovePicsQuery(_dwPicsSerialNumber);
_dwPicsSerialNumber = 0;
}
::_ReleasePicsQueries();
#endif
Assert(_pObjCache==NULL);
if (_pcmSendTo)
{
DebugMsg(DM_WARNING, TEXT("DOH::~DOH Releasing _pcmSendTo (BUG in DocObject?)"));
ATOMICRELEASE(_pcmSendTo);
}
if (_padvise) {
_padvise->OnClose();
ATOMICRELEASE(_padvise);
}
if (_hmenuBrowser) {
Assert(0);
DestroyMenu(_hmenuBrowser);
}
if (_hmenuTemplate) {
DestroyMenu(_hmenuTemplate);
}
// Make it sure that View Window is released (and _psb)
DestroyHostWindow(); // which will call _CloseMsoView and _UnBind
_ResetOwners();
DebugMsg(TF_SHDLIFE, TEXT("dtor CDocObjectHost %x"), this);
DllRelease();
}
#ifdef DEBUG
/*----------------------------------------------------------
Purpose: Dump the menu handles for this docobj. Optionally
breaks after dumping handles.
Returns:
Cond: --
*/
void
CDocObjectHost::_DumpMenus(
IN LPCTSTR pszMsg,
IN BOOL bBreak)
{
if (IsFlagSet(g_dwDumpFlags, DF_DEBUGMENU))
{
ASSERT(pszMsg);
TraceMsg(TF_ALWAYS, "Dumping menus for %#08x %s", (LPVOID)this, pszMsg);
TraceMsg(TF_ALWAYS, " _hmenuBrowser = %x, _hmenuSet = %x, _hmenuTemplate = %x",
_hmenuBrowser, _hmenuSet, _hmenuTemplate);
TraceMsg(TF_ALWAYS, " _hmenuCur = %x, _hmenuMergedHelp = %x",
_hmenuCur, _hmenuMergedHelp);
if (bBreak && IsFlagSet(g_dwBreakFlags, BF_ONDUMPMENU))
DebugBreak();
}
}
#endif
#ifdef DEBUG
class CDocObjectHostQIStub :
public IOleCommandTarget
,public IServiceProvider
,public IOleClientSite
,public IOleDocumentSite
,public IOleInPlaceSite
,public IDocHostObject
,public IViewObject
,public IAdviseSink
,public IDispatch
,public IPropertyNotifySink
,public IDocHostUIHandler
,public IOleControlSite
{
virtual STDMETHODIMP QueryInterface(REFIID riid, LPVOID * ppvObj) {
return _preal->QueryInterface(riid, ppvObj);
}
virtual STDMETHODIMP_(ULONG) AddRef(void) {
_cRef++;
return _cRef;
}
virtual STDMETHODIMP_(ULONG) Release(void) {
_cRef--;
if (_cRef>0) {
return _cRef;
}
delete this;
return 0;
}
// *** IOleWindow methods ***
virtual STDMETHODIMP GetWindow(HWND * lphwnd) {
return _preal->GetWindow(lphwnd);
}
virtual STDMETHODIMP ContextSensitiveHelp(BOOL fEnterMode) {
return _preal->ContextSensitiveHelp(fEnterMode);
}
// *** IServiceProvider methods ***
virtual STDMETHODIMP QueryService(REFGUID guidService, REFIID riid, LPVOID* ppvObj)
{ return _preal->QueryService(guidService, riid, ppvObj); }
// IOleCommandTarget
virtual STDMETHODIMP QueryStatus(const GUID *pguid,
ULONG cCmds, MSOCMD rgCmds[], MSOCMDTEXT *pcmdtext)
{ return _preal->QueryStatus(pguid, cCmds, rgCmds, pcmdtext); }
virtual STDMETHODIMP Exec(const GUID *pguid,
DWORD nCmdID, DWORD nCmdexecopt, VARIANTARG *pvarargIn, VARIANTARG *pvarargOut)
{ return _preal->Exec(pguid, nCmdID, nCmdexecopt, pvarargIn, pvarargOut); }
// IOleClientSite
virtual HRESULT STDMETHODCALLTYPE SaveObject(void) {
return _preal->SaveObject();
}
virtual HRESULT STDMETHODCALLTYPE GetMoniker(DWORD dw, DWORD dw2, IMoniker **ppmk) {
return _preal->GetMoniker(dw, dw2, ppmk);
}
virtual HRESULT STDMETHODCALLTYPE GetContainer(IOleContainer **ppc) {
return _preal->GetContainer(ppc);
}
virtual HRESULT STDMETHODCALLTYPE ShowObject(void) {
return _preal->ShowObject();
}
virtual HRESULT STDMETHODCALLTYPE OnShowWindow(BOOL fShow) {
return _preal->OnShowWindow(fShow);
}
virtual HRESULT STDMETHODCALLTYPE RequestNewObjectLayout(void) {
return _preal->RequestNewObjectLayout();
}
// IOleInPlaceSite (also IOleWindow)
virtual STDMETHODIMP CanInPlaceActivate( void) { return _preal->CanInPlaceActivate(); }
virtual STDMETHODIMP OnInPlaceActivate( void) { return _preal->OnInPlaceActivate(); }
virtual STDMETHODIMP OnUIActivate( void) { return _preal->OnUIActivate(); }
virtual STDMETHODIMP GetWindowContext(
IOleInPlaceFrame **ppFrame, IOleInPlaceUIWindow **ppDoc,
LPRECT lprcPosRect, LPRECT lprcClipRect, LPOLEINPLACEFRAMEINFO lpFrameInfo) {
return _preal->GetWindowContext(ppFrame, ppDoc,
lprcPosRect, lprcClipRect, lpFrameInfo);
}
virtual STDMETHODIMP Scroll(SIZE scrollExtant) {
return _preal->Scroll(scrollExtant);
}
virtual STDMETHODIMP OnUIDeactivate(BOOL fUndoable) {
return _preal->OnUIDeactivate(fUndoable);
}
virtual STDMETHODIMP OnInPlaceDeactivate( void) {
return _preal->OnInPlaceDeactivate();
}
virtual STDMETHODIMP DiscardUndoState( void) {
return _preal->DiscardUndoState();
}
virtual STDMETHODIMP DeactivateAndUndo( void) {
return _preal->DeactivateAndUndo();
}
virtual STDMETHODIMP OnPosRectChange(LPCRECT lprcPosRect) {
return _preal->OnPosRectChange(lprcPosRect);
}
// IOleDocumentSite
virtual STDMETHODIMP ActivateMe(IOleDocumentView *pviewToActivate) {
return _preal->ActivateMe(pviewToActivate);
}
// IDocHostUIHandler
virtual HRESULT STDMETHODCALLTYPE ShowContextMenu(
DWORD dwID, POINT *ppt, IUnknown *pcmdtReserved, IDispatch *pdispReserved) {
return _preal->ShowContextMenu(dwID, ppt, pcmdtReserved, pdispReserved);
}
virtual HRESULT STDMETHODCALLTYPE GetHostInfo(DOCHOSTUIINFO *pInfo) {
return _preal->GetHostInfo(pInfo);
}
virtual HRESULT STDMETHODCALLTYPE ShowUI(
DWORD dwID, IOleInPlaceActiveObject *pActiveObject,
IOleCommandTarget *pCommandTarget, IOleInPlaceFrame *pFrame,
IOleInPlaceUIWindow *pDoc) {
return _preal->ShowUI(dwID, pActiveObject, pCommandTarget, pFrame, pDoc);
}
virtual HRESULT STDMETHODCALLTYPE HideUI(void) {
return _preal->HideUI();
}
virtual HRESULT STDMETHODCALLTYPE UpdateUI(void) {
return _preal->UpdateUI();
}
virtual HRESULT STDMETHODCALLTYPE EnableModeless(BOOL fEnable) {
return _preal->EnableModeless(fEnable);
}
virtual HRESULT STDMETHODCALLTYPE OnDocWindowActivate(BOOL fActivate) {
return _preal->OnDocWindowActivate(fActivate);
}
virtual HRESULT STDMETHODCALLTYPE OnFrameWindowActivate(BOOL fActivate) {
return _preal->OnFrameWindowActivate(fActivate);
}
virtual HRESULT STDMETHODCALLTYPE ResizeBorder(
LPCRECT prcBorder, IOleInPlaceUIWindow *pUIWindow, BOOL fRameWindow) {
return _preal->ResizeBorder(prcBorder, pUIWindow, fRameWindow);
}
virtual HRESULT STDMETHODCALLTYPE TranslateAccelerator(
LPMSG lpMsg, const GUID *pguidCmdGroup, DWORD nCmdID) {
return _preal->TranslateAccelerator(lpMsg, pguidCmdGroup, nCmdID);
}
virtual HRESULT STDMETHODCALLTYPE GetOptionKeyPath(BSTR *pbstrKey) {
return _preal->GetOptionKeyPath(pbstrKey);
}
virtual HRESULT STDMETHODCALLTYPE GetDropTarget(
IDropTarget *pDropTarget, IDropTarget **ppDropTarget) {
return _preal->GetDropTarget(pDropTarget, ppDropTarget);
}
// *** IDocHostObject methods ***
virtual STDMETHODIMP OnQueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD rgCmds[], OLECMDTEXT *pcmdtext, HRESULT hres) {
return _preal->OnQueryStatus(pguidCmdGroup, cCmds, rgCmds, pcmdtext, hres);
}
virtual STDMETHODIMP OnExec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANTARG *pvarargIn, VARIANTARG *pvarargOut) {
return _preal->OnExec(pguidCmdGroup, nCmdID, nCmdexecopt, pvarargIn, pvarargOut);
}
virtual STDMETHODIMP QueryStatusDown(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD rgCmds[], OLECMDTEXT *pcmdtext) {
return _preal->QueryStatusDown(pguidCmdGroup, cCmds, rgCmds, pcmdtext);
}
virtual STDMETHODIMP ExecDown(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANTARG *pvarargIn, VARIANTARG *pvarargOut) {
return _preal->ExecDown(pguidCmdGroup, nCmdID, nCmdexecopt, pvarargIn, pvarargOut);
}
// IViewObject
virtual STDMETHODIMP Draw(DWORD p1, LONG p2, void *p3,
DVTARGETDEVICE * p4, HDC p5, HDC p6,
const RECTL *p7, const RECTL *p8, BOOL (*p9)(DWORD), DWORD p10) {
return _preal->Draw(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10);
}
virtual STDMETHODIMP GetColorSet(DWORD p1, LONG p2, void *p3, DVTARGETDEVICE *p4,
HDC p5, LOGPALETTE **p6) {
return _preal->GetColorSet(p1, p2, p3, p4, p5, p6);
}
virtual STDMETHODIMP Freeze(DWORD p1, LONG p2, void *p3, DWORD *p4) {
return _preal->Freeze(p1, p2, p3, p4);
}
virtual STDMETHODIMP Unfreeze(DWORD p1) {
return _preal->Unfreeze(p1);
}
virtual STDMETHODIMP SetAdvise(DWORD p1, DWORD p2, IAdviseSink *p3) {
return _preal->SetAdvise(p1, p2, p3);
}
virtual STDMETHODIMP GetAdvise(DWORD *p1, DWORD *p2, IAdviseSink **p3) {
return _preal->GetAdvise(p1, p2, p3);
}
// IAdviseSink
virtual STDMETHODIMP_(void) OnDataChange(FORMATETC *a1, STGMEDIUM *a2) {
_preal->OnDataChange(a1, a2);
}
virtual STDMETHODIMP_(void) OnViewChange(DWORD dwAspect, LONG lindex) {
_preal->OnViewChange(dwAspect, lindex);
}
virtual STDMETHODIMP_(void) OnRename(IMoniker *pmk) {
_preal->OnRename(pmk);
}
virtual STDMETHODIMP_(void) OnSave() {
_preal->OnSave();
}
virtual STDMETHODIMP_(void) OnClose() {
_preal->OnClose();
}
// IDispatch
virtual STDMETHODIMP GetTypeInfoCount(unsigned int *pctinfo)
{ return _preal->GetTypeInfoCount(pctinfo); }
virtual STDMETHODIMP GetTypeInfo(unsigned int itinfo, LCID lcid, ITypeInfo **pptinfo)
{ return _preal->GetTypeInfo(itinfo, lcid, pptinfo); }
virtual STDMETHODIMP GetIDsOfNames(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid)
{ return _preal->GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid); }
virtual STDMETHODIMP Invoke(DISPID dispidMember, REFIID iid, LCID lcid, WORD wFlags, DISPPARAMS FAR* pdispparams,
VARIANT FAR* pvarResult,EXCEPINFO FAR* pexcepinfo,UINT FAR* puArgErr)
{ return _preal->Invoke(dispidMember, iid, lcid, wFlags, pdispparams, pvarResult,pexcepinfo,puArgErr); }
// IPropertyNotifySink
virtual STDMETHODIMP OnChanged(DISPID dispid)
{ return _preal->OnChanged(dispid); }
virtual STDMETHODIMP OnRequestEdit(DISPID dispid)
{ return _preal->OnRequestEdit(dispid); }
// IOleControlSite
virtual HRESULT STDMETHODCALLTYPE OnControlInfoChanged()
{ return _preal->OnControlInfoChanged(); }
virtual HRESULT STDMETHODCALLTYPE LockInPlaceActive(BOOL fLock)
{ return _preal->LockInPlaceActive(fLock); }
virtual HRESULT STDMETHODCALLTYPE GetExtendedControl(IDispatch __RPC_FAR *__RPC_FAR *ppDisp)
{ return _preal->GetExtendedControl(ppDisp); }
virtual HRESULT STDMETHODCALLTYPE TransformCoords(POINTL __RPC_FAR *pPtlHimetric, POINTF __RPC_FAR *pPtfContainer,DWORD dwFlags)
{ return _preal->TransformCoords(pPtlHimetric, pPtfContainer,dwFlags); }
virtual HRESULT STDMETHODCALLTYPE TranslateAccelerator(MSG __RPC_FAR *pMsg,DWORD grfModifiers)
{ return _preal->TranslateAccelerator(pMsg,grfModifiers); }
virtual HRESULT STDMETHODCALLTYPE OnFocus(BOOL fGotFocus)
{ return _preal->OnFocus(fGotFocus); }
virtual HRESULT STDMETHODCALLTYPE ShowPropertyFrame(void)
{ return _preal->ShowPropertyFrame(); }
public:
CDocObjectHostQIStub(CDocObjectHost* preal, REFIID riid)
: _preal(preal), _cRef(1), _riid(riid) {}
~CDocObjectHostQIStub() { _preal->Release(); }
protected:
CDocObjectHost* _preal;
UINT _cRef;
REFIID _riid;
};
#endif
HRESULT CDocObjectHost::QueryInterface(REFIID riid, LPVOID * ppvObj)
{
if (IsEqualIID(riid, IID_IOleInPlaceSite) ||
IsEqualIID(riid, IID_IOleWindow) ||
IsEqualIID(riid, IID_IUnknown))
{
*ppvObj = SAFECAST(this, IOleInPlaceSite*);
#ifdef DEBUG
if (IsFlagSet(g_dwDumpFlags, DF_DEBUGQI) && !IsEqualIID(riid, IID_IUnknown)) {
CDocObjectHostQIStub* qistub = new CDocObjectHostQIStub(this, riid);
*ppvObj = SAFECAST(qistub, IOleInPlaceSite*);
}
#endif
}
else if (IsEqualIID(riid, IID_IOleClientSite))
{
*ppvObj = SAFECAST(this, IOleClientSite*);
#ifdef DEBUG
if (IsFlagSet(g_dwDumpFlags, DF_DEBUGQI)) {
CDocObjectHostQIStub* qistub = new CDocObjectHostQIStub(this, riid);
*ppvObj = SAFECAST(qistub, IOleClientSite*);
}
#endif
}
else if (IsEqualIID(riid, IID_IOleDocumentSite))
{
*ppvObj = SAFECAST(this, IOleDocumentSite*);
#ifdef DEBUG
if (IsFlagSet(g_dwDumpFlags, DF_DEBUGQI)) {
CDocObjectHostQIStub* qistub = new CDocObjectHostQIStub(this, riid);
*ppvObj = SAFECAST(qistub, IOleDocumentSite*);
}
#endif
}
else if (IsEqualIID(riid, IID_IOleCommandTarget))
{
*ppvObj = SAFECAST(this, IOleCommandTarget*);
#ifdef DEBUG
if (IsFlagSet(g_dwDumpFlags, DF_DEBUGQI)) {
CDocObjectHostQIStub* qistub = new CDocObjectHostQIStub(this, riid);
*ppvObj = SAFECAST(qistub, IOleCommandTarget*);
}
#endif
}
else if (IsEqualIID(riid, IID_IServiceProvider))
{
*ppvObj = SAFECAST(this, IServiceProvider*);
#ifdef DEBUG
if (IsFlagSet(g_dwDumpFlags, DF_DEBUGQI)) {
CDocObjectHostQIStub* qistub = new CDocObjectHostQIStub(this, riid);
*ppvObj = SAFECAST(qistub, IServiceProvider*);
}
#endif
}
else if (IsEqualIID(riid, IID_IViewObject))
{
*ppvObj = SAFECAST(this, IViewObject*);
#ifdef DEBUG
if (IsFlagSet(g_dwDumpFlags, DF_DEBUGQI)) {
CDocObjectHostQIStub* qistub = new CDocObjectHostQIStub(this, riid);
*ppvObj = SAFECAST(qistub, IViewObject*);
}
#endif
}
else if (IsEqualIID(riid, IID_IAdviseSink))
{
*ppvObj = SAFECAST(this, IAdviseSink*);
#ifdef DEBUG
if (IsFlagSet(g_dwDumpFlags, DF_DEBUGQI)) {
CDocObjectHostQIStub* qistub = new CDocObjectHostQIStub(this, riid);
*ppvObj = SAFECAST(qistub, IAdviseSink*);
}
#endif
}
else if (IsEqualIID(riid, IID_IDocHostObject))
{
*ppvObj = SAFECAST(this, IDocHostObject*);
#ifdef DEBUG
if (IsFlagSet(g_dwDumpFlags, DF_DEBUGQI)) {
CDocObjectHostQIStub* qistub = new CDocObjectHostQIStub(this, riid);
*ppvObj = SAFECAST(qistub, IDocHostObject*);
}
#endif
}
else if (IsEqualIID(riid, IID_IDocHostUIHandler))
{
*ppvObj = SAFECAST(this, IDocHostUIHandler*);
#ifdef DEBUG
if (IsFlagSet(g_dwDumpFlags, DF_DEBUGQI)) {
*ppvObj = (IDocHostUIHandler*)new CDocObjectHostQIStub(this, riid);
}
#endif
}
else if(IsEqualIID(riid, IID_IDispatch))
{
*ppvObj = SAFECAST(this, IDispatch*);
#ifdef DEBUG
if (IsFlagSet(g_dwDumpFlags, DF_DEBUGQI)) {
CDocObjectHostQIStub* qistub = new CDocObjectHostQIStub(this, riid);
*ppvObj = SAFECAST(qistub, IDispatch*);
}
#endif
}
else if(IsEqualIID(riid, IID_IPropertyNotifySink))
{
*ppvObj = SAFECAST(this, IPropertyNotifySink*);
#ifdef DEBUG
if (IsFlagSet(g_dwDumpFlags, DF_DEBUGQI)) {
CDocObjectHostQIStub* qistub = new CDocObjectHostQIStub(this, riid);
*ppvObj = SAFECAST(qistub, IPropertyNotifySink*);
}
#endif
}
else if(IsEqualIID(riid, IID_IOleControlSite))
{
*ppvObj = SAFECAST(this, IOleControlSite*);
#ifdef DEBUG
if (IsFlagSet(g_dwDumpFlags, DF_DEBUGQI)) {
CDocObjectHostQIStub* qistub = new CDocObjectHostQIStub(this, riid);
*ppvObj = SAFECAST(qistub, IOleControlSite*);
}
#endif
}
else
{
*ppvObj = NULL;
return E_NOINTERFACE;
}
AddRef();
return NOERROR;
}
void CDocObjectHost::_ResetOwners()
{
_pszLocation = NULL;
if (_psv) {
ATOMICRELEASE(_psv);
}
if (_pmsoctView) {
ATOMICRELEASE(_pmsoctView);
}
if (_pdvs)
{
ATOMICRELEASE(_pdvs);
}
if (_psb) {
ATOMICRELEASE(_psb);
}
if (_pwb) {
ATOMICRELEASE(_pwb);
}
if (_phf) {
ATOMICRELEASE(_phf);
}
if (_pmsoctBrowser) {
ATOMICRELEASE(_pmsoctBrowser);
}
if (_psp) {
ATOMICRELEASE(_psp);
}
if (_peds) {
ATOMICRELEASE(_peds);
}
if (_pedsHelper) {
ATOMICRELEASE(_pedsHelper);
}
// Release cached OleInPlaceUIWindow of the browser
if (_pipu) {
ATOMICRELEASE(_pipu);
}
if (_pObjCache) {
ATOMICRELEASE(_pObjCache);
}
}
ULONG CDocObjectHost::AddRef()
{
_cRef++;
DebugMsg(TF_SHDREF, TEXT("CDocObjectHost(%x)::AddRef called, new _cRef=%d"), this, _cRef);
return _cRef;
}
ULONG CDocObjectHost::Release()
{
_cRef--;
DebugMsg(TF_SHDREF, TEXT("CDocObjectHost(%x)::Release called, new _cRef=%d"), this, _cRef);
if (_cRef > 0)
return _cRef;
delete this;
return 0;
}
HRESULT CDocObjectHost::UIActivate(UINT uState, BOOL fPrevViewIsDocView)
{
DebugMsg(TF_SHDUIACTIVATE, TEXT("DOH::UIActivate called %d->%d (this=%x)"),
_uState, uState, this);
HRESULT hres = S_OK;
// We are supposed to update the menu
if (uState != _uState)
{
UINT uStatePrev = _uState;
_uState = uState;
if (_uState == SVUIA_DEACTIVATE)
{
//
// When we are deactivating (we are navigating away)
// we UIDeactivate the current MsoView.
//
_UIDeactivateMsoView();
_IPDeactivateMsoView(_pmsov);
_DestroyBrowserMenu();
}
else if (_uState == SVUIA_INPLACEACTIVATE && uStatePrev == SVUIA_ACTIVATE_FOCUS)
{
//
// BUGBUG: If we set this DONT_UIDEACTIVATE, then we stop calling
// UIActivate(FALSE) when a DocObject in a frameset looses a focus.
// It will solve some problems with Office apps (Excel, PPT), which
// InPlaceDeactivate when we call UIActivate(FALSE). We want to treat
// it as a bug, but unfortunately DocObject spec says that's OK.
//
// Putting this work around, however, slightly confuses MSHTML
// (both classic and Trident). Once it's UIActivated, it keep
// thinking that it's UIActivated and never calls onUIActivate.
// Until we figure out what's the right implementation,
// we can't turn this on. (SatoNa -- 11/04/96).
//
_GetAppHack(); // get if we don't have it yet.
if (_dwAppHack & BROWSERFLAG_DONTUIDEACTIVATE) {
//
// HACK: We are supposed to just call UIActivate(FALSE) when
// another DocObject (in the case of a frame set) became
// UIActivated. Excel/PPT, however, InplaceDeactivate instead.
// To work around, SriniK suggested us to call
// OnDocWindowActivate(FALSE). (SatoNa)
//
IOleInPlaceActiveObject* piact = _xao.GetObject(); // no AddRef
DebugMsg(TF_SHDAPPHACK, TEXT("DOH::UIActivate APPHACK calling %x->OnDocWindowActivate (this=%x)"),
piact, this);
if (piact) {
piact->OnDocWindowActivate(FALSE);
}
} else {
_UIDeactivateMsoView();
}
}
else if (uStatePrev == SVUIA_DEACTIVATE)
{
//
// If UIActivate is called either
// (1) when the binding is pending; _bsc._pbc!=NULL
// (2) when the async binding is done; _bsc._pole!=NULL
//
SHVMSG("UIActivate about to call _Bind", _bsc._pbc, NULL);
if (_pole == NULL && _bsc._pbc)
{
Assert(_pmkCur);
IBindCtx* pbc = _bsc._pbc;
pbc->AddRef();
HRESULT hresT = _BindSync(_pmkCur, _bsc._pbc, _bsc._psvPrev);
pbc->Release();
Assert(_bsc._pbc==NULL);
Assert(_bsc._psvPrev==NULL);
Assert(_bsc._pbscChained==NULL);
}
hres = _EnsureActivateMsoView();
//
// Tell the toolbar to add standard browser buttons, only if
// the previous shell view is NOT an instance of CShellDocView.
//
if (!fPrevViewIsDocView && _psp) {
IExplorerToolbar* pxtb;
HRESULT hresT = _psp->QueryService(SID_SExplorerToolbar, IID_IExplorerToolbar, (LPVOID*)&pxtb);
if (SUCCEEDED(hresT)) {
pxtb->SetCommandTarget((IUnknown*)_psp, &CLSID_NULL, VBF_TOOLS | VBF_ADDRESS | VBF_LINKS | VBF_BRAND | VBF_ONELINETEXT);
pxtb->AddStdBrowserButtons();
pxtb->Release();
}
}
}
}
else
{
DebugMsg(0, TEXT("sdv TR : UIActivate -- same uState (%x)"), _uState);
if ((_uState == SVUIA_ACTIVATE_FOCUS) && _ActiveHwnd()) {
SetFocus(_ActiveHwnd());
}
}
return hres;
}
class CDocObjAssoc : public IUnknown
{
public:
// *** IUnknown methods ***
virtual STDMETHODIMP QueryInterface(REFIID riid, LPVOID * ppvObj);
virtual STDMETHODIMP_(ULONG) AddRef(void) ;
virtual STDMETHODIMP_(ULONG) Release(void);
CDocObjAssoc(DWORD dwDOCHF) : _dwDOCHF(dwDOCHF), _cRef(1) {
DebugMsg(TF_SHDLIFE, "CDocObjAssoc(%x) being constructed", this);
}
DWORD GetDOCHF(void) { return _dwDOCHF; }
protected:
~CDocObjAssoc() {
DebugMsg(TF_SHDLIFE, "CDocObjAssoc(%x) being destroyed", this);
}
UINT _cRef;
DWORD _dwDOCHF;
};
HRESULT CDocObjAssoc::QueryInterface(REFIID riid, LPVOID * ppvObj)
{
if (IsEqualIID(riid, IID_IUnknown))
{
*ppvObj = SAFECAST(this, IUnknown*);
}
else if (IsEqualIID(riid, CLSID_CDocObjAssoc))
{
*ppvObj = (void*)this;
}
else
{
*ppvObj = NULL;
return E_NOINTERFACE;
}
AddRef();
return NOERROR;
}
ULONG CDocObjAssoc::AddRef()
{
_cRef++;
DebugMsg(TF_SHDREF, TEXT("CDocObjAssoc(%x)::AddRef called, new _cRef=%d"), this, _cRef);
return _cRef;
}
ULONG CDocObjAssoc::Release()
{
_cRef--;
DebugMsg(TF_SHDREF, TEXT("CDocObjAssoc(%x)::Release called, new _cRef=%d"), this, _cRef);
if (_cRef > 0)
return _cRef;
delete this;
return 0;
}
// this puts the _pole object in the cache.
// if we're called multiple times, we blow off the later calls.
// so if someone tries this with different pidl's, later ones won't
// get registered.
HRESULT CDocObjectHost::RegisterObject(LPCITEMIDLIST pidlKey)
{
HRESULT hres = S_FALSE;
if (!_fObjInCache) {
_fObjInCache = TRUE;
CDocObjAssoc* pdoa = new CDocObjAssoc(_dwDOCHF);
if (ShouldCache()) {
if (_pole) {
Assert(_pObjCache);
if (_pObjCache) {
_fObjInCache = _pObjCache->RegisterObject(pidlKey, _pole, pdoa, &_stExpires, _fhasLastModified);
hres = S_OK;
}
}
} else {
INavigationStackItem *pnsi;
_pwb->GetNavigationStackItem(_psv, &pnsi);
if (pnsi) {
DebugMsg(DM_CACHETRACE, TEXT("shd tr -- register object cached oleobj %x into nav item %x for _psv %x"), _pole, pnsi, _psv);
pnsi->SetCacheObject(_pole, pdoa);
pnsi->Release();
}
hres = S_OK;
}
if (pdoa) {
pdoa->Release();
}
}
return hres;
}
void CDocObjectHost::_IPDeactivateMsoView(IOleDocumentView* pmsov)
{
DebugMsg(TF_SHDUIACTIVATE, TEXT("DOH::_IPDeactivateMsoView called (this==%x)"), this);
if (pmsov)
{
IOleInPlaceObject* pipo = NULL;
HRESULT hresT = _pole->QueryInterface(IID_IOleInPlaceObject, (LPVOID*)&pipo);
if (SUCCEEDED(hresT)) {
_fIPDeactivatingView = TRUE;
pipo->InPlaceDeactivate();
_fIPDeactivatingView = FALSE;
pipo->Release();
}
pmsov->Show(FALSE);
}
}
void CDocObjectHost::_UIDeactivateMsoView(void)
{
DebugMsg(TF_SHDUIACTIVATE, TEXT("DOH::_UIDeactivateMsoView called (this==%x)"), this);
if (_pmsov)
{
_pmsov->UIActivate(FALSE);
}
}
//
// Hide the office toolbar
//
void CDocObjectHost::_HideOfficeToolbars(void)
{
if (_pmsot) {
OLECMD rgcmd = { OLECMDID_HIDETOOLBARS, 0 };
_pmsot->QueryStatus(NULL, 1, &rgcmd, NULL);
// LATCHED means hidden
rgcmd.cmdf &= (OLECMDF_SUPPORTED | OLECMDF_LATCHED);
// If it's supported and visible (not LATCHED), toggle it.
if (rgcmd.cmdf == OLECMDF_SUPPORTED) {
_pmsot->Exec(NULL, OLECMDID_HIDETOOLBARS, OLECMDEXECOPT_DONTPROMPTUSER, NULL, NULL);
}
}
}
void CDocObjectHost::_ShowMsoView(void)
{
HRESULT hres;
//
// HACK: Word97 UIDeactivate when we call SetInPlaceSite even with the
// same in-place site.
//
IOleInPlaceSite* psite;
hres = _pmsov->GetInPlaceSite(&psite);
if (SUCCEEDED(hres)) {
if (psite!=this) {
_pmsov->SetInPlaceSite(this);
} else {
DebugMsg(TF_SHDAPPHACK, TEXT("DOH::_ShowMsoView not calling SetInPlaceSite for Word97"));
}
psite->Release();
} else {
_pmsov->SetInPlaceSite(this);
}
GetClientRect(_hwnd, &_rcView);
Assert(_uState != SVUIA_DEACTIVATE);
if (_uState != SVUIA_INPLACEACTIVATE)
_pmsov->UIActivate(TRUE);
//
// HACK:
//
// We call _HideOfficeToolbars when our OnUIActivate is called.
// SriniK suggested us to do it in order to avoid flashing.
// It works well with Excel (3404), but does not work with Word.
// Word does not hide its toolbars correctly. To work around that
// bug, we call _HideofficeToolbars here again.
//
_HideOfficeToolbars();
hres = _pmsov->SetRect(&_rcView);
if (FAILED(hres)) {
DebugMsg(DM_ERROR, TEXT("DOC::_ShowMsoView _pmsov->SetRect ##FAILED## %x"), hres);
}
if (FAILED(hres) && _uState == SVUIA_INPLACEACTIVATE) {
DebugMsg(TF_SHDAPPHACK, TEXT("#APPHACK# DOH::_ShowMsoView calling UIActivate"));
// HACKHACK: for word. they refuse to show if they aren't UIActivated.
// if the setrect fails, and we didn't do a UIActivate, do it now.
_fDontInplaceActivate = TRUE;
DebugMsg(TF_SHDAPPHACK, TEXT("HACK: CDOH::_ShowMsoView calling UIActive(TRUE) to work around Word bug"));
_pmsov->UIActivate(TRUE);
_pmsov->SetRect(&_rcView);
}
hres = _pmsov->Show(TRUE);
if (FAILED(hres)) {
DebugMsg(DM_ERROR, TEXT("DOH::_ShowMsoView _pmsov->Show ##FAILED## %x"), hres);
}
}
HRESULT CDocObjectHost::_ActivateMsoView()
{
#ifdef DEBUG
PERFMSG(TEXT("_ActivateMsoView"), GetCurrentTime() - g_dwPerf);
g_dwPerf = GetCurrentTime();
#endif
HRESULT hres = NOERROR;
if (!_phls) {
_pole->QueryInterface(IID_IHlinkSource, (LPVOID*)&_phls);
}
if (_phls) {
WCHAR wszLocation[MAX_URL_STRING];
LPWSTR pwszLocation = NULL;
if (_pszLocation) {
MultiByteToWideChar(CP_ACP, 0, _pszLocation, -1,
wszLocation, ARRAYSIZE(wszLocation));
pwszLocation = wszLocation;
}
//
// Special test case for IHlinkFrame marshaling.
//
#if 0
if (GetAsyncKeyState(VK_CONTROL)<0)
{
_pole->SetClientSite(NULL);
}
#endif
hres = _phls->Navigate(0, pwszLocation);
if (FAILED(hres)) {
DebugMsg(DM_ERROR, TEXT("DOC::_ActivateMsoView _phls->Navigate(%s) ##FAILED## %x"),
_pszLocation ? _pszLocation : NULL, hres);
}
} else {
LONG iVerb = OLEIVERB_SHOW;
MSG msg;
LPMSG pmsg = NULL;
if (_uState == SVUIA_INPLACEACTIVATE) {
iVerb = OLEIVERB_INPLACEACTIVATE;
}
if (_pedsHelper)
{
if (SUCCEEDED(_pedsHelper->GetDoVerbMSG(&msg)))
{
pmsg = &msg;
}
}
hres = _pole->DoVerb(iVerb, pmsg, this, (UINT)-1, _hwnd, &_rcView);
if (hres == OLEOBJ_E_INVALIDVERB && iVerb == OLEIVERB_INPLACEACTIVATE)
hres = _pole->DoVerb(OLEIVERB_SHOW, pmsg, this, (UINT)-1, _hwnd, &_rcView);
if (FAILED(hres)) {
DebugMsg(DM_ERROR, TEXT("DOC::_ActivateMsoView _pole->DoVerb ##FAILED## %x"), hres);
}
}
// the doc is activated
if (SUCCEEDED(hres)) {
if (_fHaveParentSite) {
_HideOfficeToolbars();
}
if (_fGotFromCache) {
// since we're pulling from cache, this object might be expired.
// refresh if expired
VARIANTARG v;
v.vt = VT_I4;
v.lVal = OLECMDIDF_REFRESH_IFEXPIRED;
ExecDown(NULL, OLECMDID_REFRESH, 0, &v, NULL);
}
}
return hres;
}
HRESULT CDocObjectHost::_EnsureActivateMsoView()
{
HRESULT hres = E_FAIL;
// if we've got an ole object and
// either we don't have a view, or we don't have an active view..
// do the activation
if (_pole)
{
if (!_pmsov || !_ActiveObject()) {
hres = _ActivateMsoView();
// Note that we should not UIActivate it here. We should wait
// until the DocObject calls our ActivateMe
// _ShowMsoView();
}
}
return hres;
}
//
// This member closes the MsoView window and releases interface
// pointers. This is essentially the reverse of _CreateMsoView.
//
void CDocObjectHost::_CloseMsoView(void)
{
if (_pmsot) {
ATOMICRELEASE(_pmsot);
}
if (_pmsov)
{
VIEWMSG(TEXT("_CloseMsoView calling pmsov->UIActivate(FALSE)"));
IOleDocumentView* pmsov = _pmsov;
_pmsov = NULL;
_fDontInplaceActivate = FALSE;
#ifdef DONT_UIDEACTIVATE
if (_uState != SVUIA_DEACTIVATE)
pmsov->UIActivate(FALSE);
#else // DONT_UIDEACTIVATE
if (_uState == SVUIA_ACTIVATE_FOCUS)
pmsov->UIActivate(FALSE);
#endif // DONT_UIDEACTIVATE
_IPDeactivateMsoView(pmsov);
pmsov->CloseView(0);
pmsov->SetInPlaceSite(NULL);
pmsov->Release();
VIEWMSG(TEXT("_CloseMsoView called pmsov->Release()"));
}
if(_pmsoc) {
ATOMICRELEASE(_pmsoc);
}
}
void CDocObjectHost::_OnPaint(HDC hdc)
{
if (_pmsov && !_ActiveObject())
{
HRESULT hres;
RECT rcClient;
GetClientRect(_hwnd, &rcClient);
hres = OleDraw(_pmsov, DVASPECT_CONTENT, hdc, &rcClient);
DebugMsg(0, TEXT("shd TR ::_OnPaint OleDraw returns %x"), hres);
}
}
HRESULT _GetDefaultLocation(LPTSTR pszPath, DWORD cbPathSize, UINT id)
{
TCHAR szPath[MAX_URL_STRING];
DWORD cbSize = SIZEOF(szPath);
HRESULT hres = E_FAIL;
HKEY hkey;
// BUGBUG: Share this code!!!
// BUGBUG: This is Internet Explorer Specific
if (RegOpenKey(HKEY_LOCAL_MACHINE,
TEXT("Software\\Microsoft\\Internet Explorer\\Main"),
&hkey)==ERROR_SUCCESS)
{
DWORD dwType;
LPCTSTR pszName;
switch(id) {
default:
Assert(0);
case IDM_GOHOME:
pszName = TEXT("Default_Page_URL");
break;
case IDM_GOSEARCH:
pszName = TEXT("Default_Search_URL");
break;
case IDP_UPDATE:
pszName = TEXT("Default_Update_URL");
break;
case IDP_TODAYSLINK:
pszName = TEXT("Default_Todays_URL");
break;
}
if (RegQueryValueEx(hkey, pszName,
0, &dwType, (LPBYTE)szPath, &cbSize)==ERROR_SUCCESS)
{
// When reading a URL from registry, treat it like it was typed
// in on the address bar.
if (PathIsFilePath(szPath) ||
!InternetCanonicalizeUrl(szPath, pszPath, &cbPathSize, ICU_NO_ENCODE)) {
lstrcpyn(pszPath, szPath, cbPathSize / SIZEOF(TCHAR));
}
if (szPath[0]=='f' && szPath[1]=='i' && szPath[2]=='l'
&& szPath[3]=='e' && szPath[4]==':') {
lstrcpy(szPath, szPath+5);
}
hres = S_OK;
}
RegCloseKey(hkey);
}
HOMEMSG("_GetStdLocation returning",
(SUCCEEDED(hres) ? pszPath : "Error"), hres);
return hres;
}
HRESULT _GetStdLocation(LPTSTR pszPath, DWORD cbPathSize, UINT id)
{
TCHAR szPath[MAX_URL_STRING];
DWORD cbSize = SIZEOF(szPath);
HRESULT hres = E_FAIL;
HUSKEY hUSkey;
// BUGBUG: Share this code!!!
// BUGBUG: This is Internet Explorer Specific
if (SHRegOpenUSKey("Software\\Microsoft\\Internet Explorer\\Main", KEY_READ|KEY_WRITE,
NULL, &hUSkey, FALSE)==ERROR_SUCCESS)
{
DWORD dwType;
if (id==IDM_GOFIRSTHOME || id==IDM_GOFIRSTHOMERO) {
//
// This is one of last minutes BradSi features for beta-1.
//
#if 1
DWORD cbT = cbSize;
if (SHRegQueryUSValue(hUSkey,
TEXT("First Home Page"),
&dwType, (LPBYTE)pszPath, &cbT, FALSE, NULL, 0)==ERROR_SUCCESS)
{
if (id==IDM_GOFIRSTHOME) {
SHRegDeleteUSValue(hUSkey, TEXT("First Home Page"), SHREGDEL_DEFAULT);
}
hres = S_OK;
} else {
Assert(hres==E_FAIL);
}
goto done;
#endif
}
LPCTSTR pszName;
switch(id) {
default:
Assert(0);
case IDM_GOHOME:
pszName = TEXT("Start Page");
break;
case IDM_GOSEARCH:
pszName = TEXT("Search Page");
break;
case IDM_GOLOCALPAGE:
pszName = TEXT("Local Page");
break;
}
if (SHRegQueryUSValue(hUSkey, pszName,
&dwType, (LPBYTE)szPath, &cbSize, FALSE, NULL, 0)==ERROR_SUCCESS)
{
// When reading a URL from registry, treat it like it was typed
// in on the address bar.
if (id==IDM_GOLOCALPAGE ||
PathIsFilePath(szPath) ||
!InternetCanonicalizeUrl(szPath, pszPath, &cbPathSize, ICU_NO_ENCODE)) {
lstrcpyn(pszPath, szPath, cbPathSize / SIZEOF(TCHAR));
}
if (szPath[0]=='f' && szPath[1]=='i' && szPath[2]=='l'
&& szPath[3]=='e' && szPath[4]==':') {
lstrcpy(szPath, szPath+5);
}
hres = S_OK;
}
done:
SHRegCloseUSKey(hUSkey);
}
HOMEMSG("_GetStdLocation returning",
(SUCCEEDED(hres) ? pszPath : "Error"), hres);
return hres;
}
HRESULT _SetStdLocation(LPTSTR szPath, UINT id)
{
HRESULT hres = E_FAIL;
HKEY hkey;
// BUGBUG: Share this code!!!
// BUGBUG: This is Internet Explorer Specific
if (RegOpenKey(HKEY_CURRENT_USER,
TEXT("Software\\Microsoft\\Internet Explorer\\Main"),
&hkey)==ERROR_SUCCESS)
{
DWORD cbSize = lstrlen(szPath) + SIZEOF(TCHAR);
if (RegSetValueEx(hkey,
(id==IDM_GOHOME) ? TEXT("Start Page") : TEXT("Search Page"),
0,
REG_SZ,
(LPBYTE)szPath, cbSize)==ERROR_SUCCESS)
{
hres = S_OK;
}
RegCloseKey(hkey);
}
return hres;
}
HRESULT WINAPI SHDGetPageLocation(HWND hwndOwner, UINT idp, LPTSTR pszPath, UINT cchMax, LPITEMIDLIST *ppidlOut)
{
TCHAR szBuf[MAX_URL_STRING];
if (pszPath==NULL) {
pszPath = szBuf;
cchMax = ARRAYSIZE(szBuf);
}
*ppidlOut = NULL;
HRESULT hres = S_OK;
switch (idp) {
case IDP_UPDATE:
case IDP_TODAYSLINK:
Assert(IDP_TODAYSLINK-IDP_UPDATE == IDS_DEF_TODAYSLINK-IDS_DEF_UPDATE);
if (FAILED(_GetDefaultLocation(pszPath, cchMax*SIZEOF(TCHAR),
idp)))
LoadString(HINST_THISDLL, IDS_DEF_UPDATE+(idp-IDP_UPDATE), pszPath, cchMax);
break;
default:
Assert(idp==IDP_START || idp==IDP_SEARCH);
hres = _GetStdLocation(pszPath, cchMax*SIZEOF(TCHAR),
(idp == IDP_SEARCH) ? IDM_GOSEARCH : IDM_GOHOME);
if (FAILED(hres))
_GetDefaultLocation(pszPath, cchMax*SIZEOF(TCHAR),
(idp == IDP_SEARCH) ? IDM_GOSEARCH : IDM_GOHOME);
break;
}
if (SUCCEEDED(hres)) {
hres = IECreateFromPath(hwndOwner, pszPath, ppidlOut);
HOMEMSG("SHDGetPageLocation SHILCreateFromPage returned", pszPath, hres);
}
return hres;
}
void CDocObjectHost::_ChainBSC()
{
if (!_bsc._pbscChained && _phf) {
// Get "chaigned" bind status, if any
IServiceProvider* psp = NULL;
HRESULT hres = _phf->QueryInterface(IID_IServiceProvider, (LPVOID*)&psp);
CHAINMSG("_StartAsyncBinding hlf->QI returns", hres);
if (SUCCEEDED(hres)) {
Assert(NULL==_bsc._pbscChained);
hres = psp->QueryService(SID_SHlinkFrame, IID_IBindStatusCallback, (LPVOID*)&_bsc._pbscChained);
CHAINMSG("_StartAsyncBinding psp(hlf)->QS returns", hres);
psp->Release();
if (SUCCEEDED(hres))
{
Assert(NULL==_bsc._pnegotiateChained);
_bsc._pbscChained->QueryInterface(IID_IHttpNegotiate, (LPVOID *)&_bsc._pnegotiateChained);
}
}
}
}
//
// WARNING: Following two global variables are shared among multiple-threads
// in a thread. Therefore, all right-access must be serialized and all read
// access should be blocked when right is going on.
//
// Right now, we just initialize them once (based on the registry setting)
// and never update. It allows us to simplify the code quite a bit. If we
// need to update, then _RegisterMediaTypeClass should be changed significantlly
// so that we can safely handle multiple access to those hdsa's. (SatoNa)
//
HDSA g_hdsaCls = NULL;
HDSA g_hdsaStr = NULL;
BOOL CDocObjectHost::_BuildClassMapping(void)
{
if (g_hdsaCls) {
return (DSA_GetItemCount(g_hdsaCls)==DSA_GetItemCount(g_hdsaStr));
}
ENTERCRITICAL;
if (!g_hdsaCls) {
g_hdsaStr = DSA_Create(SIZEOF(LPCSTR), 32);
if (g_hdsaStr)
{
HDSA hdsaCls = DSA_Create(SIZEOF(CLSID), 32);
if (hdsaCls)
{
HKEY hkey;
if (RegOpenKey(HKEY_LOCAL_MACHINE,
TEXT("Software\\Microsoft\\Internet Explorer\\MediaTypeClass"),
&hkey) == ERROR_SUCCESS)
{
TCHAR szCLSID[64]; // enough for "{CLSID}"
for (int iKey=0;
RegEnumKey(hkey, iKey, szCLSID, SIZEOF(szCLSID))==ERROR_SUCCESS;
iKey++)
{
CLSID clsid;
WCHAR wszCLSID[64];
MultiByteToWideChar(CP_ACP, 0, szCLSID, -1,
wszCLSID, ARRAYSIZE(wszCLSID));
if (FAILED(CLSIDFromString(wszCLSID, &clsid))) {
DebugMsg(DM_WARNING, "CDOH::_RMTC CLSIDFromString(%x) failed", szCLSID);
continue;
}
DebugMsg(DM_MIMEMAPPING, "CDOH::_RMTC RegEnumKey found %s", szCLSID);
HKEY hkeyCLSID;
if (RegOpenKey(hkey, szCLSID, &hkeyCLSID) == ERROR_SUCCESS)
{
for (int iValue=0; ; iValue++)
{
TCHAR szFormatName[128];
DWORD dwType;
DWORD cchValueName = ARRAYSIZE(szFormatName);
if (RegEnumValue(hkeyCLSID, iValue, szFormatName, &cchValueName, NULL,
&dwType, NULL, NULL)==ERROR_SUCCESS)
{
DebugMsg(DM_MIMEMAPPING, "CDOH::_RMTC RegEnumValue found %s", szFormatName);
LPTSTR psz = StrDup(szFormatName);
if (psz) {
DSA_InsertItem(hdsaCls, 0xffff, &clsid);
if (DSA_InsertItem(g_hdsaStr, 0xffff, &psz)<0) {
LocalFree(psz);
break;
}
}
} else {
break;
}
}
RegCloseKey(hkeyCLSID);
} else {
DebugMsg(DM_WARNING, TEXT("CDOH::_RMTC RegOpenKey(%s) failed"), szCLSID);
}
}
RegCloseKey(hkey);
} else {
DebugMsg(0, TEXT("CDOH::_RMTC RegOpenKey(MediaTypeClass) failed"));
}
//
// Update g_hdsaCls at the end so that other thread won't
// access while we are adding items.
//
g_hdsaCls = hdsaCls;
Assert(DSA_GetItemCount(g_hdsaCls)==DSA_GetItemCount(g_hdsaStr));
}
}
}
LEAVECRITICAL;
return (g_hdsaCls && DSA_GetItemCount(g_hdsaCls)==DSA_GetItemCount(g_hdsaStr));
}
HRESULT CDocObjectHost::_RegisterMediaTypeClass(IBindCtx* pbc)
{
HRESULT hres = S_FALSE; // Assume no mapping
if (_BuildClassMapping() && DSA_GetItemCount(g_hdsaCls)) {
//
// WARNING: This code assumes that g_hdsaCls/g_hdsaStr never
// changes once they are initializes. Read notes above
// those global variables for detail.
//
hres = RegisterMediaTypeClass(pbc,
DSA_GetItemCount(g_hdsaCls),
(LPCTSTR*)DSA_GetItemPtr(g_hdsaStr, 0),
(CLSID*)DSA_GetItemPtr(g_hdsaCls, 0), 0);
DebugMsg(DM_MIMEMAPPING, "CDOH::_StartAsyncBinding RegisterMTC returns %x", hres);
}
// Now see if the container has anything that needs to be registered
//
Assert(_psp);
if (_psp)
{
IMimeInfo *pIMimeInfo;
hres = _psp->QueryService(SID_IMimeInfo, IID_IMimeInfo, (LPVOID*)&pIMimeInfo);
if (SUCCEEDED(hres))
{
UINT cTypes = 0;
LPCSTR *ppszTypes = NULL;
CLSID *pclsIDs= NULL;
Assert(pIMimeInfo);
hres = pIMimeInfo->GetMimeCLSIDMapping(&cTypes, &ppszTypes, &pclsIDs);
if(SUCCEEDED(hres)) {
if(cTypes && ppszTypes && pclsIDs) {
// Last one to register wins, so if the container wants to override what is
// already registered this should do it.
// URLMon will handle the duplicates corectly.
//
hres = RegisterMediaTypeClass(pbc, cTypes, ppszTypes, pclsIDs, 0);
DebugMsg(DM_MIMEMAPPING, "CDOH::_StartAsyncBinding RegisterMTC for Container returns %x", hres);
}
// RegisterMediaTypeClass should have made copies
// so free the containers allocations as it expects us to do
//
// CoTaskMemFree(NULL) is OK
//
CoTaskMemFree(ppszTypes);
CoTaskMemFree(pclsIDs);
}
pIMimeInfo->Release();
} else {
hres = S_FALSE;
}
}
return hres;
}
const SA_BSTRGUID s_sstrEFM = {
38 * SIZEOF(WCHAR),
L"{D0FCA420-D3F5-11CF-B211-00AA004AE837}"
};
void _CreateFormatEnumerator(VARIANT* pvar, IWebBrowserApp* pdie)
{
HKEY hkey;
if (RegOpenKey(HKEY_LOCAL_MACHINE,
TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\Accepted Documents"),
&hkey) == ERROR_SUCCESS)
{
HDSA hdsa = DSA_Create(SIZEOF(FORMATETC), 16);
if (hdsa)
{
HRESULT hres = S_OK;
FORMATETC fmt = { 0, 0, 0, TYMED_NULL };
for (int iValue=0; ; iValue++)
{
TCHAR szFormatName[128];
DWORD cchFormatName = ARRAYSIZE(szFormatName);
TCHAR szValueName[128];
DWORD dwType;
DWORD cchValueName = ARRAYSIZE(szValueName);
if (RegEnumValue(hkey, iValue, szValueName, &cchValueName, NULL,
&dwType, (LPBYTE) szFormatName, &cchFormatName)==ERROR_SUCCESS)
{
LPCSTR apszType[] = { szFormatName };
hres = RegisterMediaTypes(1, apszType, &fmt.cfFormat);
if (SUCCEEDED(hres)) {
DSA_AppendItem(hdsa, &fmt);
} else {
DebugMsg(DM_ERROR, TEXT("_CreateFormatEnumerator RegisterMediaType failed %x"), hres);
break;
}
} else {
break;
}
}
// For */* /* Dummy Comment to keep Source Insight happy */
fmt.cfFormat = CF_NULL;
DSA_AppendItem(hdsa, &fmt);
IEnumFORMATETC* pEFM;
hres = CreateFormatEnumerator(DSA_GetItemCount(hdsa),
(FORMATETC*)DSA_GetItemPtr(hdsa, 0), &pEFM);
if (SUCCEEDED(hres)) {
Assert(pvar->vt == VT_EMPTY);
pvar->vt = VT_UNKNOWN;
pvar->punkVal = pEFM;
hres = pdie->PutProperty((BSTR)s_sstrEFM.wsz, *pvar);
} else {
DebugMsg(DM_ERROR, TEXT("_CreateFormatEnumerator CreateFormatEnumerator failed %x"), hres);
}
DSA_Destroy(hdsa);
}
RegCloseKey(hkey);
} else {
DebugMsg(DM_ACCEPTHEADER, TEXT("_CreateFormatEnumerator RegOpenKey failed -- don't register"));
}
}
HRESULT _RegisterAcceptHeaders(IBindCtx* pbc, IShellBrowser* psb)
{
Assert(pbc);
Assert(psb);
IServiceProvider* psp = NULL;
HRESULT hres = psb->QueryInterface(IID_IServiceProvider, (LPVOID*)&psp);
if (SUCCEEDED(hres))
{
Assert(psp);
IWebBrowserApp* pdie;
hres = psp->QueryService(IID_IWebBrowserApp, IID_IWebBrowserApp, (LPVOID*)&pdie);
if (SUCCEEDED(hres)) {
VARIANT var = { VT_EMPTY };
hres = pdie->GetProperty((BSTR)s_sstrEFM.wsz, &var);
if (SUCCEEDED(hres))
{
if (var.vt == VT_EMPTY) {
DebugMsg(DM_ACCEPTHEADER, TEXT("_RegisterAcceptHeader var.vt == VT_EMPTY"));
_CreateFormatEnumerator(&var, pdie);
}
if (var.vt == VT_UNKNOWN) {
DebugMsg(DM_ACCEPTHEADER, TEXT("_RegisterAcceptHeader var.vt == VT_UNKNOWN"));
IEnumFORMATETC* pEFM;
hres = var.punkVal->QueryInterface(IID_IEnumFORMATETC, (LPVOID*)&pEFM);
if (SUCCEEDED(hres)) {
IEnumFORMATETC* pEFMClone = NULL;
hres = pEFM->Clone(&pEFMClone);
if (SUCCEEDED(hres)) {
DebugMsg(DM_ACCEPTHEADER, TEXT("_RegisterAcceptHeader registering FormatEnum %x"), pEFMClone);
hres = RegisterFormatEnumerator(pbc, pEFMClone, 0);
pEFMClone->Release();
} else {
DebugMsg(DM_ERROR, TEXT("_RegisterAcceptHeader Clone failed %x"), hres);
}
pEFM->Release();
}
} else {
DebugMsg(DM_ACCEPTHEADER, TEXT("_RegisterAcceptHeader not registering FormatEnum"));
}
VariantClear(&var);
} else {
DebugMsg(DM_ERROR, TEXT("_RegisterAcceptHeader pdie->GetProperty() failed %x"), hres);
}
pdie->Release();
} else {
DebugMsg(DM_ERROR, TEXT("_RegisterAcceptHeader psp->QS(IIE, IIE) failed %x"), hres);
}
psp->Release();
} else {
DebugMsg(DM_ERROR, TEXT("_RegisterAcceptHeader psb->QI(ISP) failed %x"), hres);
}
return hres;
}
HRESULT CDocObjectHost::_GetOfflineSilent(BOOL *pbIsOffline, BOOL *pbIsSilent)
{
HRESULT hres = E_FAIL;
VARIANT vtOffline;
VARIANT vtSilent;
vtOffline.boolVal = FALSE;
vtSilent.boolVal = FALSE;
if (_peds)
{
if (pbIsOffline)
{
hres = _peds->OnInvoke(DISPID_AMBIENT_OFFLINE, IID_NULL, NULL, DISPATCH_PROPERTYGET, NULL, &vtOffline, NULL, NULL);
Assert(vtOffline.vt == VT_BOOL);
}
if (pbIsSilent)
{
hres = _peds->OnInvoke(DISPID_AMBIENT_SILENT, IID_NULL, NULL, DISPATCH_PROPERTYGET, NULL, &vtSilent, NULL, NULL);
Assert(vtSilent.vt == VT_BOOL);
}
}
if (pbIsOffline)
*pbIsOffline = (vtOffline.boolVal) ? TRUE : FALSE;
if (pbIsSilent)
*pbIsSilent = (vtSilent.boolVal) ? TRUE : FALSE;
return hres;
}
#ifdef FEATURE_PICS
/*
Callback function for RatingObtainQuery
*/
void RatingObtainQueryCallback(DWORD dwUserData, HRESULT hr, LPCTSTR pszRating, LPVOID lpvInpageRating)
{
/* WARNING: This function is called by MSRATING.DLL on a separate thread,
* not the main message loop thread. Touch nothing in important data
* structures not protected by critical sections!
*
* Merely format up a windows message with the info we have; we'll handle
* this in the main thread, if we ever get there.
*
* Note that pszRating is ignored, we count on the ratings engine to have
* called RatingCheckUserAccess for us and provide the HRESULT.
*/
if (!::_PostPicsMessage(dwUserData, hr, lpvInpageRating))
::RatingFreeDetails(lpvInpageRating);
}
void CDocObjectHost::_StartPicsQuery(void)
{
if (::RatingEnabledQuery() == S_OK) {
_fbPicsWaitFlags = PICS_WAIT_FOR_ASYNC
| PICS_WAIT_FOR_INDOC
| PICS_WAIT_FOR_END
// | PICS_WAIT_FOR_ROOT
;
_fPicsAccessAllowed = 0;
char szURL[MAX_URL_STRING];
LPSTR pszURL = szURL;
if (FAILED(_GetCurrentPage(szURL, sizeof(szURL))))
pszURL = NULL;
HRESULT hr;
_dwPicsSerialNumber = ::_AddPicsQuery(_hwnd);
if (_dwPicsSerialNumber == 0)
hr = E_OUTOFMEMORY;
else
hr = RatingObtainQuery(pszURL, _dwPicsSerialNumber, RatingObtainQueryCallback, &_hPicsQuery);
if (FAILED(hr)) {
::_RemovePicsQuery(_dwPicsSerialNumber);
_dwPicsSerialNumber = 0;
_fbPicsWaitFlags &= ~PICS_WAIT_FOR_ASYNC;
}
}
}
void CDocObjectHost::_GotLabel(HRESULT hres, LPVOID pDetails, BYTE bfSource)
{
/* If we've already gotten a result from this or a more significant source,
* ignore this one.
*/
if (!_fbPicsWaitFlags & bfSource) {
if (pDetails != NULL)
::RatingFreeDetails(pDetails);
}
else {
/* If the result is an error somehow (label doesn't apply, etc.), and
* we can expect more labels from this source, then we don't do anything
* except save the rating details if we haven't got any yet.
*/
if (FAILED(hres) && (PICS_MULTIPLE_FLAGS & bfSource)) {
if (_pRatingDetails == NULL) {
_pRatingDetails = pDetails;
}
else {
::RatingFreeDetails(pDetails);
}
}
else {
/* Either we got a definitive answer from this rating source, or
* this is the only answer we'll get from it. We clear at least
* the flag for this source so we know we've heard from it. If
* the response was not an error, then clear flags for all less
* significant sources as well, so that we'll ignore them. On
* the other hand, if this source returned an error, it didn't
* give us anything useful, so we keep looking at other sources.
*/
if (SUCCEEDED(hres))
_fbPicsWaitFlags &= bfSource - 1;
else
_fbPicsWaitFlags &= ~bfSource;
if (hres == S_OK) {
::RatingFreeDetails(pDetails); /* don't need this if access allowed */
_fPicsAccessAllowed = 1;
}
else {
/* Access denied or error. Meaningful details from this result
* can override details from an earlier, less significant
* result. Only explicitly deny access if not an error,
* though (this handles the valid root label followed by
* invalid in-document label, for example).
*/
if (pDetails != NULL) {
if (_pRatingDetails != NULL)
::RatingFreeDetails(_pRatingDetails);
_pRatingDetails = pDetails;
}
if (SUCCEEDED(hres))
_fPicsAccessAllowed = 0;
}
}
}
if (_fPicsBlockLate && !_fbPicsWaitFlags)
_HandlePicsChecksComplete();
}
void CDocObjectHost::_HandleInDocumentLabel(LPCSTR pszLabel)
{
if (!(_fbPicsWaitFlags & PICS_WAIT_FOR_INDOC))
return;
DebugMsg(DM_WARNING, TEXT("CDOH::_HandleInDocumentLabel given label %s"), pszLabel);
LPVOID pDetails = NULL;
char szURL[MAX_URL_STRING];
LPSTR pszURL = szURL;
if (FAILED(_GetCurrentPage(szURL, sizeof(szURL))))
pszURL = NULL;
HRESULT hres = ::RatingCheckUserAccess(NULL, pszURL, pszLabel, NULL, 0, &pDetails);
_GotLabel(hres, pDetails, PICS_WAIT_FOR_INDOC);
}
void CDocObjectHost::_HandleDocumentEnd(void)
{
DebugMsg(DM_WARNING, TEXT("CDOH::_HandleDocumentEnd -- no more PICS labels"));
/* End of document; revoke the IOleCommandTarget we gave to the document,
* so it won't send us any more notifications.
*/
IOleCommandTarget *pct;
if (_pole && SUCCEEDED(_pole->QueryInterface(IID_IOleCommandTarget, (LPVOID *)&pct))) {
VARIANTARG v;
v.vt = VT_UNKNOWN;
v.lVal = 0;
pct->Exec(&CGID_ShellDocView, SHDVID_CANSUPPORTPICS, 0, &v, NULL);
pct->Release();
}
if (!(_fbPicsWaitFlags & PICS_WAIT_FOR_END))
return;
_fbPicsWaitFlags &= ~PICS_WAIT_FOR_INDOC; /* we know we won't get any more indoc labels */
LPVOID pDetails = NULL;
char szURL[MAX_URL_STRING];
LPSTR pszURL = szURL;
if (FAILED(_GetCurrentPage(szURL, sizeof(szURL))))
pszURL = NULL;
HRESULT hres = ::RatingCheckUserAccess(NULL, pszURL, NULL, NULL, 0, &pDetails);
_GotLabel(hres, pDetails, PICS_WAIT_FOR_END);
}
#endif
HRESULT CDocObjectHost::_StartAsyncBinding(IMoniker* pmk, IBindCtx* pbc, IShellView* psvPrev)
{
URLMSG(TEXT("_StartAsyncBinding called"));
HRESULT hres;
Assert(_bsc._pbc==NULL && _pole==NULL);
_bsc._RegisterObjectParam(pbc);
//
// Associate the client site as an object parameter to this
// bind context so that Trident can pick it up while processing
// IPersistMoniker::Load().
//
pbc->RegisterObjectParam(WSZGUID_OPID_DocObjClientSite,
SAFECAST(this, IOleClientSite*));
_ChainBSC();
IUnknown* punk = NULL;
_bsc._pbc = pbc;
pbc->AddRef();
// Decide right here whether or not this frame is offline
BOOL bFrameIsOffline = FALSE;
BOOL bFrameIsSilent = FALSE;
this->_GetOfflineSilent(&bFrameIsOffline, &bFrameIsSilent);
_bsc._bFrameIsOffline = bFrameIsOffline ? TRUE : FALSE;
_bsc._bFrameIsSilent = bFrameIsSilent ? TRUE : FALSE;
#ifdef DEBUG
PERFMSG(TEXT("_StartAsyncBinding Calling pmk->BindToObject"), GetCurrentTime()-g_dwPerf);
g_dwPerf = GetCurrentTime();
#endif
// Register overriding mime->CLSID mapping
_RegisterMediaTypeClass(pbc);
// Register accept headers
_RegisterAcceptHeaders(pbc, _psb);
if (_pwb)
_pwb->SetNavigateState(BNS_BEGIN_NAVIGATE);
#ifdef FEATURE_PICS
_StartPicsQuery();
#endif
URLMSG(TEXT("_StartAsyncBinding calling pmk->BindToObject"));
hres = pmk->BindToObject(pbc, NULL, IID_IUnknown, (LPVOID*)&punk);
URLMSG3(TEXT("_StartAsyncBinding pmk->BindToObject returned"), hres, punk);
if (SUCCEEDED(hres) || hres==E_PENDING)
{
hres = S_OK;
if (!_pole) {
if (psvPrev) {
_bsc._psvPrev = psvPrev;
psvPrev->AddRef();
}
} else {
URLMSG3(TEXT("_StartAsyncBinding we've already got _pole"), hres, _pole);
}
//
// If moniker happen to return the object synchronously, emulate
// OnDataAvailable callback and OnStopBinding.
//
if (punk)
{
_bsc.OnObjectAvailable(IID_IUnknown, punk);
_bsc.OnStopBinding(hres, NULL);
punk->Release();
Assert(_bsc._pbc==NULL);
}
}
else
{
// Binding failed.
DebugMsg(DM_WARNING, TEXT("CDOH::_StartAsyncBinding failed (%x)"), hres);
_bsc.OnStopBinding(hres, NULL);
Assert(_bsc._pbc==NULL);
}
return hres;
}
void CDocObjectHost::_ReleaseOleObject()
{
DebugMsg(DM_DEBUGTFRAME, TEXT("CDocObjectHost::_ReleaseOleObject called %x (%x)"), _pole, this);
// release _pole object and all the associated QI'ed pointers
if (_phls) {
_phls->SetBrowseContext(NULL); // probably no need
ATOMICRELEASE(_phls);
}
if (_pvo) {
IAdviseSink *pSink;
// paranoia: only blow away the advise sink if it is still us
if (SUCCEEDED(_pvo->GetAdvise(NULL, NULL, &pSink)) && pSink) {
if (pSink == (IAdviseSink *)this) {
_pvo->SetAdvise(0, 0, NULL);
} else {
Assert(0); // do we really hit this case?
}
pSink->Release();
}
ATOMICRELEASE(_pvo);
}
if (_pole) {
LPOLECLIENTSITE pcs;
if (SUCCEEDED(_pole->GetClientSite(&pcs)) && pcs) {
if (pcs == SAFECAST(this, LPOLECLIENTSITE)) {
_pole->SetClientSite(NULL);
}
pcs->Release();
}
// Notes: Make it sure that we don't hold a bogus _pole even
// for a moment (while we call Release).
ATOMICRELEASE(_pole);
}
// If we have a wrapping droptarget, release it now.
if (_dt._pdtDoc) {
ATOMICRELEASE(_dt._pdtDoc);
}
if (_dt._pdtFrame) {
ATOMICRELEASE(_dt._pdtFrame);
}
}
//
// This member releases all the interfaces to the DocObject, which is
// essentially the reverse of _Bind.
//
void CDocObjectHost::_UnBind(void)
{
if (_pmsot) { // paranoia
ATOMICRELEASE(_pmsot);
}
if (_pmsov) // paranoia
{
Assert(0);
ATOMICRELEASE(_pmsov);
}
if (_pmsoc) // paranoia
{
Assert(0);
ATOMICRELEASE(_pmsoc);
}
_xao.SetActiveObject(NULL);
if (_pole) {
// Just in case we're destroyed while we were waiting
// for the docobj to display itself.
//
_RemoveTransitionCapability();
if (!_fObjInCache) {
DebugMsg(DM_ADVISE, "CDocObjectHost::_UnBind about to call Close of %x", _pole);
_fIPDeactivatingView = TRUE;
_pole->Close(OLECLOSE_NOSAVE);
_fIPDeactivatingView = FALSE;
}
_ReleaseOleObject();
}
if (_pstg) {
ATOMICRELEASE(_pstg);
}
if (_pbcCur) {
ATOMICRELEASE(_pbcCur);
}
if (_pmkCur) {
ATOMICRELEASE(_pmkCur);
}
}
//
// HACK: If we open Excel95 objects directly, Excel goes crazy and eventually
// hit GPF. Here is the background info, I've got Office guys (SatoNa).
//
// From: Rajeev Misra (Xenix)
//
// 1) Excel does not handle the foll. case very well. Taking a normal file
// loading it through IPersistFile:Load and then bringing it up as an
// embedded object. The code was always tested so that the embedded
// objects always got loaded through ScPrsLoad. I am seeing a bunch of
// asserts in Excel that say that this assumption is being destroyed.
// Assert(_pole);
//
// From: Srini Koppolu
//
// For you, there is only one case, i.e. you always deal with the files. Then your code should look like this
//
// CreateFileMoniker from the file
// pUIActiveObject->OnFrameWindowActivate(FALSE);
// pmk->BindToObject(IID_IDataObject, &pdobj)
// pUIActiveObject->OnFrameWindowActivate(TRUE);
// OleCreateFromData()
//
// OnFrameWindowActivate is done to take care of another excel problem.
// If you currently have and Excel object UIActive in you and you try to
// do IPersistFile::Load on Excel, then it will cause problems.
//
void CDocObjectHost::_AppHackForExcel95(void)
{
Assert(_pole);
HRESULT hres;
IDataObject* pdt = NULL;
hres = _pole->QueryInterface(IID_IDataObject, (LPVOID*)&pdt);
DebugMsg(DM_BINDAPPHACK, TEXT("_PostBindAppHack -- QI(IOleDataObject) returned %x"), hres);
if (SUCCEEDED(hres))
{
Assert(_pstg==NULL);
hres = StgCreateDocfile(NULL,
STGM_DIRECT | STGM_CREATE | STGM_READWRITE
| STGM_SHARE_EXCLUSIVE | STGM_DELETEONRELEASE,
0, &_pstg);
DebugMsg(DM_BINDAPPHACK, TEXT("_PostBindAppHack StgCreateDocFile(NULL) returned %x"), hres);
if (SUCCEEDED(hres))
{
IOleObject* poleCopy = NULL;
hres = OleCreateFromData(pdt, IID_IOleObject, OLERENDER_NONE,
NULL, this, _pstg, (LPVOID*)&poleCopy);
DebugMsg(DM_BINDAPPHACK, TEXT("_PostBindAppHack OleCreateFromData(IOleObject) returned %x"), hres);
if (SUCCEEDED(hres)) {
_fCantSaveBack = TRUE;
ATOMICRELEASE(_pole);
_pole = poleCopy;
}
}
pdt->Release();
}
}
HKEY _GetUserCLSIDKey(IOleObject* pole)
{
HKEY hkey = NULL; // assume error
HRESULT hres;
CLSID clsid = CLSID_NULL;
hres = pole->GetUserClassID(&clsid);
//
// HACK: MSHTML.DLL does not implement GetUserClassID, but
// returns S_OK. That's why we need to check for CLSID_NULL.
//
if (SUCCEEDED(hres) && !IsEqualGUID(clsid, CLSID_NULL)) {
WCHAR wch[MAX_PATH];
StringFromGUID2(clsid, wch, ARRAYSIZE(wch));
TCHAR szBuf[50]; // 50 is enough for GUID
if (WideCharToMultiByte(CP_ACP, 0, wch, -1, szBuf, ARRAYSIZE(szBuf), NULL, NULL))
{
DebugMsg(DM_BINDAPPHACK, TEXT("_PostBindAppHack GetUserClassID = %s"), szBuf);
TCHAR szKey[60]; // 60 is enough for CLSID\\{CLSID_XX}
wsprintf(szKey, TEXT("CLSID\\%s"), szBuf);
if (RegOpenKey(HKEY_CLASSES_ROOT, szKey, &hkey)!=ERROR_SUCCESS)
{
DebugMsg(DM_WARNING, TEXT("_GetUserCLSIDKey RegOpenKey(%s) failed"), szKey);
// I don't trust RegOpenKey.
hkey = NULL;
}
}
}
return hkey;
}
BOOL _GetAppHackKey(LPCTSTR pszProgID, DWORD* pdwData)
{
BOOL fSuccess = FALSE;
HKEY hkey;
if (RegOpenKey(HKEY_CLASSES_ROOT, pszProgID, &hkey)==ERROR_SUCCESS)
{
DWORD dwType;
DWORD cbSize = SIZEOF(*pdwData);
if (RegQueryValueEx(hkey, "BrowserFlags", NULL,
&dwType, (LPBYTE)pdwData, &cbSize)==ERROR_SUCCESS
&& (dwType==REG_DWORD || (dwType==REG_BINARY && cbSize==SIZEOF(*pdwData))))
{
fSuccess = TRUE;
}
RegCloseKey(hkey);
}
return fSuccess;
}
void CDocObjectHost::_GetAppHack(void)
{
Assert(_pole);
if (!_fHaveAppHack && _pole)
{
_dwAppHack = 0; // Assume no hack
_fHaveAppHack = TRUE;
HKEY hkey = _GetUserCLSIDKey(_pole);
if (hkey)
{
TCHAR szValue[MAX_PATH];
LONG cb = SIZEOF(szValue);
if (RegQueryValue(hkey, "ProgID", szValue, &cb) == ERROR_SUCCESS)
{
//
// First, check if we have an BrowserFlags flag in the registry.
// If there is, use it. Otherwise, try hard-coded progIDs as
// we did in IE 3.0
//
if (!_GetAppHackKey(szValue, &_dwAppHack)) {
typedef struct _APPHACK {
LPCTSTR pszProgID;
DWORD dwAppHack;
} APPHACK;
const static APPHACK s_aah[] = {
{ "Excel.Sheet.5", BROWSERFLAG_OPENCOPY },
{ "Excel.Chart.5", BROWSERFLAG_OPENCOPY },
{ "SoundRec", BROWSERFLAG_OPENVERB },
{ "Word.Document.6", BROWSERFLAG_SETHOSTNAME },
{ "Word.Document.8", BROWSERFLAG_SETHOSTNAME },
{ "Paint.Picture", BROWSERFLAG_DONTINPLACE },
{ "PowerPoint.Show.8", BROWSERFLAG_DONTUIDEACTIVATE },
{ "Excel.Sheet.8", BROWSERFLAG_DONTUIDEACTIVATE },
{ "Excel.Chart.8", BROWSERFLAG_DONTUIDEACTIVATE },
};
for (int i=0; i<ARRAYSIZE(s_aah); i++) {
if (lstrcmp(szValue, s_aah[i].pszProgID)==0) {
_dwAppHack |= s_aah[i].dwAppHack;
break;
}
}
}
DebugMsg(DM_BINDAPPHACK, TEXT("_GetAppHack ProgID=%s, _dwAppHack=%x"),
szValue, _dwAppHack);
} else {
DebugMsg(DM_BINDAPPHACK, TEXT("_GetAppHack RegQueryValue(ProgID) failed"));
}
RegCloseKey(hkey);
}
}
}
void CDocObjectHost::_PostBindAppHack(void)
{
_GetAppHack();
if (_fAppHackForExcel()) {
_AppHackForExcel95();
}
}
//
// This member binds to the object specified by a moniker.
//
HRESULT CDocObjectHost::_BindSync(IMoniker* pmk, IBindCtx* pbc, IShellView* psvPrev)
{
Assert(pbc || !_pole);
HRESULT hres = S_OK;
#ifdef DEBUG
DWORD dwMksys;
hres = pmk->IsSystemMoniker(&dwMksys);
Assert(SUCCEEDED(hres) && dwMksys!=MKSYS_FILEMONIKER);
#endif
Assert(_pole==NULL);
// Check if we are in the middle of asynchronous binding
if (_bsc._fBinding) {
// Yes, wait until it's done or cancled/stopped
URLMSG(TEXT("_Bind called in the middle of async-binding. Wait in a message loop"));
while(_bsc._fBinding) {
MSG msg;
if (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
if (!_pole) {
hres = E_FAIL; // BUGBUG: Get the error code from OnStopBinding
}
} else {
// No, bind synchronously
URLMSG(TEXT("_Bind. Performing syncronous binding"));
hres = pmk->BindToObject(pbc, NULL, IID_IOleObject, (LPVOID*)&_pole);
}
DebugMsg(0, TEXT("sdv TR : _Bind -- pmk->BindToObject(IOleObject) returned %x"), hres);
_OnBound(hres);
return hres;
}
void CDocObjectHost::_OnBound(HRESULT hres)
{
if (SUCCEEDED(hres)) {
_PostBindAppHack();
_InitOleObject();
}
}
//
// This function returns TRUE if the specified file's open command is
// associated with "explorer.exe" or "iexplore.exe".
//
// NOTES: It does not check if the "open" command is actually the default
// or not, but that's sufficient in 99.99 cases.
//
BOOL IsAssociatedWithIE(LPCSTR szPath)
{
LPCTSTR pszExtension = PathFindExtension(szPath);
HKEY hkey;
BOOL bRet = FALSE;
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CLASSES_ROOT, pszExtension, (DWORD)0, KEY_READ, &hkey))
{
TCHAR szBuf[MAX_PATH];
DWORD dwType, dwcbData;
dwcbData = ARRAYSIZE(szBuf) * sizeof(TCHAR);
if (ERROR_SUCCESS == RegQueryValueEx(hkey, NULL, NULL, &dwType, (LPBYTE)&szBuf, &dwcbData))
{
HKEY hkeyOpen;
lstrcat(szBuf,TEXT("\\shell\\open\\command"));
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CLASSES_ROOT, szBuf, 0, KEY_READ, &hkeyOpen))
{
dwcbData = ARRAYSIZE(szBuf) * sizeof(TCHAR);
if (ERROR_SUCCESS == RegQueryValueEx(hkeyOpen, NULL, NULL, &dwType, (LPBYTE)&szBuf, &dwcbData))
{
DebugMsg(TF_SHDBINDING, "IsAssociatedWithIE(%s) found %s as open command", szPath, szBuf);
LPCSTR pszFound;
if ( (pszFound=StrStrI(szBuf, "iexplore.exe"))
|| (pszFound=StrStrI(szBuf, "explorer.exe")) ) {
if (pszFound==szBuf || *AnsiPrev(szBuf, pszFound)=='\\') {
bRet = TRUE;
}
}
}
RegCloseKey(hkeyOpen);
}
}
RegCloseKey(hkey);
}
DebugMsg(DM_SELFASC, "IsAssociatedWithIE(%s) returning %d", szPath, bRet);
return bRet;
}
BOOL _IsAssociatedWithIE(LPCWSTR pwszFileName)
{
CHAR szPath[MAX_PATH];
WideCharToMultiByte(CP_ACP, 0, pwszFileName, -1, szPath, ARRAYSIZE(szPath), NULL, NULL);
return IsAssociatedWithIE(szPath);
}
#ifdef FEATURE_PICS
UINT CDocObjectHost::_PicsBlockingDialog(LPCSTR pszURL)
{
char szURL[MAX_URL_STRING];
if (pszURL == NULL) {
if (SUCCEEDED(_GetCurrentPage(szURL, sizeof(szURL)))) {
pszURL = szURL;
}
}
_fDrawBackground = TRUE;
/* This message loop is used to block in non-HTML cases, where we really
* want to block the download process until ratings are checked. In the
* HTML case, this function is never called until the wait flags are all
* clear, so the message loop is skipped and we go straight to the denial
* dialog.
*/
while (_fbPicsWaitFlags) {
MSG msg;
if (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
if (!_fPicsAccessAllowed) {
_EnableModeless(FALSE);
HRESULT hres = ::RatingAccessDeniedDialog(_hwnd, NULL, pszURL, _pRatingDetails);
UINT uRet = (hres == S_OK) ? IDOK : IDCANCEL;
_EnableModeless(TRUE);
_fPicsAccessAllowed = (uRet == IDOK);
return uRet;
}
else
return IDOK;
}
#endif
//
// BUGBUG: Should we combine hres and hresT?
//
HRESULT CDocObjectHost::_MayHaveVirus(REFCLSID rclsid)
{
DebugMsg(TF_SHDPROGRESS, TEXT("DOH::_MayHaveVirus called"));
LPWSTR pwzProgID = NULL;
HRESULT hres = S_OK;
HRESULT hresT = ProgIDFromCLSID(rclsid, &pwzProgID);
if (SUCCEEDED(hresT)) {
CHAR szFileClass[MAX_PATH]; // enough for progid
WideCharToMultiByte(CP_ACP, 0, pwzProgID, -1,
szFileClass, ARRAYSIZE(szFileClass), NULL, NULL);
if (lstrcmpi(szFileClass, "htmlfile")!=0)
{
CHAR szURL[MAX_URL_STRING];
hresT = _GetCurrentPage(szURL, ARRAYSIZE(szURL));
if (SUCCEEDED(hresT)) {
#ifdef FEATURE_PICS
UINT uRet = IDOK;
if (_fbPicsWaitFlags) {
_fbPicsWaitFlags &= ~(PICS_WAIT_FOR_INDOC | PICS_WAIT_FOR_END); /* indoc ratings only on htmlfile */
uRet = _PicsBlockingDialog(szURL);
}
if (uRet == IDOK) {
DebugMsg(TF_SHDPROGRESS, TEXT("DOH::_MayHaveVirus calling MayOpenSafeDialogOpenDialog(%s)"), szFileClass);
uRet = MayOpenSafeOpenDialog(_hwnd, szFileClass, szURL);
}
#else
DebugMsg(TF_SHDPROGRESS, TEXT("DOH::_MayHaveVirus calling MayOpenSafeDialogOpenDialog(%s)"), szFileClass);
UINT uRet = MayOpenSafeOpenDialog(_hwnd, szFileClass, szURL);
#endif
switch(uRet) {
case IDOK:
break; // continue download
case IDD_SAVEAS:
CDownLoad_OpenUI(_pmkCur, _bsc._pbc, FALSE, TRUE, NULL);
// fall through to abort binding.
case IDCANCEL:
hres = HRESULT_FROM_WIN32(ERROR_CANCELLED);
break;
}
} else {
DebugMsg(DM_ERROR, TEXT("DOH::_MayHaveVirus _GetCurrentPage failed %x"), hresT);
}
} else {
DebugMsg(TF_SHDPROGRESS, TEXT("DOH::_MayHaveVirus this is htmlfile -- don't call MayOpenSafeDialogOpenDialog"));
#ifdef FEATURE_PICS
_fPicsBlockLate = TRUE;
#endif
}
OleFree(pwzProgID);
} else {
DebugMsg(DM_ERROR, TEXT("DOH::_MayHaveVirus ProgIDFromCLSID failed %x"), hresT);
}
return hres;
}
HRESULT CDocObjectHost::_BindFileMoniker(IMoniker* pmk, IBindCtx* pbc, IShellView* psvPrev)
{
DebugMsg(TF_SHDBINDING, TEXT("CDOH::_BindTileMoniker called"));
HRESULT hres;
#ifdef DEBUG
DWORD dwMksys;
hres = pmk->IsSystemMoniker(&dwMksys);
Assert(SUCCEEDED(hres) && dwMksys==MKSYS_FILEMONIKER);
#endif
#if 0 /* BUGBUG - need correct handling here, including BLANK.HTM */
/* For now, no ratings enforcement on file: objects */
#ifdef FEATURE_PICS
_StartPicsQuery();
#endif
#endif
//
// Associate the client site as an object parameter to this
// bind context so that Trident can pick it up while processing
// IPersistMoniker::Load().
//
pbc->RegisterObjectParam(WSZGUID_OPID_DocObjClientSite,
SAFECAST(this, IOleClientSite*));
//
// We implement our own file moniker binding code for two reasons:
//
// 1. OLE32.DLL in NT-SUR beta-1 has a bug in it.
// 2. We want to call GetClassEx when URLMON exports it to make
// the binding behavior the same as URL Monikers.
//
// hres = pmk->BindToObject(pbc, NULL, IID_IOleObject, (LPVOID*)&_pole);
//
LPWSTR pwszFileName;
hres = pmk->GetDisplayName(pbc, NULL, &pwszFileName);
if (SUCCEEDED(hres)) {
CLSID rclsid;
// Register overriding mime->CLSID mapping
_RegisterMediaTypeClass(pbc);
hres = GetClassFileOrMime(pbc, pwszFileName, NULL, 0,
NULL, 0, &rclsid);
DebugMsg(TF_SHDBINDING, TEXT("CDOH::_BindFileMoniker GetClassFileOrMime returned %x"), hres);
//
// HACK: If Binding failed AND this type is associated with
// iexplore.exe, use our HTMLViewer.
//
if (hres==MK_E_INVALIDEXTENSION || hres==REGDB_E_CLASSNOTREG) {
if (_IsAssociatedWithIE(pwszFileName)) {
rclsid = CLSID_HTMLViewer;
hres = S_OK;
}
}
if (SUCCEEDED(hres)) {
hres = _MayHaveVirus(rclsid);
}
if (SUCCEEDED(hres)) {
IUnknown* punk;
hres = CoCreateInstance(rclsid, NULL, CLSCTX_INPROC_SERVER|CLSCTX_LOCAL_SERVER,
IID_IUnknown, (LPVOID*)&punk);
if (SUCCEEDED(hres)) {
IPersistFile* ppfile;
hres = punk->QueryInterface(IID_IPersistFile, (LPVOID*)&ppfile);
if (SUCCEEDED(hres)) {
BIND_OPTS bindopts;
bindopts.cbStruct = sizeof(BIND_OPTS);
hres = pbc->GetBindOptions(&bindopts);
if (SUCCEEDED(hres)) {
hres = ppfile->Load(pwszFileName, bindopts.grfMode);
if (SUCCEEDED(hres)) {
Assert(NULL==_pole);
hres = punk->QueryInterface(IID_IOleObject, (LPVOID*)&_pole);
} else {
DebugMsg(TF_SHDBINDING, TEXT("CDOH::_BindTileMoniker QI(IOleObject) failed %x"), hres);
}
} else {
DebugMsg(TF_SHDBINDING, TEXT("CDOH::_BindTileMoniker pbc->GetBindOptions failed %x"), hres);
}
ppfile->Release();
} else {
DebugMsg(DM_ERROR, TEXT("CDOH::_BindTileMoniker QI(IPersistFile) failed %x"), hres);
}
punk->Release();
} else {
DebugMsg(DM_ERROR, TEXT("CDOH::_BindTileMoniker CoCreateInst failed %x"), hres);
}
} else {
DebugMsg(DM_ERROR, TEXT("CDOH::_BindTileMoniker GetClassFile failed %x"), hres);
}
OleFree(pwszFileName);
} else {
DebugMsg(TF_SHDBINDING, TEXT("CDOH::_BindTileMoniker _MayHaveVirus failed %x"), hres);
}
pbc->RevokeObjectParam(WSZGUID_OPID_DocObjClientSite);
_OnBound(hres);
return hres;
}
STDMETHODIMP CDocObjectHost::SaveObject(void)
{
DebugMsg(0, TEXT("sdv TR: CDOV::SaveObject called"));
// BUGBUG: Implemente it later.
return S_OK;
}
STDMETHODIMP CDocObjectHost::GetMoniker(DWORD dwAssign,
DWORD dwWhichMoniker,
IMoniker **ppmk)
{
HRESULT hres = E_INVALIDARG;
*ppmk = NULL;
DebugMsg(TF_SHDBINDING, TEXT("CDOH::GetMoniker called dwWhichMoniker=%x"), dwWhichMoniker);
switch(dwWhichMoniker)
{
case OLEWHICHMK_OBJREL:
case OLEWHICHMK_OBJFULL:
if (_pmkCur)
{
*ppmk = _pmkCur;
_pmkCur->AddRef();
hres = S_OK;
}
else
{
hres = E_UNEXPECTED;
}
break;
}
return hres;
}
STDMETHODIMP CDocObjectHost::GetContainer(
IOleContainer **ppContainer)
{
// BUGBUG: According to CKindel, we should implement this method
// as the way for a DocObject to access IDispatch interface of
// the container (i.e., frame). I'm currently thinking leaving
// all it's non-IUnknown memeber unimplemented. If there is no
// need to enumerates objects, we can simply QI from IShellBrowser
// to IOleContainer and return it. (SatoNa)
DebugMsg(0, TEXT("sdv TR: CDOV::GetContainer called"));
return _psb->QueryInterface(IID_IOleContainer, (LPVOID*)ppContainer);
}
STDMETHODIMP CDocObjectHost::ShowObject(void)
{
DebugMsg(0, TEXT("sdv TR: CDOV::ShowObject called"));
return E_NOTIMPL; // As specified in Kraig's document
}
STDMETHODIMP CDocObjectHost::OnShowWindow(BOOL fShow)
{
DebugMsg(TF_SHDUIACTIVATE, TEXT("DOH::OnShowWindow(%d) called (this=%x)"), fShow, this);
return E_NOTIMPL; // As specified in Kraig's document
}
STDMETHODIMP CDocObjectHost::RequestNewObjectLayout(void)
{
DebugMsg(0, TEXT("sdv TR: CDOV::RequestNewObjectLayout called"));
return E_NOTIMPL; // As specified in Kraig's document
}
//
// This is the standard way for non-active embedding to access
// the IHlinkFrame interface. We happened to use our QI to implement
// this, but the semantics of QueryService is different from QI.
// It does not necessary return the same object.
//
HRESULT CDocObjectHost::QueryService(REFGUID guidService, REFIID riid, void **ppvObj)
{
if (IsEqualGUID(guidService, SID_SDocHost)) {
DebugMsg(DM_DOCHOSTUIHANDLER, TEXT("CDOH::QS called with SID_SDocHost"));
return QueryInterface(riid, ppvObj);
}
//
// Delegate ISP to the _psb.
//
if (_psb && _psp)
return _psp->QueryService(guidService, riid, ppvObj);
*ppvObj = NULL;
return E_NOINTERFACE;
}
//
// IOleInPlaceUIWindow::GetBorder
//
HRESULT CDocObjectHost::GetBorder(
/* [out] */ LPRECT lprectBorder)
{
// DebugMsg(0, TEXT("sdv TR: CDOV::GetBorder called"));
if (!_fHaveParentSite) {
GetClientRect(_hwnd, lprectBorder);
} else {
// lie to them and give them lots of space
lprectBorder->left = lprectBorder->top = 0;
lprectBorder->right = 800;
lprectBorder->bottom = 600;
}
return S_OK;
}
//
// IOleInPlaceUIWindow::RequestBorderBorderSpace
//
HRESULT CDocObjectHost::RequestBorderSpace(
/* [unique][in] */ LPCBORDERWIDTHS pbw)
{
HRESULT hres = S_OK;
if (!_fHaveParentSite) {
RECT rcClient;
GetClientRect(_hwnd, &rcClient);
if (pbw->left + pbw->right > rcClient.right/2) {
DebugMsg(0, TEXT("sdv - TR ::RequstBorderSpace return error (more than 50% in width)"));
hres = INPLACE_E_NOTOOLSPACE;
}
else if (pbw->top + pbw->bottom > rcClient.bottom/2) {
DebugMsg(0, TEXT("sdv - TR ::RequstBorderSpace return error (more than 50% in height)"));
hres = INPLACE_E_NOTOOLSPACE;
}
}
DebugMsg(0, TEXT("sdv TR: CDOV::RequestBorderSpace called and returning %x"), hres);
return hres;
}
//
// IOleInPlaceUIWindow::SetBorderSpacve
//
HRESULT CDocObjectHost::SetBorderSpace(
/* [unique][in] */ LPCBORDERWIDTHS pbw)
{
if (!_fHaveParentSite) {
RECT rcClient;
GetClientRect(_hwnd, &rcClient);
// DebugMsg(0, TEXT("sdv TR: CDOV::SetBorderSpace called"));
if (pbw) {
_bwTools = *pbw;
_rcView.left = _bwTools.left;
_rcView.top = _bwTools.top;
_rcView.right = rcClient.right - _bwTools.right;
_rcView.bottom = rcClient.bottom - _bwTools.bottom;
} else {
SetRect(&_bwTools, 0, 0, 0, 0);
}
if (_pmsov)
{
_pmsov->SetRect(&_rcView);
}
} else {
// paranoia... we gave them our parent hwnd to use as the parent for
// client decorations, so this window and the toolbars are now siblings.
// we push ourselves to the top of the zorder so that theydon't overlap us
SetWindowPos(_hwnd, HWND_TOP, 0, 0, 0,0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
}
return S_OK;
}
//
// IOleInPlaceUIWindow::SetActiveObject
//
HRESULT CDocObjectHost::SetActiveObject(
/* [unique][in] */ IOleInPlaceActiveObject *pActiveObject,
/* [unique][string][in] */ LPCOLESTR pszObjName)
{
#ifdef DEBUG
char szObjName[MAX_PATH]; // OK with MAX_PATH
if (pszObjName) {
WideCharToMultiByte(CP_ACP, 0, pszObjName, -1, szObjName, ARRAYSIZE(szObjName), NULL, NULL);
} else {
lstrcpy(szObjName, TEXT("(NULL)"));
}
// As far as the frame support IOleInPlaceUIWindow, we are not supposed to hit
// this code.
DebugMsg(TF_SHDUIACTIVATE, TEXT("DOH::SetActiveObject called with %s, %x (this=%x)"),
szObjName, pActiveObject, this);
#endif
_xao.SetActiveObject(pActiveObject);
return S_OK;
}
/*----------------------------------------------------------
Purpose: Remove the submenu(s) that are in _hmenuTemplate
from _hmenuBrowser.
Returns:
Cond: --
*/
void
CDocObjectHost::_RemoveTemplateSubMenus(void)
{
HMENU hmenu;
ASSERT(_hmenuBrowser);
ASSERT(_hmenuTemplate);
// The file menu in _hmenuBrowser consists of the file menu from
// _hmenuTemplate and IShellBrowser. The part added by _hmenuTemplate
// includes a submenu (Send To), which must be removed before
// _hmenuBrowser is destroyed.
// We could just explicitly remove the Send To submenu. But to
// prevent the expensive bug hunt that it took to find this in the
// first place, we're going to iterate thru the menu and, for
// any submenus that belong to our template, we'll remove them.
int citemFile = 0;
UINT nID = 0;
// Get the count of menu items in our template's File menu and
// the ID of the first menu item.
hmenu = GetMenuFromID(_hmenuTemplate, FCIDM_MENU_FILE);
if (hmenu)
{
citemFile = GetMenuItemCount(hmenu);
nID = GetMenuItemID(hmenu, 0);
}
// Now look at the browser menu's File menu and, starting at
// nID, remove any submenus.
hmenu = GetMenuFromID(_hmenuBrowser, FCIDM_MENU_FILE);
if (hmenu)
{
int citem = GetMenuItemCount(hmenu);
int iTop;
int i;
// Where does our template file menu start?
for (iTop = 0; iTop < citem; iTop++)
{
if (GetMenuItemID(hmenu, iTop) == nID)
{
// Start at where our template file menu ends and work up
for (i = iTop + citemFile - 1; 0 < citemFile ; i--, citemFile--)
{
HMENU hmenuSub = GetSubMenu(hmenu, i);
if (hmenuSub)
RemoveMenu(hmenu, i, MF_BYPOSITION);
}
break;
}
}
}
}
/*----------------------------------------------------------
Purpose: Destroy the browser menu.
Returns:
Cond: --
*/
HRESULT CDocObjectHost::_DestroyBrowserMenu(void)
{
DebugMsg(TF_SHDUIACTIVATE, TEXT("DOH::_DestroyBrowserMenu called"));
if (_hmenuBrowser) {
// First remove any submenus that are held by other menus,
// so we don't blow them away.
_RemoveTemplateSubMenus();
Assert(_psb);
_psb->RemoveMenusSB(_hmenuBrowser);
DestroyMenu(_hmenuBrowser);
_hmenuBrowser = NULL;
}
return S_OK;
}
HRESULT CDocObjectHost::_CreateBrowserMenu(LPOLEMENUGROUPWIDTHS pmw)
{
DebugMsg(TF_SHDUIACTIVATE, TEXT("DOH::_CreateBrowserMenu called"));
HRESULT hres = S_OK;
if (_hmenuBrowser) {
return hres;
}
_hmenuBrowser = CreateMenu();
if (!_hmenuBrowser) {
return E_OUTOFMEMORY;
}
// DebugMsg(0, TEXT("sdv TR: _CreateBrowserMenu calling _psb->InsertMenusSB"));
Assert(_psb);
hres = _psb->InsertMenusSB(_hmenuBrowser, pmw);
// HACK: Win95 explorer returns E_NOTIMPL
if (hres==E_NOTIMPL) {
hres = S_OK;
}
if (SUCCEEDED(hres)) {
// Load our menu if not loaded yet
if (!_hmenuTemplate)
{
_hmenuTemplate = LoadMenu(HINST_THISDLL, MAKEINTRESOURCE(MID_FOCUS));
// DebugMsg(0, TEXT("sdv TR ::InsertMenus loaded _hmenuTemplate"), _hmenuTemplate);
}
// Get the "File" sub-menu from the shell browser.
MENUITEMINFO mii;
char szSubMenu[128];
mii.cbSize = SIZEOF(MENUITEMINFO); // for Win95!
mii.fMask = MIIM_SUBMENU|MIIM_TYPE|MIIM_ID;
mii.fType = MFT_STRING;
mii.cch = ARRAYSIZE(szSubMenu);
mii.dwTypeData = szSubMenu;
mii.dwItemData = 0;
if (GetMenuItemInfo(_hmenuBrowser, FCIDM_MENU_FILE, FALSE, &mii))
{
HMENU hmenuFileBrowse = mii.hSubMenu;
// Merge our menuitems into this submenu.
if (_hmenuTemplate)
{
MENUITEMINFO miiItem;
miiItem.cbSize = SIZEOF(MENUITEMINFO);
miiItem.fMask = MIIM_SUBMENU|MIIM_TYPE;
miiItem.fType = MFT_STRING;
miiItem.cch = 0;
miiItem.dwTypeData = NULL;
miiItem.dwItemData = 0;
if (GetMenuItemInfo(_hmenuTemplate, FCIDM_MENU_FILE, FALSE, &miiItem))
{
char szItem[128];
HMENU hmenuFileT = miiItem.hSubMenu;
UINT citem = GetMenuItemCount(hmenuFileT);
for (int i=citem-1; i>=0 ; i--)
{
// We need to reset for each item.
miiItem.fMask = MIIM_STATE | MIIM_ID | MIIM_SUBMENU | MIIM_CHECKMARKS | MIIM_TYPE | MIIM_DATA;
miiItem.fType = MFT_STRING;
miiItem.cch = ARRAYSIZE(szItem);
miiItem.dwTypeData = szItem;
miiItem.dwItemData = 0;
if (GetMenuItemInfo(hmenuFileT, i, TRUE, &miiItem)) {
InsertMenuItem(hmenuFileBrowse, 0, TRUE, &miiItem);
}
}
}
}
// DebugMsg(0, TEXT("sdv - TR: ::InsertMenus is inserting (%s)"), szSubMenu);
Assert(szSubMenu == mii.dwTypeData);
}
else
{
DebugMsg(TF_SHDUIACTIVATE, TEXT("DOH::_CreateBrowseMenu parent has no File menu (it's probably a browser OC)"));
Assert(0); // DocObject in OC is not supposed to call InsertMenus.
}
}
DEBUG_CODE( _DumpMenus(TEXT("after _CreateBrowserMenu"), TRUE); )
return hres;
}
//
// IOleInPlaceFrame::InsertMenus equivalent
//
HRESULT CDocObjectHost::_InsertMenus(
/* [in] */ HMENU hmenuShared,
/* [out][in] */ LPOLEMENUGROUPWIDTHS lpMenuWidths)
{
HRESULT hres = S_OK;
DebugMsg(TF_SHDUIACTIVATE, TEXT("DOH::InsertMenus called (this=%x)"), this);
// Assume error (no menu merge)
lpMenuWidths->width[0] = 0;
lpMenuWidths->width[2] = 0;
lpMenuWidths->width[4] = 0;
lpMenuWidths->width[5] = 0;
// be extra safe and don't attempt menu merging if we're not top level
if (_fHaveParentSite)
return S_OK;
OLEMENUGROUPWIDTHS mw = { {0} };
hres = _CreateBrowserMenu(&mw);
if (FAILED(hres)) {
DebugMsg(DM_ERROR, TEXT("DOH::InsertMenus _CreateBrpwserMenu failed"));
return hres;
}
// Get the "File" sub-menu from the shell browser.
MENUITEMINFO mii;
char szSubMenu[128];
mii.cbSize = SIZEOF(MENUITEMINFO); // for Win95!
mii.fMask = MIIM_SUBMENU|MIIM_TYPE|MIIM_ID;
mii.fType = MFT_STRING;
mii.cch = ARRAYSIZE(szSubMenu);
mii.dwTypeData = szSubMenu;
mii.dwItemData = 0;
if (GetMenuItemInfo(_hmenuBrowser, FCIDM_MENU_FILE, FALSE, &mii))
{
// DebugMsg(0, TEXT("sdv - TR: ::InsertMenus is inserting (%s)"), szSubMenu);
Assert(szSubMenu == mii.dwTypeData);
InsertMenuItem(hmenuShared, 0, TRUE, &mii);
lpMenuWidths->width[0] = 1;
}
else
{
Assert(0);
}
// Note that we need to re-initialize mii
mii.cbSize = SIZEOF(MENUITEMINFO);
mii.fMask = MIIM_SUBMENU|MIIM_TYPE|MIIM_ID;
mii.fType = MFT_STRING;
mii.cch = ARRAYSIZE(szSubMenu);
mii.dwTypeData = szSubMenu;
mii.dwItemData = 0;
if (GetMenuItemInfo(_hmenuBrowser, FCIDM_MENU_EXPLORE, FALSE, &mii))
{
InsertMenuItem(hmenuShared, 1, TRUE, &mii);
lpMenuWidths->width[4]++;
}
else
{
Assert(0);
}
mii.cbSize = SIZEOF(MENUITEMINFO);
mii.fMask = MIIM_SUBMENU|MIIM_TYPE|MIIM_ID;
mii.fType = MFT_STRING;
mii.cch = ARRAYSIZE(szSubMenu);
mii.dwTypeData = szSubMenu;
mii.dwItemData = 0;
if (GetMenuItemInfo(_hmenuBrowser, FCIDM_MENU_FAVORITES, FALSE, &mii))
{
InsertMenuItem(hmenuShared, 2, TRUE, &mii);
lpMenuWidths->width[4]++;
}
else
{
Assert(0);
}
//
// This block of code allows DocObject to micro-merge the help menu, but
// we can't enable it until MSHTML fixes their menu-merging code.
//
//#ifdef DEBUG // ENABLE_AFTER_FIXING_HTML
if (_hmenuTemplate)
{
mii.cbSize = SIZEOF(MENUITEMINFO);
mii.fMask = MIIM_SUBMENU|MIIM_TYPE|MIIM_ID;
mii.fType = MFT_STRING;
mii.cch = ARRAYSIZE(szSubMenu);
mii.dwTypeData = szSubMenu;
mii.dwItemData = 0;
if (GetMenuItemInfo(_hmenuTemplate, FCIDM_MENU_HELP, FALSE, &mii))
{
InsertMenuItem(hmenuShared, 3, TRUE, &mii);
lpMenuWidths->width[5]++;
}
else
{
Assert(0);
}
}
//#endif // ENABLE_AFTER_FIXING_HTML
DEBUG_CODE( _DumpMenus(TEXT("after InsertMenus"), TRUE); )
return hres;
}
void CDocObjectHost::_CompleteHelpMenuMerge(HMENU hmenu)
{
HMENU hmenuHelp;
MENUITEMINFO mii;
char szSubMenu[80];
mii.cbSize = SIZEOF(MENUITEMINFO);
mii.fMask = MIIM_SUBMENU|MIIM_TYPE|MIIM_ID;
mii.fType = MFT_STRING;
mii.cch = ARRAYSIZE(szSubMenu);
mii.dwTypeData = szSubMenu;
mii.dwItemData = 0;
// see if they added anything to our menu
if (GetMenuItemInfo(_hmenuTemplate, FCIDM_MENU_HELP, FALSE, &mii))
{
hmenuHelp = mii.hSubMenu;
int iMenuCount = GetMenuItemCount(mii.hSubMenu);
// if this changed, then that means they added something
if (iMenuCount != HELP_ITEM_COUNT) {
_hmenuMergedHelp = GetSubMenu(mii.hSubMenu, iMenuCount -1);
goto Bail;
}
// if our menu didn't change, then they didn't merge..
// now find out if they added their own help or if we ARE the help
_hmenuMergedHelp = NULL;
// if it didn't change, then we need to find out if we are the
// only help menu... if we AREN"T, then they added one and we
// need to remove ourselves
int iCount = GetMenuItemCount(hmenu) - 1;
int i;
for (i = iCount ; i >= 0 ; i--) {
mii.cbSize = SIZEOF(MENUITEMINFO);
mii.fMask = MIIM_SUBMENU|MIIM_TYPE|MIIM_ID;
mii.fType = MFT_STRING;
mii.cch = ARRAYSIZE(szSubMenu);
mii.dwTypeData = szSubMenu;
mii.dwItemData = 0;
if (GetMenuItemInfo(hmenu, i, TRUE, &mii)) {
if (mii.hSubMenu == hmenuHelp) {
BOOL bRemove = FALSE;
if (iCount != i) {
// if we're not the last one, then we're not it
bRemove = TRUE;
} else {
// if we are the last one see if the help menu was added
// right before us
char szMenuTitle[80];
mii.cbSize = SIZEOF(MENUITEMINFO);
mii.fMask = MIIM_SUBMENU|MIIM_TYPE|MIIM_ID;
mii.fType = MFT_STRING;
mii.cch = ARRAYSIZE(szMenuTitle);
mii.dwTypeData = szMenuTitle;
mii.dwItemData = 0;
if (GetMenuItemInfo(hmenu, i-1, TRUE, &mii)) {
if (!lstrcmpi(szMenuTitle, szSubMenu)) {
// same menu string yank ours
bRemove = TRUE;
}
}
}
if (bRemove) {
DeleteMenu(hmenu, i, MF_BYPOSITION);
}
}
}
}
}
Bail:;
DEBUG_CODE( _DumpMenus(TEXT("after _CompleteHelpMenuMerge"), TRUE); )
}
//
// IOleInPlaceFrame::SetMenu equivalent
//
HRESULT CDocObjectHost::_SetMenu(
/* [in] */ HMENU hmenuShared,
/* [in] */ HOLEMENU holemenu,
/* [in] */ HWND hwndActiveObject)
{
DebugMsg(TF_SHDUIACTIVATE, TEXT("DOH::SetMenus(%x) called (this=%x)"),
hmenuShared, this);
// be extra safe and don't attempt menu merging if we're not top level
if (_fHaveParentSite)
return S_OK;
if (hmenuShared)
_CompleteHelpMenuMerge(hmenuShared);
// Simply forwarding it to IShellBrowser
_hmenuSet = hmenuShared;
Assert(_psb);
HRESULT hres = _psb->SetMenuSB(hmenuShared, holemenu, hwndActiveObject);
// DebugMsg(0, TEXT("sdv TR - ::SetMenus _psb->SetMenuSB returned %x"), hres);
if (SUCCEEDED(hres))
{
// need to tell the shell browser that we want doc obj style menu merging
if (_pmsoctBrowser)
_pmsoctBrowser->Exec(&CGID_Explorer, SBCMDID_ACTIVEOBJECTMENUS, 0, NULL, NULL);
_hmenuCur = hmenuShared;
HWND hwndFrame;
_psb->GetWindow(&hwndFrame);
hres = OleSetMenuDescriptor(holemenu, hwndFrame, hwndActiveObject, &_dof, _ActiveObject());
// DebugMsg(0, TEXT("sdv TR - ::SetMenu OleSetMenuDesc returned %x"), hres);
}
DEBUG_CODE( _DumpMenus(TEXT("after SetMenu"), TRUE); )
return hres;
}
void CDocObjectHost::_SetStatusText(LPCSTR pszText)
{
if (!_fHaveParentSite) // must protect FCW_STATUS in DefView frameset case
{
if (_psb)
{
WPARAM wParam = 0;
#if defined(WINDOWS_ME) // if we want to be single-binary, remove this ifdef
char szBuf[256];
if ((GetSystemMetrics(SM_MIDEASTENABLED) == TRUE) &&
*pszText)
{
szBuf[0] = szBuf[1] = TEXT('\t');
lstrcpyn(&szBuf[2], pszText, ARRAYSIZE(szBuf)-2);
pszText = szBuf;
wParam = SBT_RTLREADING;
}
#endif
_psb->SendControlMsg(FCW_STATUS, SB_SETTEXT, wParam, (LPARAM)pszText, NULL);
}
}
}
BOOL CDocObjectHost::_IsMenuShared(HMENU hmenu)
{
ASSERT(hmenu);
if (_hmenuBrowser) {
for (int i = GetMenuItemCount(_hmenuBrowser) - 1 ; i >= 0; i--) {
if (GetSubMenu(_hmenuBrowser, i) == hmenu)
return TRUE;
}
}
// We have to special case the help menu. It's possible that the
// help menu in the shared menu actually came from _hmenuTemplate
// (not _hmenuBrowser). We need to detect this case, otherwise
// the help menu gets destroyed but it is still referenced in
// _hmenuTemplate.
MENUITEMINFO mii;
char szSubMenu[80];
mii.cbSize = SIZEOF(MENUITEMINFO);
mii.fMask = MIIM_SUBMENU|MIIM_TYPE|MIIM_ID;
mii.fType = MFT_STRING;
mii.cch = ARRAYSIZE(szSubMenu);
mii.dwTypeData = szSubMenu;
mii.dwItemData = 0;
ASSERT(_hmenuTemplate);
// Is this our help menu from _hmenuTemplate?
if (GetMenuItemInfo(_hmenuTemplate, FCIDM_MENU_HELP, FALSE, &mii) &&
mii.hSubMenu == hmenu)
{
// Yes
return TRUE;
}
return FALSE;
}
//
// IOleInPlaceFrame::RemoveMenus equivalent
//
HRESULT CDocObjectHost::_RemoveMenus(/* [in] */ HMENU hmenuShared)
{
DebugMsg(TF_SHDUIACTIVATE, TEXT("DOH::RemoveMenus called (this=%x)"), this);
// be extra safe and don't attempt menu merging if we're not top level
if (_fHaveParentSite)
return S_OK;
Assert(GetMenuItemCount(hmenuShared) != (UINT)-1);
if (hmenuShared && _pcmSendTo)
ATOMICRELEASE(_pcmSendTo);
//
// It is ok to simply remove sub-menus here.
// because ours are shared with the _hemnuBrowser
// and destroying that below will take care of cleanup.
// however, we need to only remove menus that are ours.
//
for (int i = (int)GetMenuItemCount(hmenuShared) - 1 ; i >= 0; i--)
{
// DebugMsg(0, TEXT("sdv TR - ::RemoveMenus calling RemoveMenu(0)"));
HMENU hmenu = GetSubMenu(hmenuShared, i);
if (_IsMenuShared(hmenu)) {
RemoveMenu(hmenuShared, i, MF_BYPOSITION);
}
}
// DebugMsg(0, TEXT("sdv TR - ::RemoveMenus exiting"));
return S_OK;
}
//
// IOleInPlaceFrame::SetStatusText equivalent
//
HRESULT CDocObjectHost::_SetStatusText(/* [in] */ LPCOLESTR pszStatusText)
{
// Simply forward it.
if (_psb)
return _psb->SetStatusTextSB(pszStatusText);
return S_OK;
}
HRESULT CDocObjectHost::_EnableModeless(/* [in] */ BOOL fEnable)
{
DebugMsg(0, TEXT("sdv TR - ::EnableModeless called"));
// Note that we used call _CancelPendingNavigation here.
// We do it in CBaseBrowser:::EnableModelesSB intead. (Satona)
Assert(_psb);
// Simply forwarding it (BUGBUG: which is not implemented)
return _psb->EnableModelessSB(fEnable);
}
HRESULT CDocObjectHost::TranslateHostAccelerators(LPMSG lpmsg)
{
if (_hacc && ::TranslateAccelerator(_hwnd, _hacc, lpmsg)) {
return S_OK;
}
return S_FALSE;
}
// IOleInPlaceFrame equivalent ::TranslateAccelerator
// Forwarding it from DocObject -> Browser
HRESULT CDocObjectHost::_TranslateAccelerator(
/* [in] */ LPMSG lpmsg,
/* [in] */ WORD wID)
{
// TranslateAccelerator goes to the guy with the focus first
Assert(_psb);
if (S_OK == _psb->TranslateAcceleratorSB(lpmsg, wID))
return S_OK;
#ifdef DEBUG
if (lpmsg->message == WM_KEYDOWN) {
DebugMsg(0, TEXT("CDocObjectHost::TrAcc(UP) called"));
}
#endif
return TranslateHostAccelerators(lpmsg);
}
// IViewObject
HRESULT CDocObjectHost::Draw(DWORD dwDrawAspect, LONG lindex, void *pvAspect,
DVTARGETDEVICE *ptd, HDC hicTargetDev, HDC hdcDraw,
const RECTL *lprcBounds, const RECTL *lprcWBounds,
BOOL (*pfnContinue)(DWORD), DWORD dwContinue)
{
if (_pvo)
{
return _pvo->Draw(dwDrawAspect, lindex, pvAspect, ptd, hicTargetDev,
hdcDraw, lprcBounds, lprcWBounds, pfnContinue, dwContinue);
}
return OLE_E_BLANK;
}
HRESULT CDocObjectHost::GetColorSet(DWORD dwAspect, LONG lindex,
void *pvAspect, DVTARGETDEVICE *ptd, HDC hicTargetDev,
LOGPALETTE **ppColorSet)
{
if (_pvo)
{
return _pvo->GetColorSet(dwAspect, lindex, pvAspect, ptd, hicTargetDev,
ppColorSet);
}
if (ppColorSet)
*ppColorSet = NULL;
return S_FALSE;
}
HRESULT CDocObjectHost::Freeze(DWORD, LONG, void *, DWORD *pdwFreeze)
{
if (pdwFreeze)
*pdwFreeze = 0;
return E_NOTIMPL;
}
HRESULT CDocObjectHost::Unfreeze(DWORD)
{
return E_NOTIMPL;
}
HRESULT CDocObjectHost::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)
{
if (_padvise) {
ATOMICRELEASE(_padvise);
}
_padvise = pSink;
if (_padvise)
_padvise->AddRef();
}
if (_padvise)
{
_advise_aspect = dwAspect;
_advise_advf = advf;
if (advf & ADVF_PRIMEFIRST)
OnViewChange(_advise_aspect, -1);
}
else
_advise_aspect = _advise_advf = 0;
return S_OK;
}
HRESULT CDocObjectHost::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;
}
// IAdviseSink
void CDocObjectHost::OnDataChange(FORMATETC *, STGMEDIUM *)
{
}
void CDocObjectHost::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 CDocObjectHost::OnRename(IMoniker *)
{
}
void CDocObjectHost::OnSave()
{
}
void CDocObjectHost::OnClose()
{
//
// the doc object below went away so tell our advisee something changed
//
if (_padvise)
OnViewChange(_advise_aspect, -1);
}
// IOleWindow
HRESULT CDocObjectHost::GetWindow(HWND * lphwnd)
{
*lphwnd = _hwnd;
return S_OK;
}
HRESULT CDocObjectHost::ContextSensitiveHelp(BOOL fEnterMode)
{
// NOTES: This is optional
return E_NOTIMPL; // As specified in Kraig's document (optional)
}
// IOleInPlaceSite
HRESULT CDocObjectHost::CanInPlaceActivate(void)
{
OIPSMSG(TEXT("CanInPlaceActivate called"));
return S_OK;
}
HRESULT CDocObjectHost::OnInPlaceActivate(void)
{
OIPSMSG(TEXT("OnInPlaceActivate called"));
return S_OK;
}
HRESULT CDocObjectHost::OnUIActivate( void)
{
DebugMsg(TF_SHDUIACTIVATE, TEXT("----------------------------------"));
DebugMsg(TF_SHDUIACTIVATE, TEXT("DOH::OnUIActivate called (this=%x)"), this);
//
// Hide Office toolbars early enough so that it won't flash.
//
_HideOfficeToolbars();
// REVIEW:
// Should we remove 'our' menu here instead?
//
// [Copied from OLE 2.01 Spec]
// The container should remove any UI associated with its own
// activation. This is significant if the container is itself
// an embedded object.
//
OIPSMSG(TEXT("OnUIActivate called"));
Assert(_psb);
// If we had the DocObject in SVUIA_INPLACEACTIVATE send it to SVUIA_ACTIVATE_FOCUS
_psv->UIActivate(SVUIA_ACTIVATE_FOCUS);
return _psb->OnViewWindowActive(_psv);
}
void CDocObjectHost::_GetClipRect(RECT* prc)
{
GetClientRect(_hwnd, prc);
prc->right -= _bwTools.right;
prc->bottom -= _bwTools.bottom;
}
IOleInPlaceSite* CDocObjectHost::_GetParentSite()
{
IOleInPlaceSite* pparentsite = NULL; // the parent's inplace site
if (_pwb) {
_pwb->GetParentSite(&pparentsite);
}
return pparentsite;
}
HRESULT CDocObjectHost::GetWindowContext(
/* [out] */ IOleInPlaceFrame **ppFrame,
/* [out] */ IOleInPlaceUIWindow **ppDoc,
/* [out] */ LPRECT lprcPosRect,
/* [out] */ LPRECT lprcClipRect,
/* [out][in] */ LPOLEINPLACEFRAMEINFO lpFrameInfo)
{
OIPSMSG(TEXT("GetWindowContext called"));
// BUGBUG: verify that lpFrameInfo->cb is the correct size!
// DebugMsg(0, TEXT("sdv TR - ::GetWindowContext called with lpFI->cb=%d (%d)"),
// lpFrameInfo->cb, sizeof(*lpFrameInfo));
*ppFrame = &_dof; AddRef();
*ppDoc = NULL; // indicating that doc window == frame window
_GetClipRect(lprcClipRect);
lpFrameInfo->fMDIApp = FALSE;
//
// If the frame has IOleInPlaceUIWindow (both IE and Shell have),
// return that hwnd as hwndFrame so that OLE's menu dispatching
// code works correctly.
//
// NOTE: _dof.GetWindow checks for _pipu as well, so this is code bloat
//
if (_pipu) {
_pipu->GetWindow(&lpFrameInfo->hwndFrame);
} else {
_dof.GetWindow(&lpFrameInfo->hwndFrame);
}
//
// BUGBUG: We need to find out (from SriniK or KraigB), what is the
// implecation of this accelerator. Dealing with Word, it seems that
// Word does not call our TranslateAccelerator at all, unless the key
// stroke is the accelerator. If that's the spec. (of DocObject),
// there is no way to process the accelerator of the browser.
//
lpFrameInfo->haccel = _hacc; // BUGBUG
#ifdef DEBUG
lpFrameInfo->cAccelEntries = 6; // WARNING: see shdocvw.rc, ACCELL_DOCVIEW
#else
lpFrameInfo->cAccelEntries = 5; // WARNING: see shdocvw.rc, ACCELL_DOCVIEW
#endif
*lprcPosRect = _rcView;
return S_OK;
}
HRESULT CDocObjectHost::Scroll(
/* [in] */ SIZE scrollExtant)
{
DebugMsg(0, TEXT("sdv TR - ::Scroll called"));
return E_NOTIMPL; // As specified in Kraig's document
}
HRESULT CDocObjectHost::OnUIDeactivate(
/* [in] */ BOOL fUndoable)
{
DebugMsg(TF_SHDUIACTIVATE, TEXT("DOH::OnUIDeactivate called (this=%x)"), this);
if (_hmenuSet) {
OIPSMSG(TEXT("OnUIDeactivate We need to SetMenu(NULL, NULL, NULL)"));
_SetMenu(NULL, NULL, NULL);
}
return S_OK;
}
HRESULT CDocObjectHost::OnInPlaceDeactivate( void)
{
OIPSMSG(TEXT("OnInPlaceDeactivate called"));
// BUGBUG: Not implemented
return S_OK;
}
HRESULT CDocObjectHost::DiscardUndoState( void)
{
DebugMsg(0, TEXT("sdv TR - ::DiscardUndoState called"));
return S_OK;
}
HRESULT CDocObjectHost::DeactivateAndUndo( void)
{
DebugMsg(0, TEXT("sdv TR - ::DeactivateAndUndo called"));
return S_OK;
}
HRESULT CDocObjectHost::OnPosRectChange(
/* [in] */ LPCRECT lprcPosRect)
{
return E_NOTIMPL; // As specified in Kraig's document
}
void CDocObjectHost::_OnNotify(LPNMHDR lpnm)
{
switch(lpnm->code) {
case TTN_NEEDTEXT:
#define pnmTT ((LPTOOLTIPTEXT)lpnm)
LoadString(HINST_THISDLL, IDS_TOOLTIP_OF(pnmTT->hdr.idFrom), pnmTT->szText, ARRAYSIZE(pnmTT->szText));
break;
case TBN_BEGINDRAG:
#define ptbn ((LPTBNOTIFY)lpnm)
_OnMenuSelect(ptbn->iItem, 0, NULL);
break;
}
}
void CDocObjectHost::_CreateShortcutOnDesktop(void)
{
HRESULT hres;
Assert(_pwb);
if (_pwb && ShellMessageBox(HINST_THISDLL, _hwnd, MAKEINTRESOURCE(IDS_CREATE_SHORTCUT_MSG),
MAKEINTRESOURCE(IDS_TITLE), MB_OKCANCEL) == IDOK)
{
INavigationStackItem *pnsi;
hres = _pwb->GetNavigationStackItem(_psv, &pnsi);
if (SUCCEEDED(hres))
{
LPITEMIDLIST pidl;
hres = pnsi->GetPidl(&pidl);
if (SUCCEEDED(hres))
{
TCHAR szPath[MAX_PATH];
if (SHGetSpecialFolderPath(NULL, szPath, CSIDL_DESKTOPDIRECTORY, TRUE))
{
TCHAR szName[MAX_URL_STRING];
IEGetDisplayName(pidl, szName, SHGDN_INFOLDER);
hres = CreateShortcutInDir(pidl, PathFindFileName(szName), szPath, NULL, FALSE);
AssertMsg(SUCCEEDED(hres), TEXT("CDOH::_CSOD CreateShortcutInDir failed %x"), hres);
}
else
{
DebugMsg(DM_ERROR, TEXT("CDOH::_CSOD SHGetSFP(DESKTOP) failed %x"), hres);
}
ILFree(pidl);
}
else
{
DebugMsg(DM_ERROR, TEXT("CDOH::_CSOD pnsi->GetPidl failed %x"), hres);
}
pnsi->Release();
}
else
{
DebugMsg(DM_ERROR, TEXT("CDOH::_CSOD _pwb->GetNSI failed %x"), hres);
}
}
}
void EnableOKButton(HWND hDlg)
{
TCHAR szText[MAX_PATH];
GetDlgItemText(hDlg, IDD_COMMAND, szText, ARRAYSIZE(szText));
EnableWindow(GetDlgItem(hDlg, IDOK), (BOOL)szText[0]);
}
void MapAtToNull(LPTSTR psz)
{
while (*psz)
{
if (*psz == TEXT('@'))
{
LPTSTR pszNext = CharNext(psz);
*psz = 0;
psz = pszNext;
}
else
{
psz = CharNext(psz);
}
}
}
void BrowsePushed(HWND hDlg)
{
TCHAR szText[MAX_PATH];
TCHAR szFilter[MAX_PATH];
// load the filter and then replace all the @ characters with NULL. The end of the string will be doubly
// null-terminated
LoadString(HINST_THISDLL, IDS_BROWSEFILTER, szFilter, ARRAYSIZE(szFilter));
MapAtToNull(szFilter);
GetDlgItemText(hDlg, IDD_COMMAND, szText, ARRAYSIZE(szText));
PathUnquoteSpaces(szText);
// skip the "file://" stuff
LPCTSTR pcszPath = PathSkipFileSchemeGoo(szText, NULL);
if (pcszPath != szText)
lstrcpy(szText, pcszPath);
if (GetFileNameFromBrowse(hDlg, szText, ARRAYSIZE(szText), NULL,
TEXT(".htm"), szFilter, MAKEINTRESOURCE(IDS_TITLE)))
{
PathUnquoteSpaces(szText);
SetDlgItemText(hDlg, IDD_COMMAND, szText);
EnableOKButton(hDlg);
// place the focus on OK
SendMessage(hDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hDlg, IDOK), TRUE);
}
}
struct SOpenDlg {
WCHAR wszURL[MAX_URL_STRING];
};
const DWORD aRunHelpIds[] = {
IDD_ICON, NO_HELP,
IDD_PROMPT, NO_HELP,
IDD_RUNDLGOPENPROMPT, IDH_IE_RUN_COMMAND,
IDD_COMMAND, IDH_IE_RUN_COMMAND,
IDD_BROWSE, IDH_RUNBROWSE,
0, 0
};
BOOL OpenBox_InsertURL(HWND hwndCombo, LPTSTR pszURL)
{
TCHAR szTopAddress[MAX_URL_STRING + 1];
ComboBox_GetLBText(hwndCombo, 0, szTopAddress);
IURLQualify(pszURL, TRANSLATEURL_FL_GUESS_PROTOCOL | TRANSLATEURL_FL_USE_DEFAULT_PROTOCOL,
pszURL);
if (lstrcmpi(szTopAddress, pszURL))
{
ComboBox_InsertString(hwndCombo, 0, pszURL);
return TRUE;
}
return FALSE;
}
void OpenDlgOnOK(HWND hDlg, SOpenDlg * podlg)
{
Assert(podlg);
HWND hWndOpenBox = GetDlgItem(hDlg, IDD_COMMAND);
#ifdef UNICODE
ComboBox_GetText(hWndOpenBox, podlg->wszURL, ARRAYSIZE(podlg->wszURL));
if (OpenBox_InsertURL(hWndOpenBox, podlg->wszURL))
SaveHistoryList(hWndOpenBox);
#else
{
char szText[MAX_URL_STRING];
ComboBox_GetText(hWndOpenBox, szText, ARRAYSIZE(szText));
MultiByteToWideChar(CP_ACP, 0, szText, -1,
podlg->wszURL, ARRAYSIZE(podlg->wszURL));
if (OpenBox_InsertURL(hWndOpenBox, szText))
SaveHistoryList(hWndOpenBox);
}
#endif
}
BOOL CALLBACK CDocObjectHost::s_RunDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
SOpenDlg* podlg = (SOpenDlg*)GetWindowLong(hDlg, DWL_USER);
switch (uMsg)
{
case WM_INITDIALOG:
{
Assert(lParam);
HWND hWndOpenBox = GetDlgItem(hDlg, IDD_COMMAND);
SetWindowLong(hDlg, DWL_USER, lParam);
InitHistoryList(hWndOpenBox);
CHAR szCurrentURL[MAX_URL_STRING];
SOpenDlg * podlgInit = (SOpenDlg *)lParam;
int nConverted = 0;
if (podlgInit->wszURL[0])
nConverted = WideCharToMultiByte(CP_ACP, 0, podlgInit->wszURL, -1,
szCurrentURL, ARRAYSIZE(szCurrentURL), NULL, NULL);
int icb = CB_ERR;
if (nConverted)
{
IURLQualify(szCurrentURL, TRANSLATEURL_FL_GUESS_PROTOCOL | TRANSLATEURL_FL_USE_DEFAULT_PROTOCOL,
szCurrentURL);
icb = ComboBox_FindStringExact(hWndOpenBox, 0, szCurrentURL);
if (icb == CB_ERR)
OpenBox_InsertURL(hWndOpenBox, szCurrentURL);
}
if (ComboBox_GetCount(hWndOpenBox) > 0)
EnableWindow(GetDlgItem(hDlg, IDOK), (ComboBox_SetCurSel(hWndOpenBox, (icb == CB_ERR) ? 0 : icb) != -1));
else
EnableWindow(GetDlgItem(hDlg, IDOK), FALSE);
break;
}
case WM_HELP:
WinHelp((HWND) ((LPHELPINFO) lParam)->hItemHandle, c_szHelpFile, HELP_WM_HELP,
(DWORD) (LPTSTR) aRunHelpIds);
break;
case WM_CONTEXTMENU: // right mouse click
WinHelp((HWND) wParam, c_szHelpFile, HELP_CONTEXTMENU,
(DWORD) (LPTSTR) aRunHelpIds);
break;
case WM_COMMAND:
switch (GET_WM_COMMAND_ID(wParam, lParam))
{
case IDHELP:
break;
case IDD_BROWSE:
BrowsePushed(hDlg);
break;
case IDD_COMMAND:
switch (GET_WM_COMMAND_CMD(wParam, lParam))
{
case CBN_SELCHANGE:
break;
case CBN_EDITCHANGE:
case CBN_SELENDOK:
EnableOKButton(hDlg);
break;
}
break;
case IDOK:
OpenDlgOnOK(hDlg, podlg);
case IDCANCEL:
EndDialog(hDlg, GET_WM_COMMAND_ID(wParam, lParam));
break;
default:
return FALSE;
}
break;
default:
return FALSE;
}
return TRUE;
}
void CDocObjectHost::_Navigate(LPCWSTR pwszURL)
{
Assert(_psb);
IServiceProvider* psp = NULL;
HRESULT hresT = _psb->QueryInterface(IID_IServiceProvider, (LPVOID*)&psp);
if (SUCCEEDED(hresT))
{
Assert(psp);
IWebBrowserApp* pdie;
hresT = psp->QueryService(SID_SContainerDispatch, IID_IWebBrowserApp, (LPVOID*)&pdie);
if (SUCCEEDED(hresT)) {
//
// HACK: We are not passing BSTR, but LPWSTR, which
// will work as far as IWebBrowserApp can handle
// NULL-terminated string correctly.
//
pdie->Navigate((BSTR)pwszURL, NULL, NULL, NULL, NULL);
pdie->Release();
}
psp->Release();
}
}
void CDocObjectHost::_OnOpen(void)
{
HWND hwndFrame;
_psb->GetWindow(&hwndFrame);
// Get the current URL site and put it in odlg.wszURL
SOpenDlg odlg;
LPOLESTR pszDisplayName;
HRESULT hr = _GetCurrentPageW(&pszDisplayName);
StrCpyW(odlg.wszURL, pszDisplayName);
OleFree(pszDisplayName);
if (FAILED(hr))
odlg.wszURL[0] = 0;
// BUGBUG: Make it a helper member, which notifies up and down.
_psb->EnableModelessSB(FALSE);
UINT iRet = DialogBoxParam(HINST_THISDLL, MAKEINTRESOURCE(DLG_RUN), hwndFrame,
(DLGPROC)s_RunDlgProc, (LPARAM)&odlg);
_psb->EnableModelessSB(TRUE);
if (iRet==IDOK)
{
_Navigate(odlg.wszURL);
}
}
UINT CALLBACK DocHostSaveAsOFNHook(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_INITDIALOG:
{
/* Hide the "Save as Type" text box */
CommDlg_OpenSave_HideControl(GetParent(hDlg), stc2);
/* Hide the listbox with save type extensions */
CommDlg_OpenSave_HideControl(GetParent(hDlg), cmb1);
/* Hide the Open as read-only control */
CommDlg_OpenSave_HideControl(GetParent(hDlg), chx1);
break;
}
default:
break;
}
return FALSE;
}
void CDocObjectHost::_OnHelpGoto(UINT idRes)
{
WCHAR wszURL[MAX_PATH]; // this is enough for our own
_LoadStringW(HINST_THISDLL, idRes, wszURL, ARRAYSIZE(wszURL));
_Navigate(wszURL);
}
const DWORD g_mapCtrlToContextIds[] = { 0, 0 };
STDAPI_(void) IEAboutBox( HWND hWnd );
// WM_COMMAND from _WndProc - execs are going down
void CDocObjectHost::_OnCommand(UINT wNotify, UINT id, HWND hwndControl)
{
switch(id)
{
case IDM_HELPTUTORIAL:
_OnHelpGoto(IDS_HELPTUTORIAL);
break;
case IDM_HELPABOUT:
IEAboutBox( _hwnd );
break;
case IDM_HELPSEARCH:
WinHelp(_hwnd, c_szHelpFile, HELP_FINDER, (DWORD)(LPSTR)g_mapCtrlToContextIds);
break;
case IDM_DHFAVORITES:
_pmsoctBrowser->Exec(&CGID_Explorer, SBCMDID_ADDTOFAVORITES, TRUE, NULL, NULL);
break;
case IDM_GOHOME:
case IDM_GOSEARCH:
{
TCHAR szPath[MAX_URL_STRING];
LPITEMIDLIST pidl;
HRESULT hres = SHDGetPageLocation(_hwnd,
(id==IDM_GOSEARCH) ? IDP_SEARCH : IDP_START,
szPath, ARRAYSIZE(szPath), &pidl);
if (SUCCEEDED(hres))
{
_psb->BrowseObject(pidl, SBSP_ABSOLUTE | SBSP_SAMEBROWSER);
ILFree(pidl);
}
else
{
TCHAR szMessage[256];
BOOL fSuccess = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
NULL, hres, 0, szMessage, ARRAYSIZE(szMessage), (va_list *)&szPath);
if (!fSuccess)
szMessage[0] = 0;
ShellMessageBox(HINST_THISDLL, _hwnd,
MAKEINTRESOURCE(IDS_CANTACCESSDOCUMENT),
szPath, MB_OK | MB_SETFOREGROUND | MB_ICONSTOP, szMessage);
}
}
break;
case IDM_STOPDOWNLOAD:
// We need to tell the container to cancel a pending navigation
// if any. Notice that the Cancel button serves for two purposes:
// (1) canceling a pending navigation
// (2) cancel any downloading
if (_psb)
_CancelPendingNavigation();
goto TryDocument;
case IDM_ZOOMIN:
if (_pmsot) {
if (_iZoom < _iZoomMax) {
VARIANTARG var;
VariantInit(&var);
var.vt = VT_I4;
var.lVal = _iZoom + 1;
_pmsot->Exec(NULL, OLECMDID_ZOOM, OLECMDEXECOPT_DONTPROMPTUSER, &var, NULL);
}
}
break;
case IDM_ZOOMOUT:
if (_pmsot) {
if (_iZoom > _iZoomMin) {
VARIANTARG var;
VariantInit(&var);
var.vt = VT_I4;
var.lVal = _iZoom - 1;
_pmsot->Exec(NULL, OLECMDID_ZOOM, OLECMDEXECOPT_DONTPROMPTUSER, &var, NULL);
}
}
break;
case IDM_CREATESHORTCUT:
_CreateShortcutOnDesktop();
break;
case IDM_NEWWINDOW:
_psb->BrowseObject(&s_idNull, SBSP_RELATIVE|SBSP_NEWBROWSER);
break;
case IDM_OPEN:
_OnOpen();
break;
case IDM_SAVE:
_OnSave();
break;
case IDM_NEWMESSAGE:
DropOnMailRecipient(NULL, FALSE);
break;
case IDM_SAVEASFILE:
//
// Handle the case where DocObject does not support "SaveAs"
// and we have enabled the menuitem anyway.
//
if (_pmsot)
{
OLECMD rgcmds[] = { { OLECMDID_SAVEAS, 0 }, };
_pmsot->QueryStatus(NULL, ARRAYSIZE(rgcmds), rgcmds, NULL);
if (!(rgcmds[0].cmdf & OLECMDF_ENABLED))
_OnSaveAs();
else
goto TryDocument;
}
break;
default:
if (IsInRange(id, IDM_HELPMSWEB, IDM_HELPMSWEBLAST))
{
_OnHelpGoto(IDS_HELPMSWEB + (id - IDM_HELPMSWEB));
}
else if (IsInRange(id, IDM_SENDTOFIRST, IDM_SENDTOLAST))
{
Assert(_pcmSendTo);
CMINVOKECOMMANDINFO ici = {
sizeof(CMINVOKECOMMANDINFO),
0,
_hwnd,
MAKEINTRESOURCE(id - IDM_SENDTOFIRST),
NULL,
NULL,
SW_SHOWNORMAL
};
_pcmSendTo->InvokeCommand(&ici);
}
else
{
TryDocument:
if (_pmsot)
{
// Check if we need to call object's Exec.
UINT idMso = _MapToMso(id);
if (idMso != (UINT)-1)
{
// Yes. Call it.
_pmsot->Exec(NULL, idMso, OLECMDEXECOPT_PROMPTUSER, NULL, NULL);
}
else if (id == IDM_PRINTFRAME)
{
_pmsot->Exec(&CGID_ShellDocView, SHDVID_PRINTFRAME, OLECMDEXECOPT_PROMPTUSER, NULL, NULL);
}
}
}
break;
}
}
void CDocObjectHost::_OnSaveAs(void)
{
DebugMsg(DM_SAVEASHACK, TEXT("DOH::_OnSaveAs called"));
TCHAR szSaveTo[MAX_PATH]; // ok with MAX_PATH
LoadString(HINST_THISDLL, IDS_DOCUMENT, szSaveTo, ARRAYSIZE(szSaveTo));
TCHAR szDesktop[MAX_PATH];
SHGetSpecialFolderPath(_hwnd, szDesktop, CSIDL_DESKTOPDIRECTORY, FALSE);
OPENFILENAME OFN;
OFN.lStructSize = sizeof(OPENFILENAME);
OFN.hwndOwner = _hwnd;
OFN.lpstrFileTitle = 0;
OFN.nMaxCustFilter = 0;
OFN.nFilterIndex = 0;
OFN.nMaxFile = ARRAYSIZE(szSaveTo);
OFN.lpfnHook = DocHostSaveAsOFNHook;
OFN.Flags = 0L;/* for now, since there's no readonly support */
OFN.lpstrTitle = NULL;
OFN.lpstrInitialDir = szDesktop;
OFN.lpstrFile = szSaveTo;
OFN.Flags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_ENABLEHOOK | OFN_EXPLORER |
OFN_NOREADONLYRETURN | OFN_PATHMUSTEXIST;
OFN.lpstrFilter = NULL;
OFN.lpstrCustomFilter = NULL;
OFN.lpstrDefExt = TEXT(""); // no extension
TCHAR szValue[MAX_PATH+1]; // +1 for for double-null
TCHAR szExt[40];
Assert(_pole);
HKEY hkey = _GetUserCLSIDKey(_pole);
if (hkey)
{
LONG cb = SIZEOF(szValue);
if (RegQueryValue(hkey, TEXT("DefaultExtension"), szValue, &cb) == ERROR_SUCCESS)
{
DebugMsg(DM_SAVEASHACK, TEXT("DOH::_OnSaveAs DefExt is %s"), szValue);
// It is suposed to be like ".xls, Excel Workbook (*.xls)"
if (szValue[0]==TEXT('.')) {
lstrcpyn(szExt, szValue+1, ARRAYSIZE(szExt));
LPSTR pszEnd = StrChr(szExt, TEXT(','));
if (pszEnd) {
*pszEnd = 0;
}
OFN.lpstrDefExt = szExt;
OFN.lpstrFilter = szValue;
OFN.Flags &= ~OFN_ENABLEHOOK;
DebugMsg(DM_SAVEASHACK, TEXT("DOH::_OnSaveAs OFN.lpstrDefExt is %s"), OFN.lpstrDefExt);
}
}
}
if (GetSaveFileName(&OFN)) {
IPersistFile* ppf;
Assert(_pole);
HRESULT hresT = _pole->QueryInterface(IID_IPersistFile, (LPVOID*)&ppf);
if (SUCCEEDED(hresT)) {
DebugMsg(DM_APPHACK, TEXT("APPHACK DOH SaveAs'ing to %s"), szSaveTo);
WCHAR wszSaveTo[MAX_PATH]; // ok with MAX_PATH
MultiByteToWideChar(CP_ACP, 0, szSaveTo, -1,
wszSaveTo, ARRAYSIZE(wszSaveTo));
ppf->Save(wszSaveTo, FALSE);
ppf->Release();
} else {
Assert(0);
}
}
}
// Mail Recipient drop target implementation...
// {9E56BE60-C50F-11CF-9A2C-00A0C90A90CE}
const GUID CLSID_MailRecipient = { 0x9E56BE60L, 0xC50F, 0x11CF, 0x9A, 0x2C, 0x00, 0xA0, 0xC9, 0x0A, 0x90, 0xCE };
// from sendto.cpp
HRESULT SimulateDrop(IDataObject *pdtobj, IDropTarget *pdrop, BOOL fCopy);
HRESULT DropOnMailRecipient(IDataObject *pdtobj, BOOL fCopy)
{
IDropTarget *pdrop;
HRESULT hres = CoCreateInstance(CLSID_MailRecipient,
NULL, CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER,
IID_IDropTarget, (void**)&pdrop);
if (SUCCEEDED(hres))
hres = SimulateDrop(pdtobj, pdrop, fCopy);
pdrop->Release();
return hres;
}
HRESULT _GetDataObjectForPidl(LPCITEMIDLIST pidl, IDataObject ** ppdtobj)
{
if (pidl)
{
IShellFolder *psfParent;
LPCITEMIDLIST pidlChild;
HRESULT hres = BindToParentFolder(pidl, &psfParent, &pidlChild);
if (SUCCEEDED(hres))
{
hres = psfParent->GetUIObjectOf(NULL, 1, &pidlChild, IID_IDataObject, NULL, (void**)ppdtobj);
psfParent->Release();
}
return hres;
}
return E_FAIL;
}
HRESULT SendDocToMailRecipient(LPCITEMIDLIST pidl, BOOL fCopy)
{
IDataObject *pdtobj;
HRESULT hres = _GetDataObjectForPidl(pidl, &pdtobj);
if (SUCCEEDED(hres))
{
hres = DropOnMailRecipient(pdtobj, fCopy);
pdtobj->Release();
}
return hres;
}
IContextMenu2 * GetSendToMenu(IBrowserService * pbs, IShellView * psv, HMENU hmInit)
{
IContextMenu2 * pcm = NULL;
HRESULT hres = CoCreateInstance(CLSID_SendToMenu, NULL, CLSCTX_INPROC_SERVER, IID_IContextMenu2, (LPVOID*)&pcm);
if (SUCCEEDED(hres))
{
IShellExtInit *psei;
hres = pcm->QueryInterface(IID_IShellExtInit, (void**)&psei);
if (SUCCEEDED(hres))
{
INavigationStackItem *pnsi;
hres = pbs->GetNavigationStackItem(psv, &pnsi);
if (SUCCEEDED(hres))
{
LPITEMIDLIST pidl;
hres = pnsi->GetPidl(&pidl);
if (SUCCEEDED(hres))
{
IDataObject *pdtobj;
hres = _GetDataObjectForPidl(pidl, &pdtobj);
if (SUCCEEDED(hres))
{
psei->Initialize(NULL, pdtobj, NULL);
// BUGBUG: hard coded menu offset
pcm->QueryContextMenu(hmInit, 6, IDM_SENDTOFIRST, IDM_SENDTOLAST, 0);
pdtobj->Release();
}
ILFree(pidl);
}
pnsi->Release();
}
psei->Release();
}
}
return pcm;
}
void CDocObjectHost::_OnInitMenuPopup(HMENU hmInit, int nIndex, BOOL fSystemMenu)
{
if (!_hmenuCur)
return;
MENUITEMINFO mii;
mii.cbSize = SIZEOF(MENUITEMINFO);
mii.fMask = MIIM_SUBMENU|MIIM_ID;
mii.cch = 0; // just in case
if (GetMenuFromID(_hmenuCur, FCIDM_MENU_FILE) == hmInit)
{
if (_uState != SVUIA_ACTIVATE_FOCUS)
return;
if (_pmsot)
{
DebugMsg(0, TEXT("sdv TR _OnInitMenuPopup : step 5"));
OLECMD rgcmds[] = {
{ OLECMDID_PRINT, 0 },
{ OLECMDID_PAGESETUP, 0 },
{ OLECMDID_PROPERTIES, 0 },
{ OLECMDID_SAVE, 0 },
{ OLECMDID_SAVEAS, 0 },
{ OLECMDID_PRINTPREVIEW, 0 },
};
_pmsot->QueryStatus(NULL, ARRAYSIZE(rgcmds), rgcmds, NULL);
// Adding a comment for my sanity: we use SHDVID_PRINTFRAME instead
// of OLECMDID_PRINT because IE40 is going to support the printing
// of entire framesets, instead of the current behavior or forwarding
// the command to the active frame.
//
OLECMD rgcmds1[] = {
{ SHDVID_PRINTFRAME, 0 },
};
_pmsot->QueryStatus(&CGID_ShellDocView, ARRAYSIZE(rgcmds1), rgcmds1, NULL);
//
// If OLECMDID_SAVEAS is not supported (neither ENABLED nor
// SUPPORTED is set) by the DocObject, check if the object
// support IPersistFile. If it does, enable it. Note that
// this mechanism allows the DocObject to disable this menu
// item (by setting only OLECMDF_SUPPORTED). (SatoNa)
//
Assert(rgcmds[4].cmdID == OLECMDID_SAVEAS);
if (!(rgcmds[4].cmdf & (OLECMDF_ENABLED | OLECMDF_SUPPORTED)))
{
IPersistFile* ppf;
Assert(_pole);
HRESULT hresT = _pole->QueryInterface(IID_IPersistFile, (LPVOID*)&ppf);
if (SUCCEEDED(hresT))
{
DebugMsg(DM_APPHACK, TEXT("APPHACK DOH Enabling SaveAs menu for Excel95"));
rgcmds[4].cmdf |= OLECMDF_ENABLED;
ppf->Release();
}
}
//
// APPHACK: Office apps do not enable "Save" correctly.
// Automatically enable it if the moniker is a FILE moniker
// AND the document has been altered by the user.
//
if (_IsFileMoniker() && _IsDirty(NULL))
{
if (!(rgcmds[3].cmdf & OLECMDF_ENABLED))
{
DebugMsg(DM_APPHACK, TEXT("APPHACK DOH Enabling Save for Office Apps"));
}
rgcmds[3].cmdf |= OLECMDF_ENABLED;
}
// Remove/disable/enable the "Print" command as appropriate.
// Excel doesn't set SUPPORTED bit when it sets ENABLED bit
// so we have to check both bits.
if (!(rgcmds[0].cmdf & (OLECMDF_SUPPORTED | OLECMDF_ENABLED)))
RemoveMenu(hmInit, IDM_PRINT, MF_BYCOMMAND);
else
EnableMenuItem(hmInit, IDM_PRINT,
(rgcmds[0].cmdf & OLECMDF_ENABLED) ? MF_ENABLED : MF_GRAYED);
EnableMenuItem(hmInit, IDM_PAGESETUP,
(rgcmds[1].cmdf & OLECMDF_ENABLED) ? MF_ENABLED : MF_GRAYED);
EnableMenuItem(hmInit, IDM_PROPERTIES,
(rgcmds[2].cmdf & OLECMDF_ENABLED) ? MF_ENABLED : MF_GRAYED);
EnableMenuItem(hmInit, IDM_SAVE,
(rgcmds[3].cmdf & OLECMDF_ENABLED) ? MF_ENABLED : MF_GRAYED);
EnableMenuItem(hmInit, IDM_SAVEASFILE,
(rgcmds[4].cmdf & OLECMDF_ENABLED) ? MF_ENABLED : MF_GRAYED);
// Remove/disable/enable the "Print Preview" command as appropriate.
if (!(rgcmds[5].cmdf & (OLECMDF_SUPPORTED | OLECMDF_ENABLED)))
RemoveMenu(hmInit, IDM_PRINTPREVIEW, MF_BYCOMMAND);
else
EnableMenuItem(hmInit, IDM_PRINTPREVIEW,
(rgcmds[5].cmdf & OLECMDF_ENABLED) ? MF_ENABLED : MF_GRAYED);
// Remove/disable/enable the "Print Frame" command as appropriate.
if (!(rgcmds1[0].cmdf & OLECMDF_SUPPORTED))
RemoveMenu(hmInit, IDM_PRINTFRAME, MF_BYCOMMAND);
else
EnableMenuItem(hmInit, IDM_PRINTFRAME,
(rgcmds1[0].cmdf & OLECMDF_ENABLED) ? MF_ENABLED : MF_GRAYED);
if (!IsRegistered(TEXT("Software\\Clients\\Mail")))
RemoveMenu(hmInit, IDM_NEWMESSAGE, MF_BYCOMMAND);
}
if (!_pcmSendTo)
_pcmSendTo = GetSendToMenu(_pwb, _psv, hmInit);
}
else if (GetMenuItemID(hmInit, 0) == IDM_SENDTOFIRST)
{
// Handling child popup in sendto popup.
Assert(_pcmSendTo);
_pcmSendTo->HandleMenuMsg(WM_INITMENUPOPUP, (WPARAM)hmInit, (LPARAM)MAKELONG(nIndex, fSystemMenu));
}
}
//
// ATTEMPT: Handling WM_SETFOCUS message here caused several problems
// under IE 3.0. Since we can't find any code scenario that requires
// this code, I'm yanking out. If might introduce a new bug, but dealing
// with those bugs is probably better than dealing with this code.
// (SatoNa)
//
#if 0
void CDocObjectHost::_OnSetFocus()
{
// DebugMsg(0, TEXT("sdv TR : _WndProc -- Got WM_SETFOCUS"));
Assert(_psb);
// BUGBUG: In IE 4.0, we should just get rid of OnSetFocus code.
if (_fIPDeactivatingView || (_pdvctx && _pdvctx->IsClosing()))
return; // ignore if inplace deactivating view
_psb->OnViewWindowActive(_psv);
if (_ActiveHwnd())
{
SetFocus(_ActiveHwnd());
if (!_pipu) {
_xao.OnFrameWindowActivate(TRUE);
}
}
_psv->UIActivate(SVUIA_ACTIVATE_FOCUS);
}
#endif
BOOL CDocObjectHost::_CheckHelpMenuMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg) {
case WM_INITMENUPOPUP:
if ((HMENU)wParam == _hmenuMergedHelp) {
goto ForwardMessage;
}
break;
case WM_COMMAND:
if (_fLastMenuForwarded) {
// didn't come from a menu
_fLastMenuForwarded = FALSE;
if (!HIWORD(wParam)) {
goto ForwardMessage;
}
}
break;
case WM_MENUSELECT:
if (_hmenuMergedHelp &&
GET_WM_MENUSELECT_HMENU(wParam, lParam) == _hmenuMergedHelp) {
_fLastMenuForwarded = TRUE;
ForwardMessage:
IOleInPlaceActiveObject *piact = _xao.GetObject();
Assert(piact);
if (piact) {
HWND hwnd;
piact->GetWindow(&hwnd);
if (hwnd) {
if (uMsg==WM_COMMAND) {
PostMessage(hwnd, uMsg, wParam, lParam);
} else {
SendMessage(hwnd, uMsg, wParam, lParam);
}
return TRUE;}
}
} else {
// don't clear this on closeup because USER sends thisbefore
// the wm_command comes through
if (GET_WM_MENUSELECT_HMENU(wParam, lParam))
_fLastMenuForwarded = FALSE;
}
break;
}
return FALSE;
}
void CDocObjectHost::_OnMenuSelect(UINT id, UINT mf, HMENU hmenu)
{
if (_psb)
{
WCHAR wszT[MAX_STATUS_SIZE];
if (_LoadStringW(HINST_THISDLL, IDS_HELP_OF(id), wszT, ARRAYSIZE(wszT)))
{
_psb->SetStatusTextSB(wszT);
}
}
}
#ifdef FEATURE_PICS
BOOL CDocObjectHost::_HandlePicsChecksComplete(void)
{
Assert(_pmsoctBrowser);
if (_PicsBlockingDialog(NULL) == IDOK) {
_pmsoctBrowser->Exec(&CGID_ShellDocView, SHDVID_ACTIVATEMENOW, NULL, NULL, NULL);
return TRUE;
}
else {
_CancelPendingNavigation();
// _pmsoctBrowser->Exec(NULL, OLECMDID_STOP, NULL, NULL, NULL);
if (_pObjCache) {
_pObjCache->RevokeObject(_pole, FALSE);
}
return FALSE;
}
}
#endif
LRESULT CDocObjectHost::_WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch(uMsg)
{
#ifdef TEST_DELAYED_SHOWMSOVIEW
case WM_TIMER:
MessageBeep(0);
KillTimer(_hwnd, 100);
ActivateMe(NULL);
break;
#endif // TEST_DELAYED_SHOWMSOVIEW
#ifdef FEATURE_PICS
case WM_PICS_ASYNCCOMPLETE:
{
PicsQuery pq;
HRESULT hr;
LPVOID lpvRatingDetails;
if (::_GetPicsQuery((DWORD)lParam, &pq)) {
::_RemovePicsQuery((DWORD)lParam);
hr = (HRESULT)wParam;
lpvRatingDetails = pq.lpvRatingDetails;
}
else {
hr = E_FAIL;
lpvRatingDetails = NULL;
}
_GotLabel(hr, lpvRatingDetails, PICS_WAIT_FOR_ASYNC);
break;
}
#endif
case WM_LBUTTONDOWN:
case WM_RBUTTONDOWN:
MessageBeep(0);
break;
case WM_MENUSELECT:
if (!_CheckHelpMenuMessage(uMsg, wParam, lParam))
_OnMenuSelect(GET_WM_MENUSELECT_CMD(wParam, lParam), GET_WM_MENUSELECT_FLAGS(wParam, lParam), GET_WM_MENUSELECT_HMENU(wParam, lParam));
break;
case WM_INITMENUPOPUP:
if (!_CheckHelpMenuMessage(uMsg, wParam, lParam))
_OnInitMenuPopup((HMENU)wParam, LOWORD(lParam), HIWORD(lParam));
break;
case WM_DRAWITEM:
case WM_MEASUREITEM:
#ifdef DEBUG
{
DRAWITEMSTRUCT * pdi = (DRAWITEMSTRUCT *)lParam;
Assert((IDM_SENDTOFIRST >= pdi->itemID) &&
(IDM_SENDTOLAST > pdi->itemID) &&
(pdi->CtlType == ODT_MENU));
}
#endif
// only one ownerdraw thing...
Assert(_pcmSendTo);
_pcmSendTo->HandleMenuMsg(uMsg, wParam, lParam);
return TRUE;
case WM_NOTIFY:
_OnNotify((LPNMHDR)lParam);
break;
case WM_COMMAND:
if (!_CheckHelpMenuMessage(uMsg, wParam, lParam))
_OnCommand(HIWORD(wParam), LOWORD(wParam), (HWND)lParam);
break;
case WM_SIZE:
if (_pmsov)
{
RECT rcClient;
GetClientRect(_hwnd, &rcClient);
//
// We should call ResizeBorder only if the browser is
// not an IOleInPlaceUIWindow.
//
if (_pipu==NULL)
{
DebugMsg(TF_SHDUIACTIVATE, TEXT("DOH::WM_SIZE calling _piact->ResizeBorder"));
_xao.ResizeBorder(&rcClient, &_dof, TRUE);
}
_rcView.left = _bwTools.left;
_rcView.top = _bwTools.top;
_rcView.right = rcClient.right - _bwTools.right;
_rcView.bottom = rcClient.bottom - _bwTools.bottom;
DebugMsg(TF_SHDUIACTIVATE, TEXT("DOH::WM_SIZE calling SetRect (%d, %d, %d, %d)"), _rcView.left, _rcView.top, _rcView.right, _rcView.bottom);
_pmsov->SetRect(&_rcView);
}
_PlaceProgressBar();
break;
//
// ATTEMPT: Handling WM_SETFOCUS message here caused several problems
// under IE 3.0. Since we can't find any code scenario that requires
// this code, I'm yanking out. If might introduce a new bug, but dealing
// with those bugs is probably better than dealing with this code.
// (SatoNa)
//
#if 0
case WM_ACTIVATE:
//
// If the browser support IOleInPlaceUIWindow, we don't need to
// process this message.
//
if (_pipu) {
break;
}
if (wParam == WA_INACTIVE) {
_xao.OnFrameWindowActivate(FALSE);
break;
}
wParam = 0;
// fall through
case WM_SETFOCUS:
if (!wParam || GetParent((HWND)wParam) != _hwnd) {
_OnSetFocus();
} else {
DebugMsg(DM_WARNING, "CDOH::_WndProc WM_SETFOCUS from one of our children!!!");
}
break;
#endif
case WM_PRINT:
_OnPaint((HDC)wParam);
break;
case WM_QUERYNEWPALETTE:
case WM_PALETTECHANGED:
case WM_SYSCOLORCHANGE:
case WM_DISPLAYCHANGE:
case WM_ENTERSIZEMOVE:
case WM_EXITSIZEMOVE:
{
HWND hwndT = HWNDFromOleObject(_pole);
return hwndT? SendMessage(hwndT, uMsg, wParam, lParam) : 0;
}
case WM_PAINT:
PAINTSTRUCT ps;
HDC hdc;
hdc = BeginPaint(_hwnd, &ps);
// we don't need them to paint into our dc...
// docobj has own hwnd.
//_OnPaint(hdc);
EndPaint(_hwnd, &ps);
break;
case WM_LBUTTONUP:
if (_uState != SVUIA_ACTIVATE_FOCUS) {
SetFocus(_hwnd);
}
break;
case WM_ERASEBKGND:
// Checking _bsc._fBinding will catch the first page case.
if ((_pmsov && _uState!=SVUIA_DEACTIVATE)
|| _bsc._fBinding
|| _fDrawBackground)
{
PAINTMSG("WM_ERASEBKGND", this);
goto DoDefault;
}
// Don't draw WM_ERASEBKGND if we have no view activated.
return TRUE; // TRUE = fErased
default:
// Handle the MSWheel message
if ((uMsg == g_msgMSWheel) && _pole)
{
HWND hwndT;
// If for some reason our window has focus we just need to
// swallow the message. If we don't we may create an infinite loop
// because most clients send the message to the focus window.
if (GetFocus() == _hwnd)
return 1;
//
// try to find a window to forward along to
//
if ((hwndT = HWNDFromOleObject(_pole)) != NULL)
{
PostMessage(hwndT, uMsg, wParam, lParam);
return 1;
}
// Fall through...
}
DoDefault:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
return 0L;
}
LRESULT CDocObjectHost::s_WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
CDocObjectHost* pdoh = (CDocObjectHost*)GetWindowLong(hwnd, 0);
switch(uMsg)
{
case WM_NCCREATE:
pdoh = (CDocObjectHost*)(((LPCREATESTRUCT)lParam)->lpCreateParams);
if (pdoh) // paranoia
{
pdoh->_hwnd = hwnd;
SetWindowLong(hwnd, 0, (LONG)pdoh);
// RegisterDragDrop(hwnd, pdoh);
}
// Notes: No need to pdoh->AddRef here.
return TRUE; // success
case WM_NCDESTROY:
if (pdoh) // just in case
{
// Notes: No need to pdoh->Release here.
// RevokeDragDrop(pdoh);
}
break;
default:
return pdoh->_WndProc(hwnd, uMsg, wParam, lParam);
}
return 0L;
}
static const TCHAR c_szViewClass[] = TEXT("Shell DocObject View");
void CDocObjectHost::_RegisterWindowClass(void)
{
static fRegistered = FALSE;
if (!fRegistered) {
WNDCLASS wc = {0};
wc.style = CS_PARENTDC;
wc.lpfnWndProc = s_WndProc ;
//wc.cbClsExtra = 0;
wc.cbWndExtra = SIZEOF(CDocObjectHost*);
wc.hInstance = g_hinst ;
//wc.hIcon = NULL ;
//wc.hCursor = NULL;
wc.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE + 1);
//wc.lpszMenuName = NULL ;
wc.lpszClassName = c_szViewClass;
fRegistered = RegisterClass(&wc);
}
}
void CDocObjectHost::_InitOleObject()
{
if (!_fClientSiteSet) {
_fClientSiteSet = TRUE;
#ifdef DEBUG
IOleClientSite* pcliT = NULL;
if (SUCCEEDED(_pole->GetClientSite(&pcliT)) && pcliT)
{
extern HRESULT _IsSameObject(IUnknown* punk1, IUnknown* punk2);
//
// Trident now grabs the client site from the bind context.
// We don't want to hit this assertin this case (pcliT==this).
//
AssertMsg(_IsSameObject(pcliT, SAFECAST(this, IOleClientSite*)) == S_OK,
TEXT("CDocObjectHost::_InitOleObject _pole (%x) already has a client site (%x) (this=%x)"),
_pole, pcliT, this);
pcliT->Release();
}
#endif
HRESULT hresT = _pole->SetClientSite(this);
if (FAILED(hresT)) {
DebugMsg(TF_SHDAPPHACK, TEXT("DOH::_InitOleObject SetClientSite failed (%x). Don't in-place navigate"), hresT);
_dwAppHack |= BROWSERFLAG_DONTINPLACE;
}
Assert(NULL==_pvo);
_pole->QueryInterface(IID_IViewObject, (LPVOID*)&_pvo);
if (_pvo) {
DebugMsg(DM_DEBUGTFRAME, TEXT("CDocObjectHost::_InitOleObject about call SetAdvise on %x (%x)"), _pole, this);
_pvo->SetAdvise(DVASPECT_CONTENT, ADVF_PRIMEFIRST, this);
}
//
// According to SteveRa (Word developer), a word object has an
// internal flag which indicates whether or not it is created
// from a file. If that flag is set, UIActivate will open the
// window in Word. Calling SetHostName will reset that flag.
//
_GetAppHack(); // Make it sure that we have _dwAppHack
if (_fCallSetHostName()) {
DebugMsg(TF_SHDAPPHACK, TEXT("DOH::_InitOleObject calling SetHostName for Word95"));
WCHAR wszTitle[128];
_LoadStringW(HINST_THISDLL, IDS_TITLE, wszTitle, ARRAYSIZE(wszTitle));
_pole->SetHostNames(wszTitle, wszTitle);
}
}
}
BOOL CDocObjectHost::_OperationIsHyperlink()
{
_ChainBSC();
DWORD dw = 0;
BINDINFO bindinfo = { sizeof(BINDINFO) };
HRESULT hr = _bsc.GetBindInfo(&dw, &bindinfo);
if (SUCCEEDED(hr)) {
ReleaseStgMedium(&bindinfo.stgmedData);
}
return (dw & BINDF_HYPERLINK);
}
BOOL CDocObjectHost::_ShouldReadFromCache()
{
// can't have a false positive
if (!_fDontReadFromCache) {
_ChainBSC();
DWORD dw;
BINDINFO bindinfo = { sizeof(BINDINFO) };
HRESULT hr = _bsc.GetBindInfo(&dw, &bindinfo);
if (SUCCEEDED(hr)) {
ReleaseStgMedium(&bindinfo.stgmedData);
}
}
return !_fDontReadFromCache;
}
HRESULT CDocObjectHost::SetTarget(IMoniker* pmk, LPCSTR pszLocation, HGLOBAL hszPostData, int cbPostData, LPSTR pszHeaders, LPITEMIDLIST pidlKey,
IShellView* psvPrev)
{
HRESULT hres = NOERROR;
if (_pmkCur) {
ATOMICRELEASE(_pmkCur);
}
_pmkCur = pmk;
pmk->AddRef();
_pszLocation = pszLocation;
if (_bsc._hszPostData)
GlobalFree(_bsc._hszPostData);
_bsc._hszPostData = hszPostData;
_bsc._cbPostData = cbPostData;
if (_bsc._pszHeaders)
LocalFree(_bsc._pszHeaders);
_bsc._pszHeaders = pszHeaders;
Assert(_pObjCache);
if (_pObjCache && !_pole && _ShouldReadFromCache()) {
// if we've got a cache from the previous view and
// we didn't steal their ole object directly, see
// if there's one in the cache.
// first check the navigation stack cache
INavigationStackItem* pnsi;
_pwb->GetNavigationStackItem(_psv, &pnsi);
DebugMsg(DM_CACHETRACE, TEXT("shd TR -- dochost. GetNavigationStackItem for %x returned %x"), _psv, pnsi);
if (pnsi) {
CDocObjAssoc* pdoa = NULL;
pnsi->GetCacheObject(&_pole, CLSID_CDocObjAssoc, (LPVOID*)&pdoa);
DebugMsg(DM_CACHETRACE, TEXT("shd TR -- dochost. GetNavigationStackItem cached oleobject %x"), _pole);
pnsi->Release();
if (_pole) {
// this means we didn't store it to the lookup cache last
// time... we don't want to do so this time
_fDontCache = TRUE;
}
if (pdoa) {
Assert(_pole);
_dwDOCHF = pdoa->GetDOCHF();
pdoa->Release();
}
}
if (!_pole) {
CDocObjAssoc* pdoa = NULL;
_pole = _pObjCache->GetObject(pidlKey, CLSID_CDocObjAssoc, (LPVOID*)&pdoa, &_stExpires, &_fhasLastModified, _OperationIsHyperlink());
if (pdoa) {
Assert(_pole);
_dwDOCHF = pdoa->GetDOCHF();
pdoa->Release();
}
}
if (_pole) {
_fObjInCache = TRUE;
_fGotFromCache = TRUE;
DebugMsg(DM_CACHETRACE, TEXT("SHDocVW: CACHE: got ole object from cache"));
}
}
if (_pole) {
_InitOleObject();
hres = S_OK;
// if we were already up and created, just scroll to it.
// we if we were created DEACTIVATED, (possible in the ocx case)
// don't do this activation
if (_uState != SVUIA_DEACTIVATE) {
hres = _ActivateMsoView();
}
}
else
{
IBindCtx* pbc = NULL;
DebugMsg(DM_CACHETRACE, TEXT("SHDocVW: CACHE: creating ole object from scratch"));
if (_psp) {
hres = _psp->QueryService(SID_SShellBrowser, IID_IBindCtx, (LPVOID*)&pbc);
}
if (pbc==NULL) {
hres = CreateBindCtx(0, &pbc);
} else {
hres = S_OK;
}
if (SUCCEEDED(hres))
{
IBindCtx* pbcWrapper = BCW_Create(pbc);
if (pbcWrapper == NULL)
{
pbcWrapper = pbc;
}
else
{
pbc->Release();
}
pbc = NULL;
IBindCtx* pbcAsync = NULL;
hres = CreateAsyncBindCtxEx(pbcWrapper, 0, NULL, NULL, &pbcAsync,0);
if (SUCCEEDED(hres))
{
Assert(pbcAsync);
if (_pbcCur)
{
ATOMICRELEASE(_pbcCur);
}
_pbcCur = pbcAsync;
_pbcCur->AddRef();
pbcWrapper->Release();
pbcWrapper = pbcAsync;
}
if (SUCCEEDED(hres))
{
DWORD dwMksys;
hres = pmk->IsSystemMoniker(&dwMksys);
if (SUCCEEDED(hres) && dwMksys==MKSYS_FILEMONIKER) {
//
// Notes: Set this #if to 1 to debug ref-count bug.
//
hres = _BindFileMoniker(pmk, pbcWrapper, psvPrev);
if (SUCCEEDED(hres))
{
HRESULT hresT;
// We need to call OleRun to make IID_IOleDocument availalbe.
hresT = OleRun(_pole);
OPENMSG2(TEXT("CreateViewWindow _OleRun returned"), hresT);
IOleDocument* pmsod = NULL;
hresT = (_fDontInPlaceNavigate() ? E_NOINTERFACE : _pole->QueryInterface(IID_IOleDocument, (LPVOID*)&pmsod));
OPENMSG2(TEXT("CreateViewWindow _pole->QI(IOleDoc) returned"), hresT);
if (SUCCEEDED(hresT)) {
// case 1: DocObject
OPENMSG(TEXT("CreateViewWindow SYNC DocObject"));
pmsod->Release();
} else {
// Case 2: OLE object
OPENMSG(TEXT("CreateViewWindow SYNC OLE Object"));
_ActivateOleObject();
hres = HRESULT_FROM_WIN32(ERROR_CANCELLED);
}
} else if (hres != E_OUTOFMEMORY
&& hres!=HRESULT_FROM_WIN32(ERROR_CANCELLED)
&& hres!=E_ABORT) {
// DebugBreak();
// Case 3: Non OLE object
OPENMSG(TEXT("CreateViewWindow SYNC non-OLE Object"));
LPOLESTR pszDisplayName = NULL;
hres = pmk->GetDisplayName(pbcWrapper, NULL, &pszDisplayName);
if (SUCCEEDED(hres))
{
// if we're supposed to directly execute
// local files then do it, otehrwise go through
// the download code which give a warning dialog
DWORD dwFlags = 0;
IBrowserService * pbs;
if (_psp) {
hres = _psp->QueryService(SID_STopLevelBrowser, IID_IBrowserService, (LPVOID*)&pbs);
if (SUCCEEDED(hres))
{
pbs->GetFlags(&dwFlags);
pbs->Release();
}
}
if (dwFlags & BSF_NOLOCALFILEWARNING) {
TCHAR szBuf[MAX_URL_STRING];
WideCharToMultiByte(CP_ACP, 0, pszDisplayName, -1,
szBuf, ARRAYSIZE(szBuf), NULL, NULL);
DebugMsg(TF_SHDBINDING, TEXT("DOH::SetTarget calling ShellExecuteEx with %s"), szBuf);
SHELLEXECUTEINFO sei = { SIZEOF(SHELLEXECUTEINFO),
0, _hwnd, NULL, szBuf, NULL, NULL, SW_SHOWNORMAL, NULL};
if (!ShellExecuteEx(&sei)) {
DebugMsg(TF_SHDBINDING, TEXT("DOH::SetTarget ShellExecuteEx failed"));
}
} else {
CDownLoad_OpenUIURL(pszDisplayName, NULL, NULL, FALSE, FALSE, FALSE);
}
OleFree(pszDisplayName);
// We must return ERROR_CANCELLED if failed.
hres = HRESULT_FROM_WIN32(ERROR_CANCELLED);
} else {
DebugMsg(TF_SHDBINDING, TEXT("DOH::SetTarget pmk->GetDisplayName failed"));
}
}
} else {
if (!g_bUserHasBeenPromptedToConnect)
{
InternetAttemptConnect(0);
g_bUserHasBeenPromptedToConnect = TRUE;
}
hres = _StartAsyncBinding(pmk, _pbcCur, psvPrev);
if (SUCCEEDED(hres)) {
hres = S_FALSE;
}
}
}
pbcWrapper->Release();
}
}
return hres;
}
//
// Copied from COMCTL32.DLL. It's not exporeted.
//
BOOL CCForwardEraseBackground(HWND hwnd, HDC hdc)
{
HWND hwndParent = GetParent(hwnd);
LRESULT lres = 0;
if (hwndParent)
{
// Adjust the origin so the parent paints in the right place
POINT pt = {0,0};
MapWindowPoints(hwnd, hwndParent, &pt, 1);
OffsetWindowOrgEx(hdc, pt.x, pt.y, &pt);
lres = SendMessage(hwndParent, WM_ERASEBKGND, (WPARAM) hdc, 0L);
SetWindowOrgEx(hdc, pt.x, pt.y, NULL);
}
return(lres != 0);
}
LRESULT CDocObjectHost::s_IconsWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
CDocObjectHost* that = (CDocObjectHost*)GetWindowLong(hwnd, GWL_ID);
Assert(that);
Assert(that->_hwndIcons == hwnd);
Assert(that->_pfnStaticWndProc);
switch(uMsg) {
case WM_ERASEBKGND:
CCForwardEraseBackground(hwnd, (HDC)wParam);
return TRUE;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
const UINT cx = GetSystemMetrics(SM_CXSMICON);
const UINT cy = GetSystemMetrics(SM_CYSMICON);
const INT cyTop = -GetSystemMetrics(SM_CYBORDER);
UINT posNextIcon = 1;
if (that->_dwDOCHF & DOCHF_SSL) {
DrawIconEx(hdc, cx, cyTop, g_hiconSSL, cx, cy,
0, NULL, DI_NORMAL);
posNextIcon ++;
}
BOOL bOffline = FALSE;
TOOLINFO ti;
UINT posOld = that->posOfflineIcon;
INT hr = that->_GetOfflineSilent(&bOffline, 0);
if (SUCCEEDED(hr) && bOffline) {
DrawIconEx(hdc, cx * posNextIcon, cyTop, g_hiconOffline,
cx, cy, 0, NULL, DI_NORMAL);
that->posOfflineIcon = posNextIcon;
if (posOld != posNextIcon) {
ti.cbSize = sizeof(ti);
ti.uFlags = 0;
ti.hinst = HINST_THISDLL;
ti.hwnd = hwnd;
ti.uId = 0;
ti.rect.left = cx * posNextIcon;
ti.rect.right = ti.rect.left + cx;
ti.rect.top = cyTop;
ti.rect.bottom = cyTop + cy;
if (that->_hwndTooltip) {
SendMessage(that->_hwndTooltip, TTM_NEWTOOLRECT,
0, (LPARAM)&ti);
}
}
posNextIcon ++;
} else {
that->posOfflineIcon = 0;
if (posOld != 0) {
ti.cbSize = sizeof(ti);
ti.uFlags = 0;
ti.hinst = HINST_THISDLL;
ti.hwnd = hwnd;
ti.uId = 0;
ti.rect.left = ti.rect.right = 0;
ti.rect.top = ti.rect.bottom = 0;
if (that->_hwndTooltip) {
SendMessage(that->_hwndTooltip, TTM_NEWTOOLRECT,
0, (LPARAM)&ti);
}
}
}
const static c_aidRes[] = {
IDI_STATE_NORMAL, // 0
IDI_STATE_FINDINGRESOURCE, // BINDSTATUS_FINDINGRESOURCE
IDI_STATE_FINDINGRESOURCE, // BINDSTATUS_CONNECTING
IDI_STATE_FINDINGRESOURCE, // BINDSTATUS_REDIRECTING
IDI_STATE_DOWNLOADINGDATA, // BINDSTATUS_BEGINDOWNLOADDATA
IDI_STATE_DOWNLOADINGDATA, // BINDSTATUS_DOWNLOADINGDATA
IDI_STATE_DOWNLOADINGDATA, // BINDSTATUS_ENDDOWNLOADDATA
IDI_STATE_DOWNLOADINGDATA, // BINDSTATUS_BEGINDOWNLOADCOMPONENTS
IDI_STATE_DOWNLOADINGDATA, // BINDSTATUS_INSTALLINGCOMPONENTS
IDI_STATE_DOWNLOADINGDATA, // BINDSTATUS_ENDDOWNLOADCOMPONENTS
IDI_STATE_SENDINGREQUEST, // BINDSTATUS_USINGCACHEDCOPY
IDI_STATE_SENDINGREQUEST, // BINDSTATUS_SENDINGREQUEST
IDI_STATE_DOWNLOADINGDATA, // BINDSTATUS_CLASSIDAVAILABLE
};
UINT idRes = IDI_STATE_NORMAL;
if (that->_bsc._bindst < ARRAYSIZE(c_aidRes)) {
idRes = c_aidRes[that->_bsc._bindst];
}
Assert(idRes-IDI_STATE_FIRST < ARRAYSIZE(g_ahiconState));
DebugMsg(TF_SHDPROGRESS, TEXT("DOH::Icons::WM_PAINT _bindst=%d _idRes=%x"),
that->_bsc._bindst, idRes);
DrawIconEx(hdc, 0, cyTop, g_ahiconState[idRes-IDI_STATE_FIRST],
cx, cy, 0, NULL, DI_NORMAL);
EndPaint(hwnd, &ps);
}
break;
case WM_MOUSEMOVE:
{
if (that->posOfflineIcon == 0)
break;
MSG msg;
msg.lParam = lParam;
msg.wParam = wParam;
msg.message = uMsg;
msg.hwnd = hwnd;
if (that->_hwndTooltip) {
SendMessage(that->_hwndTooltip, TTM_RELAYEVENT, 0, (LPARAM)&msg);
}
break;
}
case WM_NCDESTROY:
that->Release();
// fall through
default:
return CallWindowProc(that->_pfnStaticWndProc, hwnd, uMsg, wParam, lParam);
}
return 0L;
}
#define USE_HISTBMOFFSET 0
#define USE_MYBMOFFSET 1
#define USE_STDBMOFFSET 2
const TBBUTTON c_abtnDocHost[] = {
{ MAKELONG(4, USE_MYBMOFFSET), IDM_GOHOME, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0,0}, 0, -1},
{ MAKELONG(10, USE_MYBMOFFSET),IDM_GOSEARCH, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0,0}, 0, -1},
{ MAKELONG(HIST_FAVORITES, USE_HISTBMOFFSET),IDM_DHFAVORITES, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0,0}, 0, -1},
{ 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, {0,0}, 0, -1 },
{ MAKELONG(3, USE_MYBMOFFSET), IDM_STOPDOWNLOAD, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0,0}, 0, -1},
{ MAKELONG(5, USE_MYBMOFFSET), IDM_REFRESH, 0 /* TBSTATE_ENABLED */, TBSTYLE_BUTTON, {0,0}, 0, -1},
{ MAKELONG(STD_PRINT, USE_STDBMOFFSET), IDM_PRINT, 0 /* TBSTATE_ENABLED */, TBSTYLE_BUTTON, {0,0}, 0, -1},
{ 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, {0,0}, 0, -1 },
{ MAKELONG(8, USE_MYBMOFFSET), IDM_ZOOMIN, 0 /* TBSTATE_ENABLED */, TBSTYLE_BUTTON, {0,0}, 0, -1},
{ MAKELONG(9, USE_MYBMOFFSET), IDM_ZOOMOUT, 0 /* TBSTATE_ENABLED */, TBSTYLE_BUTTON, {0,0}, 0, -1},
{ 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, {0,0}, 0, -1 },
{ MAKELONG(STD_CUT, USE_STDBMOFFSET), IDM_CUT, 0 /* TBSTATE_ENABLED */, TBSTYLE_BUTTON, {0,0}, 0, -1},
{ MAKELONG(STD_COPY, USE_STDBMOFFSET), IDM_COPY, 0 /* TBSTATE_ENABLED */, TBSTYLE_BUTTON, {0,0}, 0, -1},
{ MAKELONG(STD_PASTE, USE_STDBMOFFSET), IDM_PASTE, 0 /* TBSTATE_ENABLED */, TBSTYLE_BUTTON, {0,0}, 0, -1},
};
void CDocObjectHost::_MergeToolbarSB()
{
return;
//
//
//
// HWND hwndToolbar;
// if (SUCCEEDED(_psb->GetControlWindow(FCW_TOOLBAR, &hwndToolbar))) {
// //
// // Merge the toolbar items.
// //
// TBADDBITMAP ab;
// int iStdBMOffset;
// int iHistBMOffset;
// ab.hInst = HINST_COMMCTRL; // hinstCommctrl
// ab.nID = IDB_STD_SMALL_COLOR; // std bitmaps
// _psb->SendControlMsg(FCW_TOOLBAR, TB_ADDBITMAP, 8, (LPARAM)&ab, (LRESULT*)&iStdBMOffset);
//
// ab.nID = IDB_HIST_SMALL_COLOR; // std bitmaps
// _psb->SendControlMsg(FCW_TOOLBAR, TB_ADDBITMAP, 8, (LPARAM)&ab, (LRESULT*)&iHistBMOffset);
//
// int iMyBMOffset;
// ab.hInst = HINST_THISDLL;
// ab.nID = IDB_TOOLBAR;
// _psb->SendControlMsg(FCW_TOOLBAR, TB_ADDBITMAP, 14, (LPARAM)&ab, (LRESULT*)&iMyBMOffset);
//
// int aOffsets[3] = {
// iHistBMOffset,
// iMyBMOffset,
// iStdBMOffset
// };
//
// TBBUTTON abtn[ARRAYSIZE(c_abtnDocHost)];
// int i = ARRAYSIZE(c_abtnDocHost);
// memcpy(abtn, c_abtnDocHost, SIZEOF(c_abtnDocHost));
// while (i--) {
// if (abtn[i].iBitmap) {
// abtn[i].iBitmap = LOWORD(abtn[i].iBitmap) + aOffsets[HIWORD(abtn[i].iBitmap)];
// }
// }
//
// _psb->SetToolbarItems(abtn, ARRAYSIZE(abtn), FCT_MERGE);
// }
}
void _InitIcons(void)
{
if (g_hiconSSL && g_hiconOffline) {
return;
}
ENTERCRITICAL;
if (!g_hiconSSL) {
g_hiconSSL = (HICON)LoadImage(HINST_THISDLL, MAKEINTRESOURCE(IDI_SSL), IMAGE_ICON,
GetSystemMetrics(SM_CXSMICON),
GetSystemMetrics(SM_CYSMICON),
0);
for (UINT id = IDI_STATE_FIRST; id<=IDI_STATE_LAST; id++) {
g_ahiconState[id-IDI_STATE_FIRST]
= (HICON)LoadImage(HINST_THISDLL,
MAKEINTRESOURCE(id), IMAGE_ICON,
GetSystemMetrics(SM_CXSMICON),
GetSystemMetrics(SM_CYSMICON),
0);
}
}
if (!g_hiconOffline) {
g_hiconOffline = (HICON)LoadImage(HINST_THISDLL,
MAKEINTRESOURCE(IDI_OFFLINE), IMAGE_ICON,
GetSystemMetrics(SM_CXSMICON),
GetSystemMetrics(SM_CYSMICON),
0);
}
LEAVECRITICAL;
}
//
// This function (re)initializes CDocObjectHost object with the buddy
// IShellView (which is always CShellDocView) and the IShellBrowser.
// If this is the first time (_hwnd==NULL), it creates the view window
// and other associated windows as well. Otherwise (_hwnd!=NULL) -- it
// means this object is passed from one CDocViewObject to another because
// of intra-page jump -- we move it to the specified location (prcView)
// to make it really sure that we show it at the right place.
//
BOOL CDocObjectHost::InitHostWindow(IShellView* psv, IShellBrowser* psb,
LPRECT prcView)
{
HWND hwndParent;
_ResetOwners();
Assert(psv);
_psv = psv;
_psv->AddRef();
Assert(NULL==_pmsoctView);
_psv->QueryInterface(IID_IOleCommandTarget, (LPVOID*)&_pmsoctView);
Assert(NULL==_pdvs);
_psv->QueryInterface(IID_IDocViewSite, (LPVOID*)&_pdvs);
Assert(psb);
_psb = psb;
_psb->AddRef();
Assert(NULL==_pwb);
_psb->QueryInterface(IID_IBrowserService, (LPVOID*)&_pwb);
Assert(NULL==_pmsoctBrowser);
_psb->QueryInterface(IID_IOleCommandTarget, (LPVOID*)&_pmsoctBrowser);
Assert(NULL==_psp);
_psb->QueryInterface(IID_IServiceProvider, (LPVOID*)&_psp);
Assert(NULL==_pipu);
_psb->QueryInterface(IID_IOleInPlaceUIWindow, (LPVOID*)&_pipu);
Assert(_psp);
if (_psp) {
//
// LATER: I don't like that CDocObjectHost is directly accessing
// the automation service object to fire events. We should
// probably move all the progress UI code above IShellBrowser
// so that we don't need to do this shortcut. (SatoNa)
//
Assert(NULL==_peds);
_psp->QueryService(IID_IExpDispSupport, IID_IExpDispSupport, (LPVOID*)&_peds);
Assert(_peds);
Assert(NULL==_pedsHelper);
_peds->QueryInterface(IID_IExpDispSupportOC, (LPVOID*)&_pedsHelper);
Assert(NULL==_phf);
_psp->QueryService(SID_SHlinkFrame, IID_IHlinkFrame, (LPVOID*)&_phf);
if (_phf)
_phf->QueryInterface(IID_IObjectCache, (LPVOID *)&_pObjCache);
}
#if 0
if (_pmsoctBrowser) {
_pmsoctBrowser->Exec(&CGID_Explorer, SBCMDID_ENABLESHOWTREE, TRUE, NULL, NULL);
}
#endif
_psb->GetWindow(&hwndParent);
if (!_hwnd) {
// There are several things we don't attempt to do when
// we're not toplevel. Frameset type DOH should never
// try to menu merge or dork with the statusbar.
// Do this before the CreateWindowEx call 'cuz during
// creation we party on the status bar.
{
IOleInPlaceSite* pparentsite = _GetParentSite();
if (pparentsite) {
_fHaveParentSite = TRUE;
pparentsite->Release();
}
}
_RegisterWindowClass();
// really create the window
DWORD dwStyle = WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_VISIBLE | WS_TABSTOP;
//
// BUGBUG: In Office 95, Excel and PowerPoint don't draw the client edge,
// while Word does draw the client edge. To avoid having double edges,
// we remove it for now. SriniK (Office) will find out which will be
// the standard for Office 96. (SatoNa)
//
_hwnd = CreateWindowEx(0 /* WS_EX_CLIENTEDGE */,
c_szViewClass, NULL,
dwStyle,
prcView->left, prcView->top, prcView->right-prcView->left, prcView->bottom-prcView->top,
hwndParent,
(HMENU)0,
HINST_THISDLL,
(LPVOID)this);
if (!_hwnd) {
goto Bail;
}
HWND hwndStatus = NULL;
if (!_fHaveParentSite) {
// must protect FCW_STATUS in DefView frameset case
_psb->GetControlWindow(FCW_STATUS, &hwndStatus);
_hacc = LoadAccelerators(HINST_THISDLL, MAKEINTRESOURCE(ACCEL_DOCVIEW));
}
if (hwndStatus) {
RECT rc;
GetClientRect(hwndStatus, &rc);
_hwndProgress = CreateWindowEx(0, PROGRESS_CLASS, NULL,
WS_CHILD | WS_CLIPSIBLINGS,
0, 0, 1, 1,
hwndStatus, (HMENU)1,
HINST_THISDLL, NULL);
// we yank off this bit because we REALLY don't want it because
// the status bar already draws this for us when we specify rects
//
// but the progress bar forces this bit on during creation
if (_hwndProgress)
{
DWORD dwExStyle = GetWindowLong(_hwndProgress, GWL_EXSTYLE);
SetWindowLong(_hwndProgress, GWL_EXSTYLE, dwExStyle & ~WS_EX_STATICEDGE);
}
//
// NOTES: We create a static window as the child of the status
// bar to show icons (such as SSL icon).
//
// 1. It's a static window, which is subclassed.
// 2. Window ID is the pointer back to this object.
// 3. We process WM_PAINT message only (so far).
// We now also process WM_RBUTTONUP to watch for context menus.
// 4. Unlike the progress bar, it is always visible.
// 5. _PlaceProgressBar places this window as well.
//
_hwndIcons = CreateWindowEx(0, "STATIC", NULL,
WS_CHILD | WS_CLIPSIBLINGS | SS_SIMPLE | SS_NOTIFY,
0, 0, 1, 1,
hwndStatus, (HMENU)this,
HINST_THISDLL, NULL);
if (_hwndIcons) {
_InitIcons();
_pfnStaticWndProc = (WNDPROC)SetWindowLong(_hwndIcons, GWL_WNDPROC, (LONG)s_IconsWndProc);
AddRef(); // Will be Released _hwndIcons is released.
Assert(_pfnStaticWndProc);
SetWindowPos(_hwndIcons, HWND_TOP, 0, 0, 0, 0,
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
_hwndTooltip = CreateWindow(TOOLTIPS_CLASS, NULL,
WS_POPUP | TTS_ALWAYSTIP,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
_hwndIcons, NULL, HINST_THISDLL, NULL);
if (_hwndTooltip) {
TOOLINFO ti;
ti.cbSize = SIZEOF(ti);
ti.uFlags = 0;
ti.hwnd = _hwndIcons;
ti.hinst = HINST_THISDLL;
ti.uId = 0;
ti.rect.left = 0;
ti.rect.right = 0;
ti.rect.top = 0;
ti.rect.bottom = 0;
ti.lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_OFFLINE);
SendMessage(_hwndTooltip, TTM_ADDTOOL, 0, (LPARAM)&ti);
posOfflineIcon = 0;
}
}
}
} else {
Assert(GetParent(_hwnd) == hwndParent);
MoveWindow(_hwnd, prcView->left, prcView->top,
prcView->right-prcView->left, prcView->bottom - prcView->top, TRUE);
}
Bail:
return (BOOL)_hwnd;
}
void CDocObjectHost::DestroyHostWindow()
{
// really destroy the window
_fCanceledByBrowser = TRUE;
_bsc.AbortBinding();
_CloseMsoView();
//
// Notes: We need to delete OLE object from this side (container),
// otherwise, we leak because of circular reference.
//
_UnBind();
if (_hwndProgress) {
DestroyWindow(_hwndProgress);
_hwndProgress = NULL;
}
if (_hwndTooltip) {
DestroyWindow(_hwndTooltip);
_hwndTooltip = NULL;
}
if (_hwndIcons) {
DestroyWindow(_hwndIcons);
_hwndIcons = NULL;
}
//
// Note that we need to destroy the parent after destroying children.
//
// OLE seems to recurse back into this function when we destroy the hwnd
// and we try to destroy it a second time causing a RIP. Avoid this RIP
// by NULLing out our internal variables before we destroy the hwnds.
if (_hwnd) {
HWND hwndT = _hwnd;
_hwnd = NULL;
DestroyWindow(hwndT);
}
if (_psp) {
ATOMICRELEASE(_psp);
}
_ResetOwners();
}
//
// This member creates a view (IOleDocumentView) of the DocObject we have (_pole).
// This function is called only once from ::CreateViewWindow.
//
HRESULT CDocObjectHost::_CreateMsoView(void)
{
Assert(_pmsov == NULL);
ASSERT(_pmsoc == NULL);
HRESULT hres = OleRun(_pole);
if (SUCCEEDED(hres))
{
//// WARNING:
// if you add anything to here, you should also pass it along
// in _CreateDocObjHost
//
IOleDocument* pmsod = NULL;
hres = _pole->QueryInterface(IID_IOleDocument, (LPVOID*)&pmsod);
if (SUCCEEDED(hres)) {
hres = pmsod->CreateView(this, NULL /* BUGBUG */ ,0,&_pmsov);
if (SUCCEEDED(hres)) {
//
// BUGBUG/HACK: Working about MSHTML bug (#28756). We really
// want to take this hack out before we ship. (SatoNa)
//
_pmsov->SetInPlaceSite(this);
} else {
DebugMsg(DM_ERROR, TEXT("DOH::_CreateMsoView pmsod->CreateView() ##FAILED## %x"), hres);
}
if (SUCCEEDED(hres) && !_pmsot) {
_pmsov->QueryInterface(IID_IOleCommandTarget, (LPVOID*)&_pmsot);
}
if (SUCCEEDED(hres) && !_pmsoc) {
_pmsov->QueryInterface(IID_IOleControl, (LPVOID*)&_pmsoc);
}
#ifdef HLINK_EXTRA
if (_pihlbc)
{
if (_phls)
{
_phls->SetBrowseContext(_pihlbc);
}
Assert(_pmkCur);
hres = HlinkOnNavigate(this, _pihlbc, 0,
_pmkCur, NULL, NULL);
// DebugMsg(0, TEXT("sdv TR : _CreateMsoView HlinkOnNavigate returned %x"), hres);
}
#endif // HLINK_EXTRA
pmsod->Release();
} else {
DebugMsg(DM_ERROR, TEXT("DOH::_CreateMsoView _pole->QI(IOleDocument) ##FAILED## %x"), hres);
}
} else {
DebugMsg(DM_ERROR, TEXT("DOH::_CreateMsoView OleRun ##FAILED## %x"), hres);
}
return hres;
}
//
// This is the only method of IOleDocumentSite, which we MUST implement.
//
HRESULT CDocObjectHost::ActivateMe(IOleDocumentView *pviewToActivate)
{
DebugMsg(TF_SHDUIACTIVATE, TEXT("DOC::ActivateMe called when _pmsov is %x"), _pmsov);
HRESULT hres = S_OK;
if (_pmsov==NULL) {
// Reset the progress bar for non MSHTML DocObject here.
_OnSetProgressPos(0);
hres = _CreateMsoView();
#ifdef TEST_DELAYED_SHOWMSOVIEW
SetTimer(_hwnd, 100, 1500, NULL);
MessageBeep(0);
return hres;
#endif // TEST_DELAYED_SHOWMSOVIEW
}
if (SUCCEEDED(hres)) {
_ShowMsoView();
_MergeToolbarSB();
_InitToolbarButtons();
}
return hres;
}
//Helper routine for QueryStatus for status messages
ULONG ulBufferSizeNeeded(wchar_t *wsz, int ids, ULONG ulBufferLen)
{
DebugMsg(0, TEXT("sdv TR ulBufferSizeNeeded called with (%x)"), ids);
DWORD dwLen;
WCHAR szTemp[MAX_STATUS_SIZE+1];
dwLen = _LoadStringW(HINST_THISDLL, ids, szTemp, MAX_STATUS_SIZE);
dwLen += 1; // for NULL terminator
if (dwLen <= (DWORD)ulBufferLen)
MoveMemory(wsz, szTemp, dwLen * sizeof(WCHAR));
else
*wsz = 0;
return ((ULONG)dwLen);
}
HRESULT CDocObjectHost::OnQueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD rgCmds[], OLECMDTEXT *pcmdtext, HRESULT hres)
{
if (pguidCmdGroup == NULL)
{
ULONG i;
if (rgCmds == NULL)
return E_INVALIDARG;
for (i=0 ; i<cCmds ; i++)
{
// ONLY say that we support the stuff we support in ::OnExec
switch (rgCmds[i].cmdID)
{
case OLECMDID_OPEN:
case OLECMDID_SAVE:
case OLECMDID_UPDATECOMMANDS:
case OLECMDID_SETPROGRESSMAX:
case OLECMDID_SETPROGRESSPOS:
case OLECMDID_SETPROGRESSTEXT:
case OLECMDID_SETTITLE:
rgCmds[i].cmdf = OLECMDF_ENABLED;
break;
default:
if (SUCCEEDED(hres))
{
// _pmsoctBrowser already filled this in
}
else
{
rgCmds[i].cmdf = 0;
}
break;
}
}
/* for now we deal only with status text*/
if (pcmdtext)
{
switch (rgCmds[i].cmdID)
{
case OLECMDID_OPEN:
case OLECMDID_SAVE:
pcmdtext->cwActual = ulBufferSizeNeeded(pcmdtext->rgwz,
IDS_HELP_OF(_MapFromMso(rgCmds[0].cmdID)),
pcmdtext->cwBuf);
break;
default:
if (SUCCEEDED(hres))
{
// _pmsoctBrowser already filled this in
}
else
{
pcmdtext->cmdtextf = OLECMDTEXTF_NONE;
pcmdtext->cwActual = 0;
if (pcmdtext->rgwz && pcmdtext->cwBuf>0)
*pcmdtext->rgwz = TEXT('\0');
}
break;
}
}
hres = S_OK;
}
return hres;
}
HRESULT CDocObjectHost::QueryStatus(
/* [unique][in] */ const GUID *pguidCmdGroup,
/* [in] */ ULONG cCmds,
/* [out][in][size_is] */ OLECMD rgCmds[ ],
/* [unique][out][in] */ OLECMDTEXT *pcmdtext)
{
HRESULT hres = OLECMDERR_E_UNKNOWNGROUP;
if (_pmsoctBrowser)
hres = _pmsoctBrowser->QueryStatus(pguidCmdGroup, cCmds, rgCmds, pcmdtext);
return OnQueryStatus(pguidCmdGroup, cCmds, rgCmds, pcmdtext, hres);
}
BOOL CDocObjectHost::_IsFileMoniker(void)
{
BOOL fRet = FALSE;
if (_pmkCur) {
DWORD dwMksys;
HRESULT hres = _pmkCur->IsSystemMoniker(&dwMksys);
if (SUCCEEDED(hres) && dwMksys==MKSYS_FILEMONIKER) {
fRet = TRUE;
}
}
return fRet;
}
void CDocObjectHost::_OnSave(void)
{
if (_pole && _IsFileMoniker())
{
IPersistFile* ppf = 0;
HRESULT hres = _pole->QueryInterface(IID_IPersistFile, (LPVOID*)&ppf);
if (SUCCEEDED(hres))
{
LPOLESTR pszDisplayName = NULL;
hres = _GetCurrentPageW(&pszDisplayName);
if (SUCCEEDED(hres))
{
// fRemember = TRUE for normal case
hres = ppf->Save(pszDisplayName, !_fCantSaveBack);
if (FAILED(hres)) {
DebugMsg(DM_ERROR, TEXT("DOH::_OnSave ppf->Save(psz, FALSE) failed with %x"), hres);
}
OleFree(pszDisplayName);
}
ppf->Release();
}
}
}
void CDocObjectHost::_OnSetProgressPos(DWORD dwPos)
{
if (_hwndProgress) {
SendMessage(_hwndProgress, PBM_SETPOS, dwPos, 0);
}
// fire an event that progress has changed
Assert(_peds);
if (_peds) {
_peds->DoInvokeDwords(DISPID_PROGRESSCHANGE,dwPos,_dwProgressMax);
}
}
void CDocObjectHost::_OnSetProgressMax(DWORD dwMax)
{
// remember the maximum range so we have it when we want to fire progress events
_dwProgressMax = dwMax;
if (_hwndProgress) {
if (dwMax) {
_PlaceProgressBar();
SendMessage(_hwndProgress, PBM_SETRANGE32, 0, dwMax);
} else {
// max of 0 shuts it down
ShowWindow(_hwndProgress, SW_HIDE);
}
}
}
UINT CDocObjectHost::_MapCommandID(UINT id, BOOL fToMsoCmd)
{
// HEY, this maps OLECMDID commands *only*
static const UINT s_aicmd[][2] = {
{ IDM_PROPERTIES, OLECMDID_PROPERTIES },
{ IDM_PRINT, OLECMDID_PRINT },
{ IDM_PRINTPREVIEW, OLECMDID_PRINTPREVIEW },
{ IDM_PAGESETUP, OLECMDID_PAGESETUP},
{ IDM_SAVEASFILE, OLECMDID_SAVEAS },
{ IDM_CUT, OLECMDID_CUT },
{ IDM_COPY, OLECMDID_COPY },
{ IDM_PASTE, OLECMDID_PASTE },
{ IDM_REFRESH, OLECMDID_REFRESH },
{ IDM_STOPDOWNLOAD, OLECMDID_STOP },
// subset - above this line document handles
{ IDM_OPEN, OLECMDID_OPEN },
{ IDM_SAVE, OLECMDID_SAVE },
};
#define CCMD_MAX (sizeof(s_aicmd)/sizeof(s_aicmd[0]))
UINT iFrom = fToMsoCmd ? 0 : 1;
for (UINT i = 0; i < CCMD_MAX; i++) {
if (s_aicmd[i][iFrom]==id) {
return s_aicmd[i][1-iFrom];
}
}
return (UINT)-1;
#undef CCMD_MAX
}
void CDocObjectHost::_InitToolbarButtons()
{
OLECMD acmd[] = {
{ OLECMDID_ZOOM, 0 }, // Notes: This must be the first one
{ OLECMDID_PRINT, 0 },
{ OLECMDID_CUT, 0 },
{ OLECMDID_COPY, 0 },
{ OLECMDID_PASTE, 0 },
{ OLECMDID_REFRESH, 0 },
{ OLECMDID_STOP, 0 }, // Notes: This must be the last one
};
if (_pmsot) {
_pmsot->QueryStatus(NULL, ARRAYSIZE(acmd), acmd, NULL);
}
if (_pmsoctBrowser) {
// the browser may support stop also, so override the document
// with what the browser says. this is okay because the browser
// forwards stop back down the chain.
_pmsoctBrowser->QueryStatus(NULL, 1, &acmd[ARRAYSIZE(acmd)-1], NULL);
}
for (int i=1; i<ARRAYSIZE(acmd); i++) {
UINT idCmd = _MapFromMso(acmd[i].cmdID);
_psb->SendControlMsg(FCW_TOOLBAR, TB_ENABLEBUTTON, idCmd,
(LPARAM)acmd[i].cmdf, NULL);
}
// Check if ZOOM command is supported.
if (acmd[0].cmdf) {
VARIANTARG var;
VariantInit(&var);
var.vt = VT_I4;
var.lVal = 0;
// get the current zoom depth
_pmsot->Exec(NULL, OLECMDID_ZOOM, OLECMDEXECOPT_DONTPROMPTUSER, NULL, &var);
if (var.vt == VT_I4) {
_iZoom = var.lVal;
} else {
VariantClear(&var);
}
// get the current zoom range
var.vt = VT_I4;
var.lVal = 0;
_pmsot->Exec(NULL, OLECMDID_GETZOOMRANGE, OLECMDEXECOPT_DONTPROMPTUSER, NULL, &var);
if (var.vt == VT_I4) {
_iZoomMin = (int)(short)LOWORD(var.lVal);
_iZoomMax = (int)(short)HIWORD(var.lVal);
} else {
VariantClear(&var);
}
// depending on how far in and out we are zoomed, enable/disable
// these buttons
_psb->SendControlMsg(FCW_TOOLBAR, TB_ENABLEBUTTON, IDM_ZOOMIN,
(LPARAM)(_iZoom < _iZoomMax), NULL);
_psb->SendControlMsg(FCW_TOOLBAR, TB_ENABLEBUTTON, IDM_ZOOMOUT,
(LPARAM)(_iZoom > _iZoomMin), NULL);
}
}
void CDocObjectHost::_OnSetStatusText(VARIANTARG* pvarIn)
{
if (pvarIn->vt == (VT_BSTR)) {
LPCOLESTR pwch = (LPCOLESTR)pvarIn->bstrVal;
TCHAR szHint[256];
szHint[0]= TEXT('\0');
if (pwch) {
OleStrToStrN(szHint, ARRAYSIZE(szHint), pwch, (UINT)-1);
}
_SetStatusText(szHint);
}
}
//
// This function returns TRUE if
// (1) the DocObject supports IPersistFile and
// (2) IPersistFile::IsDirty returns S_OK.
// Caller may pass pppf to retrieve IPersistFile*, which will be AddRef'ed
// and returned only when this function returns TRUE.
//
BOOL CDocObjectHost::_IsDirty(IPersistFile** pppf)
{
BOOL fDirty = FALSE; // Assume non-dirty
if (pppf) {
*pppf = NULL;
}
if (_pole) {
IPersistFile* ppf;
HRESULT hresT = _pole->QueryInterface(IID_IPersistFile, (LPVOID*)&ppf);
if (SUCCEEDED(hresT))
{
if (ppf->IsDirty()==S_OK) {
fDirty = TRUE;
if (pppf) {
*pppf = ppf;
ppf->AddRef();
}
}
ppf->Release();
}
}
return fDirty;
}
void CDocObjectHost::_OnSetTitle(VARIANTARG *pvTitle, BOOL bFinal)
{
if (pvTitle->vt == (VT_BSTR)) {
LPCOLESTR pwch = (LPCOLESTR)pvTitle->bstrVal;
if (pwch) {
if (_pwb)
_pwb->SetTitle(pwch);
}
}
// tell our parent DocObjectView about this as well
if (_pdvs)
_pdvs->OnSetTitle(pvTitle, bFinal);
}
HRESULT CDocObjectHost::OnExec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANTARG *pvarargIn, VARIANTARG *pvarargOut)
{
if (pguidCmdGroup == NULL)
{
// _InitToolbarButtons and _OnSetStatusText reference _psb directly
Assert(_psb);
if (!_psb)
return E_FAIL;
switch (nCmdID)
{
case OLECMDID_REFRESH:
if (pvarargIn && pvarargIn->vt == VT_I4 &&
pvarargIn->lVal == OLECMDIDF_REFRESH_IFEXPIRED) {
VARIANTARG v;
v = *pvarargIn;
// check to see if this doc has expired
// no expireation date.
if (_stExpires.wYear) {
SYSTEMTIME st;
GetSystemTime(&st);
if (CmpSystemtime(&st, &_stExpires) >= 0) {
// current time is past expire time.. do a regular
v.lVal = OLECMDIDF_REFRESH_NORMAL;
}
}
if (_pmsot)
_pmsot->Exec(pguidCmdGroup, nCmdID, nCmdexecopt, &v, pvarargOut);
return S_OK;
}
return E_FAIL; // say we didn't handle it in the default case
case OLECMDID_OPEN:
_OnOpen();
return S_OK;
case OLECMDID_SAVE:
_OnSave();
return S_OK;
case OLECMDID_UPDATECOMMANDS:
_InitToolbarButtons();
return E_FAIL; // lie and say we don't do anything to forward the command on
case OLECMDID_SETPROGRESSMAX:
Assert(pvarargIn->vt == VT_I4);
_OnSetProgressMax((DWORD) pvarargIn->lVal);
return S_OK;
case OLECMDID_SETPROGRESSPOS:
Assert(pvarargIn->vt == VT_I4);
_OnSetProgressPos((DWORD) pvarargIn->lVal);
return S_OK;
case OLECMDID_SETPROGRESSTEXT:
_OnSetStatusText(pvarargIn);
return S_OK;
case OLECMDID_SETTITLE:
_OnSetTitle(pvarargIn, FALSE);
return S_OK;
// case OLECMDID_PRINT:
// In the up direction, this case is handled by the outermost frame as
// a request to print from the docobj. It handles it by sending an OLECMDID_PRINT
// back to the docobj to print. (Or, as in Binder, to all the docobjects.)
default:
return OLECMDERR_E_NOTSUPPORTED;
}
}
else if (IsEqualGUID(*pguidCmdGroup, CGID_ShellDocView))
{
switch (nCmdID)
{
case SHDVID_FINALTITLEAVAIL:
_OnSetTitle(pvarargIn, TRUE);
return S_OK;
case SHDVID_AMBIENTPROPCHANGE:
// An ambient property above us has changed, let the docobj know
if (_pmsoc)
{
Assert(pvarargIn->vt == VT_I4);
return(_pmsoc->OnAmbientPropertyChange(pvarargIn->lVal));
}
return E_FAIL;
#ifdef FEATURE_PICS
case SHDVID_CANACTIVATENOW:
return (_fPicsAccessAllowed && !_fbPicsWaitFlags) ? S_OK : S_FALSE;
#endif
default:
return OLECMDERR_E_NOTSUPPORTED;
}
}
else if (IsEqualGUID(*pguidCmdGroup, CGID_Explorer))
{
switch (nCmdID)
{
case SBCMDID_MAYSAVECHANGES:
{
HRESULT hres = S_OK;
//
// ASSUMPTIONS:
// 1. Not supporting IPersistFile indicates we don't need to worry
// about prompting the user for "save as".
// 2. DocObject which returns S_OK for IPersistFile::S_OK implements
// OLECMDID_SAVEAS.
//
if (_IsFileMoniker() || _pmsot)
{
IPersistFile* ppf;
if (_IsDirty(&ppf))
{
Assert(ppf);
TCHAR szBuf[MAX_URL_STRING];
UINT id;
_GetCurrentPage(szBuf, ARRAYSIZE(szBuf));
id = ShellMessageBox(HINST_THISDLL, _hwnd,
MAKEINTRESOURCE(IDS_MAYSAVEDOCUMENT), szBuf, MB_YESNOCANCEL);
switch(id) {
case IDCANCEL:
hres = S_FALSE;
break;
case IDYES:
if (_IsFileMoniker()) {
_OnSave();
} else {
HRESULT hresT=_pmsot->Exec(NULL, OLECMDID_SAVEAS, OLECMDEXECOPT_PROMPTUSER, NULL, NULL);
SAVEMSG("Exec(OLECMDID_SAVEAS) returned", hresT);
// Cancel the navigation if it failed.
if (FAILED(hresT)) {
// Beep if it is not canceled by the end user.
if (hresT != OLECMDERR_E_CANCELED) {
MessageBeep(0);
}
hres = S_FALSE;
}
}
break;
case IDNO:
//
// If user says 'No' to save changes to this page,
// we should remove it from the cache so that
// the user won't see that discarded change.
//
// BUGBUG: (pri-2) This object discarding mechanism
// does not work for POSTed result, which is cached
// in the travel log.
//
Assert(_pObjCache);
if (_pObjCache) {
_pObjCache->RevokeObject(_pole, TRUE);
_fObjInCache = FALSE; // So that we close
}
break;
}
ppf->Release();
} else {
Assert(ppf==NULL);
}
}
return hres;
} // SBCMDID_MAYSAVECHANGES
default:
return OLECMDERR_E_NOTSUPPORTED;
} // switch
}
return OLECMDERR_E_UNKNOWNGROUP;
}
BOOL _ExecNearest(const GUID *pguidCmdGroup, DWORD nCmdID, BOOL fDown)
{
// Some commands we want to do in the closest frame to the docobj,
// some in the farthest-away frame, and some we want to handle
// in the top-most dochost. Look at the command to figure out
// the routing and then do it.
BOOL fNearest = FALSE; // most everything goes to the farthest-away frame
if (pguidCmdGroup==NULL)
{
switch(nCmdID)
{
case OLECMDID_OPEN:
case OLECMDID_SAVE:
case OLECMDID_SETTITLE:
fNearest = TRUE;
break;
// some are top-most down, so nearest depends on direction.
case OLECMDID_REFRESH:
// say top-most for commands that only work on the topmost guy.
// (ie, these probably should be implemented in CShellBrowser!)
// do this even though these are really "upwards-only" commands.
case OLECMDID_UPDATECOMMANDS:
case OLECMDID_SETPROGRESSMAX:
case OLECMDID_SETPROGRESSPOS:
case OLECMDID_SETPROGRESSTEXT:
fNearest = fDown;
break;
}
}
else if (IsEqualGUID(*pguidCmdGroup, CGID_ShellDocView))
{
switch (nCmdID)
{
case SHDVID_FINALTITLEAVAIL:
case SHDVID_AMBIENTPROPCHANGE:
fNearest = TRUE;
break;
}
}
else if (IsEqualGUID(*pguidCmdGroup, CGID_Explorer))
{
switch(nCmdID)
{
case SBCMDID_MAYSAVECHANGES: // since OLECMDID_SAVE is to the nearest frame
fNearest = TRUE;
break;
}
}
return fNearest;
}
HRESULT CDocObjectHost::Exec(
/* [unique][in] */ const GUID *pguidCmdGroup,
/* [in] */ DWORD nCmdID,
/* [in] */ DWORD nCmdexecopt,
/* [unique][in] */ VARIANTARG *pvarargIn,
/* [unique][out][in] */ VARIANTARG *pvarargOut)
{
HRESULT hres = OLECMDERR_E_UNKNOWNGROUP;
BOOL fNearest = _ExecNearest(pguidCmdGroup, nCmdID, FALSE);
if (fNearest)
hres = OnExec(pguidCmdGroup, nCmdID, nCmdexecopt, pvarargIn, pvarargOut);
if (FAILED(hres) && _pmsoctBrowser)
hres = _pmsoctBrowser->Exec(pguidCmdGroup, nCmdID, nCmdexecopt,
pvarargIn, pvarargOut);
// BUGBUG: if this is a command that puts up UI and the user presses
// cancel in the above call, we may try to handle the call here,
// and that would be bad. Steal OleCmdHRHandled() from MSHTML.
if (FAILED(hres) && !fNearest)
hres = OnExec(pguidCmdGroup, nCmdID, nCmdexecopt, pvarargIn, pvarargOut);
return hres;
}
// called from CDocObjectView to exec and forward these calls down
//
HRESULT CDocObjectHost::ExecDown(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANTARG *pvarargIn, VARIANTARG *pvarargOut)
{
HRESULT hres = OLECMDERR_E_UNKNOWNGROUP;
BOOL fNearest = _ExecNearest(pguidCmdGroup, nCmdID, TRUE);
if (fNearest)
hres = OnExec(pguidCmdGroup, nCmdID, nCmdexecopt, pvarargIn, pvarargOut);
if (FAILED(hres) && _pmsot)
hres = _pmsot->Exec(pguidCmdGroup, nCmdID, nCmdexecopt, pvarargIn, pvarargOut);
if (FAILED(hres) && !fNearest)
hres = OnExec(pguidCmdGroup, nCmdID, nCmdexecopt, pvarargIn, pvarargOut);
return hres;
}
HRESULT CDocObjectHost::QueryStatusDown(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD rgCmds[], OLECMDTEXT *pcmdtext)
{
HRESULT hres = OLECMDERR_E_UNKNOWNGROUP;
if (_pmsot)
hres = _pmsot->QueryStatus(pguidCmdGroup, cCmds, rgCmds, pcmdtext);
else if (pguidCmdGroup && _pole && IsEqualGUID(*pguidCmdGroup, CGID_ShellDocView))
{
IOleCommandTarget *pct;
if (SUCCEEDED(_pole->QueryInterface(IID_IOleCommandTarget, (LPVOID *)&pct)))
{
hres = pct->QueryStatus(pguidCmdGroup, cCmds, rgCmds, pcmdtext);
pct->Release();
}
}
return OnQueryStatus(pguidCmdGroup, cCmds, rgCmds, pcmdtext, hres);
}
HRESULT CDocObjectHost::Invoke(DISPID dispidMember, REFIID iid, LCID lcid, WORD wFlags, DISPPARAMS FAR* pdispparams,
VARIANT FAR* pVarResult,EXCEPINFO FAR* pexcepinfo,UINT FAR* puArgErr)
{
if (!_peds)
return(E_NOTIMPL);
return _peds->OnInvoke(dispidMember, iid, lcid, wFlags, pdispparams, pVarResult,pexcepinfo,puArgErr);
}
HRESULT CDocObjectHost::OnControlInfoChanged()
{
HRESULT hres = E_NOTIMPL;
if (_pedsHelper)
{
hres = _pedsHelper->OnOnControlInfoChanged();
}
return(hres);
}
HRESULT CDocObjectHost::TranslateAccelerator(MSG __RPC_FAR *pMsg,DWORD grfModifiers)
{
HRESULT hres = E_NOTIMPL;
if (_pedsHelper)
{
hres = _pedsHelper->OnTranslateAccelerator(pMsg, grfModifiers);
}
return(hres);
}
#ifdef FEATURE_PICS
STDMETHODIMP CDocObjectHost::CPicsCommandTarget::QueryInterface(REFIID riid, LPVOID * ppvObj)
{
if (IsEqualIID(riid, IID_IOleCommandTarget) ||
IsEqualIID(riid, IID_IUnknown))
{
*ppvObj = SAFECAST(this, IOleCommandTarget *);
}
else
{
*ppvObj = NULL;
return E_NOINTERFACE;
}
CDocObjectHost* pdoh = IToClass(CDocObjectHost, _ctPics, this);
return pdoh->AddRef();
}
STDMETHODIMP_(ULONG) CDocObjectHost::CPicsCommandTarget::AddRef(void)
{
CDocObjectHost* pdoh = IToClass(CDocObjectHost, _ctPics, this);
return pdoh->AddRef();
}
STDMETHODIMP_(ULONG) CDocObjectHost::CPicsCommandTarget::Release(void)
{
CDocObjectHost* pdoh = IToClass(CDocObjectHost, _ctPics, this);
return pdoh->Release();
}
STDMETHODIMP CDocObjectHost::CPicsCommandTarget::QueryStatus(const GUID *pguidCmdGroup,
ULONG cCmds, OLECMD rgCmds[], OLECMDTEXT *pcmdtext)
{
return E_NOTIMPL;
}
STDMETHODIMP CDocObjectHost::CPicsCommandTarget::Exec(const GUID *pguidCmdGroup,
DWORD nCmdID, DWORD nCmdexecopt, VARIANTARG *pvarargIn, VARIANTARG *pvarargOut)
{
CDocObjectHost* pdoh = IToClass(CDocObjectHost, _ctPics, this);
if (IsEqualGUID(*pguidCmdGroup, CGID_ShellDocView))
{
switch (nCmdID)
{
case SHDVID_PICSLABELFOUND:
if (pvarargIn->vt == (VT_BSTR)) {
LPOLESTR pwch = (LPOLESTR)pvarargIn->bstrVal;
UINT cbLabel = lstrlenW(pwch) * sizeof(*pwch);
TCHAR *pszLabel = new char[cbLabel+1];
if (pszLabel != NULL) {
OleStrToStrN(pszLabel, cbLabel+1, pwch, -1);
pdoh->_HandleInDocumentLabel(pszLabel);
delete pszLabel;
}
}
return NOERROR;
case SHDVID_NOMOREPICSLABELS:
pdoh->_HandleDocumentEnd();
return NOERROR;
default:
return OLECMDERR_E_NOTSUPPORTED;
}
}
return OLECMDERR_E_UNKNOWNGROUP;
}
#endif
HRESULT CDocObjectFrame::QueryService(REFGUID guidService,
REFIID riid, void **ppvObj)
{
return _pdoh->QueryService(guidService, riid, ppvObj);
}
HRESULT CDocObjectFrame::QueryInterface(REFIID riid, LPVOID * ppvObj)
{
if (IsEqualIID(riid, IID_IOleInPlaceFrame) ||
IsEqualIID(riid, IID_IOleInPlaceUIWindow) ||
IsEqualIID(riid, IID_IOleWindow) ||
IsEqualIID(riid, IID_IUnknown))
{
*ppvObj = SAFECAST(this, IOleInPlaceFrame*);
}
else if (IsEqualIID(riid, IID_IOleCommandTarget))
{
*ppvObj = SAFECAST(this, IOleCommandTarget*);
}
else if (IsEqualIID(riid, IID_IServiceProvider))
{
*ppvObj = SAFECAST(this, IServiceProvider*);
}
else
{
*ppvObj = NULL;
return E_NOINTERFACE;
}
_pdoh->AddRef();
return NOERROR;
}
ULONG CDocObjectFrame::AddRef(void)
{
return _pdoh->AddRef();
}
ULONG CDocObjectFrame::Release(void)
{
return _pdoh->Release();
}
HRESULT CDocObjectFrame::GetWindow(HWND * lphwnd)
{
DOFMSG(TEXT("GetWindow called"));
return _pdoh->_pipu ?
_pdoh->_pipu->GetWindow(lphwnd) :
_pdoh->_psb ? _pdoh->_psb->GetWindow(lphwnd) :
_pdoh->GetWindow(lphwnd);
}
HRESULT CDocObjectFrame::ContextSensitiveHelp(BOOL fEnterMode)
{
DOFMSG(TEXT("ContextSensitiveHelp called"));
return _pdoh->ContextSensitiveHelp(fEnterMode);
}
HRESULT CDocObjectFrame::GetBorder(LPRECT lprectBorder)
{
// DOFMSG(TEXT("GetBorder called"));
return _pdoh->_pipu ?
_pdoh->_pipu->GetBorder(lprectBorder) : _pdoh->GetBorder(lprectBorder);
}
HRESULT CDocObjectFrame::RequestBorderSpace(LPCBORDERWIDTHS pborderwidths)
{
DOFMSG(TEXT("RequestBorderSpace called"));
return _pdoh->_pipu ?
_pdoh->_pipu->RequestBorderSpace(pborderwidths) : _pdoh->RequestBorderSpace(pborderwidths);
}
HRESULT CDocObjectFrame::SetBorderSpace(LPCBORDERWIDTHS pborderwidths)
{
// DOFMSG(TEXT("SetBorderSpace called"));
return _pdoh->_pipu ?
_pdoh->_pipu->SetBorderSpace(pborderwidths) : _pdoh->SetBorderSpace(pborderwidths);
}
HRESULT CDocObjectFrame::SetActiveObject(
IOleInPlaceActiveObject *pActiveObject, LPCOLESTR pszObjName)
{
DOFMSG(TEXT("SetActiveObject called"));
// Note that we need to call both.
HRESULT hres = _pdoh->SetActiveObject(pActiveObject, pszObjName);
if (_pdoh->_pipu) {
//
// Note that we should pass proxy IOleActiveObject pointer instead.
//
_pdoh->_pipu->SetActiveObject(pActiveObject ? &_pdoh->_xao : NULL, pszObjName);
}
return hres;
}
HRESULT CDocObjectFrame::InsertMenus(HMENU hmenuShared, LPOLEMENUGROUPWIDTHS lpMenuWidths)
{
DOFMSG2(TEXT("InsertMenus called with"), hmenuShared);
return _pdoh->_InsertMenus(hmenuShared, lpMenuWidths);
}
HRESULT CDocObjectFrame::SetMenu(HMENU hmenuShared, HOLEMENU holemenu, HWND hwndActiveObject)
{
DOFMSG2(TEXT("SetMenu called with"), hmenuShared);
return _pdoh->_SetMenu(hmenuShared, holemenu, hwndActiveObject);
}
HRESULT CDocObjectFrame::RemoveMenus(HMENU hmenuShared)
{
DOFMSG(TEXT("RemoveMenus called"));
return _pdoh->_RemoveMenus(hmenuShared);
}
HRESULT CDocObjectFrame::SetStatusText(LPCOLESTR pszStatusText)
{
DOFMSG(TEXT("SetStatusText called"));
return _pdoh->_SetStatusText(pszStatusText);
}
HRESULT CDocObjectFrame::EnableModeless(BOOL fEnable)
{
DOFMSG(TEXT("EnableModeless called"));
return _pdoh->_EnableModeless(fEnable);
}
// IOleInPlaceFrame::TranslateAccelerator
HRESULT CDocObjectFrame::TranslateAccelerator(LPMSG lpmsg, WORD wID)
{
// NOTES: This code remains as-is. If we have something special
// it should be done in CDocObjectHost::TranslateAccelerator
return _pdoh->_TranslateAccelerator(lpmsg, wID);
}
HRESULT CDocObjectFrame::QueryStatus(const GUID *pguidCmdGroup,
ULONG cCmds, OLECMD rgCmds[], OLECMDTEXT *pcmdtext)
{
DOFMSG(TEXT("QueryStatus called"));
return _pdoh->QueryStatus(pguidCmdGroup, cCmds, rgCmds, pcmdtext);
}
HRESULT CDocObjectFrame::Exec(const GUID *pguidCmdGroup,
DWORD nCmdID, DWORD nCmdexecopt, VARIANTARG *pvarargIn, VARIANTARG *pvarargOut)
{
DOFMSG(TEXT("Exec called"));
return _pdoh->Exec(pguidCmdGroup, nCmdID, nCmdexecopt, pvarargIn, pvarargOut);
}
HRESULT CProxyActiveObject::TranslateAccelerator(
LPMSG lpmsg)
{
// IShellBrowser is supporsed to call ISV::TranslateAcceleratorSV,
// but why not be nice?
if (_piact && _piact->TranslateAccelerator(lpmsg) == S_OK)
return S_OK;
return _pdoh->TranslateHostAccelerators(lpmsg);
}
HRESULT CProxyActiveObject::OnFrameWindowActivate(
BOOL fActivate)
{
DebugMsg(TF_SHDUIACTIVATE, TEXT("CProxyAO::OnFrameWindowActivate called with %d (_piact=%x)"),
fActivate, _piact);
if (_piact) {
return _piact->OnFrameWindowActivate(fActivate);
}
return S_OK;
}
HRESULT CProxyActiveObject::OnDocWindowActivate(
BOOL fActivate)
{
// BUGBUG: Implement it later!
return S_OK;
}
HRESULT CProxyActiveObject::ResizeBorder(
LPCRECT prcBorder,
IOleInPlaceUIWindow *pUIWindow,
BOOL fFrameWindow)
{
if (_piact) {
//
// Note that we must pass our proxy frame instead!
//
return _piact->ResizeBorder(prcBorder, &_pdoh->_dof, TRUE);
}
return E_FAIL;
}
void CProxyActiveObject::SetActiveObject(IOleInPlaceActiveObject *piact )
{
if (_piact)
{
ATOMICRELEASE(_piact);
_hwnd = NULL;
}
if (piact) {
_piact = piact;
_piact->AddRef();
_piact->GetWindow(&_hwnd);
}
}
HRESULT CProxyActiveObject::EnableModeless(
BOOL fEnable)
{
// IShellBrowser is supporsed to call ISV::EnableModelessSV,
// but why not be nice?
HRESULT hres = S_OK;
if (_piact)
hres = _piact->EnableModeless(fEnable);
return hres;
}
HRESULT CProxyActiveObject::QueryInterface(REFIID riid, LPVOID * ppvObj)
{
if (IsEqualIID(riid, IID_IOleInPlaceActiveObject) ||
IsEqualIID(riid, IID_IOleWindow) ||
IsEqualIID(riid, IID_IUnknown))
{
*ppvObj = SAFECAST(this, IOleInPlaceActiveObject*);
}
else
{
*ppvObj = NULL;
return E_NOINTERFACE;
}
_pdoh->AddRef();
return NOERROR;
}
ULONG CProxyActiveObject::AddRef(void)
{
return _pdoh->AddRef();
}
ULONG CProxyActiveObject::Release(void)
{
return _pdoh->Release();
}
HRESULT CProxyActiveObject::GetWindow(HWND * lphwnd)
{
return _pdoh->GetWindow(lphwnd);
}
HRESULT CProxyActiveObject::ContextSensitiveHelp(BOOL fEnterMode)
{
return _pdoh->ContextSensitiveHelp(fEnterMode);
}
CDocObjectHost::CBindStatusCallback::~CBindStatusCallback()
{
DebugMsg(DM_DEBUGTFRAME, TEXT("dtor CDocObjectHost::CBSC %x"), this);
if (_pib) {
AssertMsg(0, TEXT("CBSC::~ _pib is %x (this=%x)"), _pib, this);
ATOMICRELEASE(_pib);
}
if (_pbc) {
AssertMsg(0, TEXT("CBSC::~ _pbc is %x (this=%x)"), _pbc, this);
ATOMICRELEASE(_pbc);
}
if (_psvPrev) {
AssertMsg(0, TEXT("CBSC::~ _psvPrev is %x (this=%x)"), _psvPrev, this);
ATOMICRELEASE(_psvPrev);
}
if (_pbscChained) {
ATOMICRELEASE(_pbscChained);
}
if (_pnegotiateChained) {
ATOMICRELEASE(_pnegotiateChained);
}
if (_hszPostData)
{
GlobalFree(_hszPostData);
_hszPostData = NULL;
}
if (_pszHeaders)
{
LocalFree(_pszHeaders);
_pszHeaders = NULL;
}
if (_pszRedirectedURL)
{
LocalFree(_pszRedirectedURL);
_pszRedirectedURL = NULL;
}
}
HRESULT CDocObjectHost::CBindStatusCallback::QueryInterface(REFIID riid, LPVOID * ppvObj)
{
if (IsEqualIID(riid, IID_IBindStatusCallback) ||
IsEqualIID(riid, IID_IUnknown))
{
*ppvObj = SAFECAST(this, IBindStatusCallback*);
}
else if (IsEqualIID(riid, IID_IHttpNegotiate))
{
*ppvObj = SAFECAST(this, IHttpNegotiate*);
}
else if (IsEqualIID(riid, IID_IAuthenticate))
{
*ppvObj = SAFECAST(this, IAuthenticate*);
}
else if (IsEqualIID(riid, IID_IServiceProvider))
{
*ppvObj = SAFECAST(this, IServiceProvider*);
}
else if (IsEqualIID(riid, IID_IHttpSecurity))
{
*ppvObj = SAFECAST(this, IHttpSecurity*);
}
else
{
*ppvObj = NULL;
return E_NOINTERFACE;
}
AddRef();
return NOERROR;
}
ULONG CDocObjectHost::CBindStatusCallback::AddRef(void)
{
CDocObjectHost* pdoh = IToClass(CDocObjectHost, _bsc, this);
return pdoh->AddRef();
}
ULONG CDocObjectHost::CBindStatusCallback::Release(void)
{
CDocObjectHost* pdoh = IToClass(CDocObjectHost, _bsc, this);
return pdoh->Release();
}
HRESULT CDocObjectHost::CBindStatusCallback::GetBindInfo(
DWORD* grfBINDF,
BINDINFO *pbindinfo)
{
CDocObjectHost* pdoh = IToClass(CDocObjectHost, _bsc, this);
BSCMSG(TEXT("GetBindInfo"), 0, 0);
*grfBINDF = BINDF_ASYNCHRONOUS;
// Delegation is valid ONLY for the ::GetBindInfo() method
if (_pbscChained) {
CHAINMSG("GetBindInfo", grfBINDF);
_pbscChained->GetBindInfo(grfBINDF, pbindinfo);
}
else
{
// fill out the BINDINFO struct
BuildBindInfo(grfBINDF,pbindinfo,_hszPostData,_cbPostData,
_bFrameIsOffline, _bFrameIsSilent, TRUE, /* bHyperlink */
(IBindStatusCallback *) this);
// HTTP headers are added by the callback to our
// IHttpNegotiate::BeginningTransaction() method
}
if ((*grfBINDF) & (BINDF_CONTAINER_NOWRITECACHE))
{
pdoh->_fDontCache = TRUE;
}
if ((*grfBINDF) & (BINDF_GETNEWESTVERSION))
{
pdoh->_fDontReadFromCache = TRUE;
}
// If we are delegating, let the delagted GBI() set the policy; otherwise
// we will set it
if (!_pbscChained)
if (GetSyncMode(WININET_SYNC_MODE_ONCE_PER_SESSION) == WININET_SYNC_MODE_ALWAYS)
*grfBINDF |= BINDF_GETNEWESTVERSION; // Always hit net
// In the else{} case, we rely on WININET to make the correct syncmode
// determination (ie, ifmodsince vs full get)
// Remember it to perform modeless download for POST case.
_dwBindVerb = pbindinfo->dwBindVerb;
return S_OK;
}
// *** IAuthenticate ***
HRESULT CDocObjectHost::CBindStatusCallback::Authenticate(
HWND *phwnd,
LPWSTR *pszUsername,
LPWSTR *pszPassword)
{
CDocObjectHost* pdoh = IToClass(CDocObjectHost, _bsc, this);
if (!phwnd || !pszUsername || !pszPassword)
return E_POINTER;
if(!_bFrameIsSilent){
if (pdoh->_psb) {
pdoh->_psb->GetWindow(phwnd);
} else {
*phwnd = pdoh->_hwnd;
}
}else{
*phwnd = NULL;
}
*pszUsername = NULL;
*pszPassword = NULL;
return S_OK;
}
// *** IServiceProvider ***
HRESULT CDocObjectHost::CBindStatusCallback::QueryService(REFGUID guidService,
REFIID riid, void **ppvObj)
{
HRESULT hres = E_FAIL;
*ppvObj = NULL;
if (IsEqualGUID(guidService, IID_IAuthenticate)) {
return QueryInterface(riid, ppvObj);
}
else if (_pbscChained)
{
// Has a delegating IBindStatusCallback.
IServiceProvider* psp;
hres = _pbscChained->QueryInterface(IID_IServiceProvider, (LPVOID*)&psp);
if (SUCCEEDED(hres)) {
// It supports ServiceProvider, just delegate.
hres = psp->QueryService(guidService, riid, ppvObj);
psp->Release();
} else if (IsEqualGUID(guidService, riid)) {
// It does not supports ServiceProvide, try QI.
hres = _pbscChained->QueryInterface(riid, ppvObj);
}
}
return hres;
}
//
// NOTES: This one also places _hwndIcons.
//
#define ANIMATION_WND_WIDTH (100+3)
void CDocObjectHost::_PlaceProgressBar()
{
if (_psb) {
HWND hwndStatus = NULL;
if (!_fHaveParentSite) // must protect FCW_STATUS in DefView frameset case
_psb->GetControlWindow(FCW_STATUS, &hwndStatus);
if (hwndStatus) {
RECT rc;
if (SendMessage(hwndStatus, SB_ISSIMPLE, 0, 0)) {
if (_hwndProgress) {
ShowWindow(_hwndProgress, SW_HIDE);
}
} else {
GetClientRect(hwndStatus, &rc);
const UINT cxIcons =
GetSystemMetrics(SM_CXSMICON) * 2 // State+SSL icons
+ GetSystemMetrics(SM_CXVSCROLL) // sizing grabber
+ GetSystemMetrics(SM_CXBORDER) * 2;
INT aWidths[] = {
rc.right-cxIcons-ANIMATION_WND_WIDTH,
rc.right-cxIcons,
-1 };
// Avoid passing a negative value.
if (aWidths[0] < 0) {
aWidths[0] = 1;
}
SendMessage(hwndStatus, SB_SETPARTS, 3, (LPARAM)aWidths);
if (_hwndProgress) {
SendMessage(hwndStatus, SB_GETRECT, 1, (LPARAM)&rc);
InflateRect(&rc, -GetSystemMetrics(SM_CXEDGE), -GetSystemMetrics(SM_CYEDGE));
SetWindowPos(_hwndProgress, NULL,
rc.left, rc.top,
rc.right-rc.left, rc.bottom-rc.top,
SWP_NOZORDER | SWP_NOACTIVATE | SWP_SHOWWINDOW);
}
if (_hwndIcons) {
SendMessage(hwndStatus, SB_GETRECT, 2, (LPARAM)&rc);
InflateRect(&rc, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER));
SetWindowPos(_hwndIcons, NULL,
rc.left, rc.top,
rc.right-rc.left, rc.bottom-rc.top,
SWP_NOZORDER | SWP_NOACTIVATE | SWP_SHOWWINDOW);
}
}
}
} else {
AssertMsg(0, "_PlaceProgressBar Assert(_psb) this=%x", this);
}
}
HRESULT CDocObjectHost::CBindStatusCallback::OnStartBinding(
DWORD grfBSCOption, IBinding *pib)
{
BSCMSG(TEXT("OnStartBinding"), _pib, pib);
_fBinding = TRUE;
CDocObjectHost* pdoh = IToClass(CDocObjectHost, _bsc, this);
// Assert(_pib==NULL);
if (_pib) {
ATOMICRELEASE(_pib);
}
_pib = pib;
if (_pib) {
_pib->AddRef();
}
pdoh->_PlaceProgressBar();
#ifndef NO_DELEGATION
if (_pbscChained) {
CHAINMSG("OnStartBinding", grfBSCOption);
_pbscChained->OnStartBinding(grfBSCOption, pib);
}
#endif
return S_OK;
}
HRESULT CDocObjectHost::CBindStatusCallback::GetPriority(LONG *pnPriority)
{
BSCMSG(TEXT("GetPriority"), 0, 0);
*pnPriority = NORMAL_PRIORITY_CLASS;
#ifndef NO_DELEGATION
if (_pbscChained) {
_pbscChained->GetPriority(pnPriority);
}
#endif
return S_OK;
}
void CDocObjectHost::CBindStatusCallback::_Redirect(LPCWSTR pwzNew)
{
LPITEMIDLIST pidlNew;
char szUrl[MAX_URL_STRING];
CDocObjectHost* pdoh = IToClass(CDocObjectHost, _bsc, this);
WideCharToMultiByte(CP_ACP, 0, pwzNew, -1,
szUrl, ARRAYSIZE(szUrl), NULL, NULL);
if (SUCCEEDED(IECreateFromPath(pdoh->_hwnd, szUrl, &pidlNew))) {
DebugMsg(TF_SHDNAVIGATE, TEXT("CDOH::CBSC::_Redirect calling NotifyRedirect(%s)"), szUrl);
pdoh->_pwb->NotifyRedirect(pdoh->_psv, pidlNew);
// Save te redirected URL
if (_pszRedirectedURL)
LocalFree( _pszRedirectedURL );
#ifdef UNICODE
_pszRedirectedURL = StrDupW(pwzNew);
#else
_pszRedirectedURL = StrDupA(szUrl);
#endif
ILFree(pidlNew);
}
}
#ifdef BETA1_DIALMON_HACK
extern void IndicateWinsockActivity();
#endif // BETA1_DIALMON_HACK
HRESULT CDocObjectHost::CBindStatusCallback::OnProgress(
ULONG ulProgress,
ULONG ulProgressMax,
ULONG ulStatusCode,
LPCWSTR pwzStatusText)
{
DebugMsg(TF_SHDPROGRESS, TEXT("DOH::BSC::OnProgress (%d of %d) ulStatus=%x"),
ulProgress, ulProgressMax, ulStatusCode);
//BUGBUG JEFFWE 4/15/96 Beta 1 Hack - every once in a while, send message
//BUGBUG to the hidden window that detects inactivity so that it doesn't
//BUGBUG think we are inactive during a long download
#ifdef BETA1_DIALMON_HACK
IndicateWinsockActivity();
#endif
CDocObjectHost* pdoh = IToClass(CDocObjectHost, _bsc, this);
#ifdef DEBUG
if (pwzStatusText) {
char szStatusText[MAX_PATH]; // OK with MAX_PATH
WideCharToMultiByte(CP_ACP, 0, pwzStatusText, -1, szStatusText, ARRAYSIZE(szStatusText), NULL, NULL);
DebugMsg(TF_SHDPROGRESS, TEXT("DOH::BSC::OnProgress pszStatus=%s"), szStatusText);
}
#endif
if (pdoh->_psb)
{
if (_bindst != ulStatusCode)
{
_bindst = ulStatusCode;
if (pdoh->_hwndIcons) {
// InvalidateRect(pdoh->_hwndIcons, NULL, TRUE);
// UpdateWindow(pdoh->_hwndIcons);
RedrawWindow(pdoh->_hwndIcons, NULL, NULL,
RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW);
}
char szStatusText[MAX_PATH]; // OK with MAX_PATH
if (pwzStatusText) {
WideCharToMultiByte(CP_ACP, 0, pwzStatusText, -1, szStatusText, ARRAYSIZE(szStatusText), NULL, NULL);
} else {
lstrcpy(szStatusText, "...");
}
//
// This if-block will open the safe open dialog for OLE Object
// and DocObject.
//
if (_bindst == BINDSTATUS_CLASSIDAVAILABLE) {
DebugMsg(TF_SHDPROGRESS, TEXT("DOH::BSC::OnProgress got CLSID=%s"), szStatusText);
CLSID clsid;
// WORK-AROUND: CLSIDFromString does not take LPCOLESTR correctly.
HRESULT hresT = CLSIDFromString((LPOLESTR)pwzStatusText, &clsid);
if (SUCCEEDED(hresT)) {
hresT = pdoh->_MayHaveVirus(clsid);
if (hresT == HRESULT_FROM_WIN32(ERROR_CANCELLED)) {
AbortBinding();
}
} else {
DebugMsg(DM_ERROR, TEXT("DOH::BSC::OnProgress CLSIDFromString failed %x"), hresT);
}
} else if (_bindst == BINDSTATUS_CACHEFILENAMEAVAILABLE) {
DebugMsg(DM_SELFASC, TEXT("DOH::OnProgress got BINDSTATUS_CACHEFILENAMEAVAILABLE"));
_fSelfAssociated = _IsAssociatedWithIE(pwzStatusText);
}
if (_bindst >= BINDSTATUS_FINDINGRESOURCE
&& _bindst <= BINDSTATUS_SENDINGREQUEST)
{
char szTemplate[MAX_PATH]; // OK with MAX_PATH
if (LoadString(HINST_THISDLL, IDS_BINDSTATUS+_bindst,
szTemplate, ARRAYSIZE(szTemplate)))
{
BSCMSGS("OnProgress szTemplate=", szTemplate);
TCHAR szMessage[MAX_PATH]; // OK with MAX_PATH
BOOL fSuccess = _FormatMessage(szTemplate, szMessage, ARRAYSIZE(szMessage), szStatusText);
if (fSuccess)
{
BSCMSGS("OnProgress szMessage=", szMessage);
pdoh->_SetStatusText(szMessage);
}
}
}
}
switch (ulStatusCode)
{
case BINDSTATUS_REDIRECTING:
// they're redirecting. treat this as a rename.
_Redirect(pwzStatusText);
break;
}
// set progress control and fire progress events
pdoh->_OnSetProgressMax(ulProgressMax);
pdoh->_OnSetProgressPos(ulProgress);
}
#ifndef NO_DELEGATION
if (_pbscChained) {
_pbscChained->OnProgress(ulProgress, ulProgressMax, ulStatusCode, pwzStatusText);
}
#endif
return S_OK;
}
HRESULT CDocObjectHost::CBindStatusCallback::OnDataAvailable(
/* [in] */ DWORD grfBSC,
/* [in] */ DWORD dwSize,
/* [in] */ FORMATETC *pformatetc,
/* [in] */ STGMEDIUM *pstgmed)
{
BSCMSG(TEXT("OnDataAvailable (grf,pstg)"), grfBSC, pstgmed);
CDocObjectHost* pdoh = IToClass(CDocObjectHost, _bsc, this);
#ifndef NO_DELEGATION
if (_pbscChained) {
_pbscChained->OnDataAvailable(grfBSC, dwSize, pformatetc, pstgmed);
}
#endif
return S_OK;
}
void CDocObjectHost::CBindStatusCallback::_UpdateSSLIcon(void)
{
CDocObjectHost* pdoh = IToClass(CDocObjectHost, _bsc, this);
if (pdoh->_hwndIcons)
{
#define DM_SSL 0
pdoh->_dwDOCHF &= ~DOCHF_SSL;
Assert(_pib);
if (_pib) {
IWinInetInfo* pwinet;
HRESULT hresT = _pib->QueryInterface(IID_IWinInetInfo, (LPVOID*)&pwinet);
if (SUCCEEDED(hresT)) {
DWORD dwOptions = 0;
DWORD cbSize = SIZEOF(dwOptions);
hresT = pwinet->QueryOption(INTERNET_OPTION_SECURITY_FLAGS,
(LPVOID)&dwOptions, &cbSize);
DebugMsg(DM_SSL, "pwinet->QueryOptions hres=%x dwOptions=%x", hresT, dwOptions);
if (SUCCEEDED(hresT)
&& (dwOptions & SECURITY_FLAG_SECURE)) {
pdoh->_dwDOCHF |= DOCHF_SSL;
}
pwinet->Release();
} else {
DebugMsg(DM_SSL, "QI to IWinInetInfo failed");
}
}
InvalidateRect(pdoh->_hwndIcons, NULL, TRUE);
}
}
void CDocObjectHost::_ActivateOleObject(void)
{
HRESULT hres;
_pole->SetClientSite(NULL);
if (_fDontInPlaceNavigate()) {
DebugMsg(TF_SHDAPPHACK, TEXT("CDOH::_ActivateOleObject calling DoVerb because of _fDontInPlaceNavigate()"));
}
hres = _pole->DoVerb(
_fUseOpenVerb() ? OLEIVERB_OPEN : OLEIVERB_PRIMARY,
NULL, NULL, (UINT)-1, NULL, NULL);
if (SUCCEEDED(hres)) {
CShdAdviseSink_Advise(_pwb, _pole);
} else {
DebugMsg(DM_ERROR, TEXT("CDOH::_ActivateOleObject DoVerb failed %x."), hres);
}
// We must release the OLE object to avoid calling Close
// from _UnBind.
_ReleaseOleObject();
}
//
// The docobject's READYSTATE property may have changed
//
HRESULT CDocObjectHost::_OnChangedReadyState()
{
IDispatch * p_idispatch;
Assert(_pole);
if (!_pole)
return E_UNEXPECTED;
if (SUCCEEDED(_pole->QueryInterface( IID_IDispatch, (LPVOID*) &p_idispatch)))
{
DISPPARAMS dp = {NULL, NULL, 0, 0};
VARIANTARG va;
EXCEPINFO exInfo;
va.vt = 0;
if (FAILED(p_idispatch->Invoke( DISPID_READYSTATE, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET, &dp, &va, &exInfo, NULL))
|| va.vt != VT_I4)
{
// We set up this sink if everything worked in the first case,
// so we should never hit this case.
//
Assert(FALSE);
}
else
{
// BUGBUG TODO: forward READYSTATE value to WebBrowserOC (if it exists)
IShellHTMLWindowSupport *phtmlWS = NULL;
if( SUCCEEDED(_psp->QueryService( SID_SOmWindow, IID_IShellHTMLWindowSupport, (void**)&phtmlWS )) )
{
phtmlWS->ReadyStateChangedTo( va.lVal, _psv );
phtmlWS->Release( );
}
if (va.lVal >= READYSTATE_INTERACTIVE)
{
// Technically we can get this value multiple times,
// so make sure we call _Navigate only once.
//
if (!_fReadystateInteractiveProcessed)
{
_fReadystateInteractiveProcessed = TRUE;
_Navigate();
}
if (va.lVal == READYSTATE_COMPLETE)
{
// We're done with this property. We should only
// get this value once because we remove our sink here.
//
_RemoveTransitionCapability();
}
}
}
p_idispatch->Release();
}
return( NOERROR );
}
HRESULT CDocObjectHost::OnRequestEdit(DISPID dispid)
{
return E_NOTIMPL;
}
//
// OnChanged
//
// Notification from the DocObject that one of its
// properties has changed.
//
HRESULT CDocObjectHost::OnChanged(DISPID dispid)
{
if (DISPID_READYSTATE == dispid || DISPID_UNKNOWN == dispid)
return _OnChangedReadyState();
return S_OK;
}
//
// CDocObjectHost::_SetUpTransitionCapability()
//
// Returns TRUE iff all the following hold true:
// - object has readystate property
// - readystate property is currently < interactive
// - Object supports IPropertyNotifySink
// Then this object supports delayed switching when it
// it tells us that it is ready...
//
// This is how we switch pages only when the new page is ready to be
// switched to. Also, by doing this we can also make the switch smooth
// by applying graphical transitions.
//
BOOL CDocObjectHost::_SetUpTransitionCapability()
{
// By default DocObject doesn't have gray-flash communication
BOOL fSupportsReadystate = FALSE;
// Sanity Check
if (!_pole)
return(fSupportsReadystate);
// Check for proper readystate support
BOOL fReadyStateOK = FALSE;
IDispatch * p_idispatch;
if (SUCCEEDED(_pole->QueryInterface( IID_IDispatch, (LPVOID*) &p_idispatch )))
{
DISPPARAMS dp = { NULL, NULL, 0, 0 };
VARIANTARG va;
EXCEPINFO exInfo;
if (SUCCEEDED(p_idispatch->Invoke( DISPID_READYSTATE, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET, &dp, &va, &exInfo, NULL)))
{
if ((va.vt == VT_I4) && (va.lVal < READYSTATE_INTERACTIVE))
{
fReadyStateOK = TRUE;
}
}
p_idispatch->Release();
}
if (! fReadyStateOK)
return( fSupportsReadystate );
// Check and Set-Up IPropertyNotifySink
IConnectionPointContainer * p_icpc;
if (SUCCEEDED(_pole->QueryInterface( IID_IConnectionPointContainer, (LPVOID*) &p_icpc)))
{
IConnectionPoint * p_icp;
if (SUCCEEDED(p_icpc->FindConnectionPoint( IID_IPropertyNotifySink, &p_icp)))
{
if (SUCCEEDED(p_icp->Advise(SAFECAST(this, IPropertyNotifySink*), &_dwPropNotifyCookie )))
fSupportsReadystate = TRUE;
p_icp->Release();
}
p_icpc->Release();
}
return(fSupportsReadystate);
}
// This removes any property notify sink we set up
//
void CDocObjectHost::_RemoveTransitionCapability()
{
if (_dwPropNotifyCookie)
{
IConnectionPointContainer * p_icpc;
Assert(_pole);
if (!_pole)
return;
if (SUCCEEDED(_pole->QueryInterface( IID_IConnectionPointContainer, (LPVOID*) &p_icpc)))
{
IConnectionPoint * p_icp;
if (SUCCEEDED(p_icpc->FindConnectionPoint( IID_IPropertyNotifySink, &p_icp )))
{
p_icp->Unadvise(_dwPropNotifyCookie);
_dwPropNotifyCookie = 0;
p_icp->Release();
}
p_icpc->Release();
}
}
}
HRESULT CDocObjectHost::CBindStatusCallback::OnObjectAvailable(
/* [in] */ REFIID riid,
/* [iid_is][in] */ IUnknown *punk)
{
BSCMSG(TEXT("OnObjectAvailable (riid,punk)"), riid, punk);
CDocObjectHost* pdoh = IToClass(CDocObjectHost, _bsc, this);
#ifdef DEBUG
PERFMSG(TEXT("OnObjectAvailable called"), GetCurrentTime()-g_dwPerf);
g_dwPerf = GetCurrentTime();
#endif
//
// When this notification is called first time, we should ask
// the browser to activate us (which causes BindToObject).
//
if (pdoh->_pole==NULL && punk)
{
HRESULT hresT = punk->QueryInterface(IID_IOleObject, (LPVOID*)&(pdoh->_pole));
if (SUCCEEDED(hresT)) {
IOleDocument* pmsod = NULL;
pdoh->_OnBound(S_OK);
hresT = (pdoh->_fDontInPlaceNavigate() ? E_NOINTERFACE : punk->QueryInterface(IID_IOleDocument, (LPVOID*)&pmsod));
if (SUCCEEDED(hresT)) {
pmsod->Release(); // We don't use it at this point.
// Case 1: DocObject
OPENMSG(TEXT("OnObjectAvailable ASYNC DocObject"));
Assert(pdoh->_psb);
#ifdef FEATURE_PICS
IOleCommandTarget *pct;
BOOL fSupportsPICS = FALSE;
if (SUCCEEDED(pdoh->_pole->QueryInterface(IID_IOleCommandTarget, (LPVOID *)&pct))) {
VARIANTARG v;
v.vt = VT_UNKNOWN;
v.lVal = (DWORD)(IOleCommandTarget *)&pdoh->_ctPics;
hresT = pct->Exec(&CGID_ShellDocView, SHDVID_CANSUPPORTPICS, 0, &v, NULL);
if (hresT == S_OK) {
BSCMSG(TEXT("OnObjectAvailable - obj supports PICS"), 0, 0);
fSupportsPICS = TRUE;
}
else {
BSCMSG(TEXT("OnObjectAvailable - obj doesn't support PICS"), hresT, 0);
}
pct->Release();
}
else {
BSCMSG(TEXT("OnObjectAvailable - obj doesn't support IOleCommandTarget"), 0, 0);
}
#endif
BSCMSG(TEXT("OnObjectAvailable calling pdoh->_Navigate"), 0, 0);
if (!pdoh->_SetUpTransitionCapability())
pdoh->_Navigate();
_UpdateSSLIcon();
#ifdef FEATURE_PICS
if (!fSupportsPICS) {
pdoh->_fbPicsWaitFlags &= ~(PICS_WAIT_FOR_INDOC | PICS_WAIT_FOR_END); /* no indoc ratings */
if (!pdoh->_fbPicsWaitFlags) {
if (!pdoh->_HandlePicsChecksComplete())
AbortBinding();
}
}
#endif
} else {
// Case 2: OLE object
OPENMSG(TEXT("OnDataAvailable ASYNC OLE Object"));
pdoh->_ActivateOleObject();
// We need to tell the browser not to add this one to the
// browse history.
pdoh->_CancelPendingNavigation();
//
// If this is the very first page, we should draw the background.
//
pdoh->_fDrawBackground = TRUE;
//If the following assert is hit, then that means that we are
// going to invalidate the desktop window (which is not
// intended here)
//
Assert(pdoh->_hwnd);
InvalidateRect(pdoh->_hwnd, NULL, TRUE);
}
} else {
_fBoundToNoOleObject = TRUE;
}
}
#ifndef NO_DELEGATION
if (_pbscChained) {
_pbscChained->OnObjectAvailable(riid, punk);
}
#endif
return S_OK;
}
HRESULT CDocObjectHost::CBindStatusCallback::OnLowResource(DWORD reserved)
{
BSCMSG(TEXT("OnLowResource"), 0, 0);
#ifndef NO_DELEGATION
if (_pbscChained) {
_pbscChained->OnLowResource(reserved);
}
#endif
return S_OK;
}
// BUGBUG chrisfra 7/5/96. this is a facility that we should consider adding to
// URLMON. the object created by our BindToObject needs to know Referer from
// request headers and if Pragma: No-Cache occurs in response headers (at a
// minimum
#define PUT_HEADERS_IN_CTX
#ifdef PUT_HEADERS_IN_CTX
/* creates an IStream fills it with ascii version ofpwzValue and registers it in
_pbc under key pwzKey */
HRESULT RegisterWString(IBindCtx *_pbc, LPCWSTR pwzKey, LPCWSTR pwzValue)
{
LPSTREAM pstream;
HRESULT hres = S_OK;
ULONG cbValue = 0;
LPTSTR pString;
if (pwzValue)
{
hres = CreateStreamOnHGlobal(NULL, TRUE, &pstream);
if (SUCCEEDED(hres))
{
cbValue = WideCharToMultiByte(CP_ACP, 0, pwzValue, -1,
NULL, 0, NULL, NULL);
pString = (LPTSTR)LocalAlloc(LPTR, cbValue);
if (pString)
{
cbValue = WideCharToMultiByte(CP_ACP, 0, pwzValue, -1,
pString, cbValue, NULL, NULL);
hres = pstream->Write(pString, cbValue, NULL);
if (SUCCEEDED(hres))
{
hres = _pbc->RegisterObjectParam((LPWSTR) pwzKey, pstream);
}
LocalFree(pString);
}
pstream->Release(); // RegisterObjectParam AddRef's pstream
}
}
return hres;
}
#endif
HRESULT CDocObjectHost::CBindStatusCallback::BeginningTransaction(LPCWSTR szURL, LPCWSTR szHeaders,
DWORD dwReserved, LPWSTR __RPC_FAR * ppwzAdditionalHeaders)
{
HRESULT hres;
#ifndef NO_DELEGATION
if (_pnegotiateChained) {
hres = _pnegotiateChained->BeginningTransaction(szURL, szHeaders, dwReserved, ppwzAdditionalHeaders);
}
else
{
#endif
// Here we pass headers to URLMon
hres=BuildAdditionalHeaders((LPCSTR) _pszHeaders,(LPCWSTR *) ppwzAdditionalHeaders);
#ifndef NO_DELEGATION
}
#endif
#ifdef PUT_HEADERS_IN_CTX
// The only case _pbc is NULL is the OpenUIPost() downloading case
if (SUCCEEDED(hres) && _pbc)
{
RegisterWString(_pbc, TEXT(L"HTTP-REQUEST-HEADERS"),*ppwzAdditionalHeaders);
}
#endif
return hres;
}
HRESULT CDocObjectHost::CBindStatusCallback::OnResponse(DWORD dwResponseCode, LPCWSTR szResponseHeaders,
LPCWSTR szRequestHeaders,
LPWSTR *pszAdditionalRequestHeaders)
{
#ifndef NO_DELEGATION
if (_pnegotiateChained) {
_pnegotiateChained->OnResponse(dwResponseCode, szResponseHeaders, szRequestHeaders, pszAdditionalRequestHeaders);
}
else
{
#endif
// This is a no-op for us
;
#ifndef NO_DELEGATION
}
#endif
#ifdef PUT_HEADERS_IN_CTX
RegisterWString(_pbc, TEXT(L"HTTP-RESPONSE-HEADERS"), szResponseHeaders);
#endif
return S_OK;
}
HRESULT CDocObjectHost::CBindStatusCallback::GetWindow(REFGUID rguidReason, HWND* phwnd)
{
CDocObjectHost* pdoh = IToClass(CDocObjectHost, _bsc, this);
if (!phwnd)
return E_POINTER;
if (pdoh->_psb) {
pdoh->_psb->GetWindow(phwnd);
} else {
*phwnd = pdoh->_hwnd;
}
return S_OK;
}
HRESULT CDocObjectHost::CBindStatusCallback::OnSecurityProblem(DWORD dwProblem)
{
// force UI - return S_FALSE for all problems
return S_FALSE;
}
void CDocObjectHost::_Navigate()
{
#ifdef OLD_HLIFACE
Assert(_phf);
if (!_bsc._pbscChained) {
NAVMSG3(TEXT("_Navigate calling _phf->Navigate"), 0, NULL);
// tell hlframe to release its states.
_phf->Navigate(0, NULL);
}
else
#endif
{
// all's ready... switch to it now.
NAVMSG3(TEXT("_Navigate calling _psb->BrowseObject"), 0, NULL);
_psb->BrowseObject(&s_idNull, SBSP_RELATIVE);
}
}
void CDocObjectHost::_CancelPendingNavigation()
{
Assert(_phf);
// the hlframe no longer knows if the clear was a cancel or a start of navigation
// because we don't call anything tosignal a successfull navigation
if (_pmsoctBrowser) {
DebugMsg(DM_TRACE, TEXT("DOH::_CancelPendingNavigation calling _pmsc->Exec"));
_pmsoctBrowser->Exec(&CGID_Explorer, SBCMDID_CANCELNAVIGATION, 0, NULL, NULL);
}
// release our navigation state
_phf->Navigate(0, NULL, NULL, (IHlink*)-1);
}
void CDocObjectHost::_DoAsyncNavigation(LPCWSTR pwzURL)
{
VARIANT vararg = {0};
vararg.vt = VT_BSTR;
vararg.bstrVal = SysAllocString (pwzURL);
if (_pmsoctBrowser) {
DebugMsg(DM_TRACE, TEXT("DOH::_DoAsyncNavigation calling _pmsc->Exec"));
_pmsoctBrowser->Exec(&CGID_Explorer, SBCMDID_ASYNCNAVIGATION, 0, &vararg, NULL);
}
VariantClear(&vararg);
}
UINT IE_ErrorMsgBox(IShellBrowser* psb,
HWND hwndOwner, HRESULT hrError, LPCWSTR szError, LPCTSTR pszURLparam,
UINT idResource, UINT wFlags)
{
UINT uRet;
TCHAR szMsg[MAX_PATH];
LPCTSTR pszURL = TEXT("");
// if a URL was specified, use it; otherwise use empty string
if (pszURLparam)
pszURL = pszURLparam;
//
// NOTES: This table of error code will be mapped to (IDS_ERRMSG_FIRST +
// offset) and we LoadString it.
//
const static c_ahres[] = {
HRESULT_FROM_WIN32(ERROR_INTERNET_INVALID_URL),
HRESULT_FROM_WIN32(ERROR_INTERNET_NAME_NOT_RESOLVED),
INET_E_UNKNOWN_PROTOCOL,
};
for (int i=0; i<ARRAYSIZE(c_ahres); i++) {
if (c_ahres[i]==hrError) {
LoadString(HINST_THISDLL, IDS_ERRMSG_FIRST+i,
szMsg, ARRAYSIZE(szMsg));
break;
}
}
if (i >= ARRAYSIZE(c_ahres))
{
// Default message if FormatMessage doesn't recognize dwLastError
LoadString(HINST_THISDLL, IDS_UNDEFINEDERR, szMsg, ARRAYSIZE(szMsg));
if (hrError >= HRESULT_FROM_WIN32(INTERNET_ERROR_BASE)
&& hrError <= HRESULT_FROM_WIN32(INTERNET_ERROR_LAST))
{
HMODULE hmod = GetModuleHandle("WININET");
Assert(hmod);
FormatMessage(FORMAT_MESSAGE_FROM_HMODULE, (LPCVOID)hmod, HRESULT_CODE(hrError), 0L,
szMsg, ARRAYSIZE(szMsg), NULL);
} else {
// See if one of the system components has an error message
// for this error. If not, szMsg will retain our default
// message to handle this.
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, hrError, 0L,
szMsg, ARRAYSIZE(szMsg), NULL);
}
}
if (psb) {
psb->AddRef();
psb->EnableModelessSB(FALSE);
}
uRet = ShellMessageBox(HINST_THISDLL, hwndOwner,
MAKEINTRESOURCE(idResource),
MAKEINTRESOURCE(IDS_TITLE),
wFlags, pszURL,szMsg);
if (psb) {
psb->EnableModelessSB(TRUE);
UINT cRef = psb->Release();
AssertMsg(cRef>0, TEXT("IE_ErrorMsgBox psb->Release returned 0."));
}
return uRet;
}
// See if the URL is of a type that we should
// ShellExecute()
//
BOOL ShouldShellExecURL( LPTSTR pszURL )
{
BOOL rval = FALSE;
TCHAR *pszUrlCopy = StrDup( pszURL );
if (pszUrlCopy)
{
// change "foo:blah" to "foo" by temporarily replacing first colon
TCHAR *pchColon = StrChr( pszUrlCopy, ':' );
if (pchColon)
{
HKEY hkProtoKey;
*pchColon = 0;
// Check and confirm that it is a URL Protocol
if (RegOpenKey( HKEY_CLASSES_ROOT, pszUrlCopy, &hkProtoKey ) == ERROR_SUCCESS)
{
DWORD dwType;
BYTE abBuffer[64];
DWORD cbBuffer = sizeof(abBuffer);
if (RegQueryValueEx( hkProtoKey, TEXT("URL Protocol"), NULL, &dwType, abBuffer, &cbBuffer ) == ERROR_SUCCESS)
{
rval = TRUE;
}
RegCloseKey( hkProtoKey );
}
}
LocalFree( pszUrlCopy );
}
return rval;
}
HRESULT CDocObjectHost::CBindStatusCallback::_HandleSelfAssociate(void)
{
CDocObjectHost* pdoh = IToClass(CDocObjectHost, _bsc, this);
HRESULT hres;
IPersistMoniker* ppmk;
hres = CoCreateInstance(CLSID_HTMLViewer, NULL, CLSCTX_INPROC_SERVER|CLSCTX_LOCAL_SERVER,
IID_IPersistMoniker, (LPVOID*)&ppmk);
if (SUCCEEDED(hres)) {
BIND_OPTS bindopts;
bindopts.cbStruct = sizeof(BIND_OPTS);
hres = _pbc->GetBindOptions(&bindopts);
if (SUCCEEDED(hres)) {
hres = ppmk->Load(FALSE, pdoh->_pmkCur, _pbc, bindopts.grfMode);
if (SUCCEEDED(hres)) {
Assert(NULL==pdoh->_pole);
hres = ppmk->QueryInterface(IID_IOleObject, (LPVOID*)&pdoh->_pole);
if (SUCCEEDED(hres)) {
pdoh->_InitOleObject();
DebugMsg(DM_SELFASC, TEXT("DOH::_HandleSelfAssociate self-association is working"));
pdoh->_Navigate();
_UpdateSSLIcon();
} else {
DebugMsg(DM_WARNING, TEXT("DOH::_HandleSelfAssociate ppmk->QI(IOleObject) failed (%x)"), hres);
}
} else {
DebugMsg(DM_WARNING, TEXT("DOH::_HandleSelfAssociate ppmk->Load failed (%x)"), hres);
}
} else {
DebugMsg(DM_WARNING, TEXT("DOH::_HandleSelfAssociate _pbc->GetBindOptions failed (%x)"), hres);
}
ppmk->Release();
} else {
DebugMsg(DM_WARNING, TEXT("DOH::_HandleSelfAssociate CoCreateInst failed (%x)"), hres);
}
return hres;
}
#define BUG_EXEC_ON_FAILURE // BUGBUG nash:31526
HRESULT CDocObjectHost::CBindStatusCallback::OnStopBinding(HRESULT hrError,
LPCWSTR szError)
{
BSCMSG(TEXT("OnStopBinding"), this, hrError);
_fBinding = FALSE;
CDocObjectHost* pdoh = IToClass(CDocObjectHost, _bsc, this);
LPWSTR pwzHeaders = NULL;
BOOL fShouldDisplayError = TRUE;
DWORD dwStatusCode = 0; // We use 0 to mean no status yet
DWORD dwStatusCodeSize = sizeof(dwStatusCode);
BOOL bFrameIsSilent = FALSE;
// Why not use the cached value?
// pdoh->_GetOfflineSilent(0, &bFrameIsSilent);
bFrameIsSilent = _bFrameIsSilent ? TRUE : FALSE;
_bindst = 0; // go back to the normal state
if (!_pbc) {
Assert(0);
return S_OK;
}
// NOTES: Guard against last Release by _RevokeObjectParam
AddRef();
if (pdoh->_pwb)
pdoh->_pwb->SetNavigateState(BNS_NORMAL);
if (pdoh->_psb) { // paranoia
pdoh->_psb->SetStatusTextSB(NULL);
}
BSCMSG("OnStopBinding calling _RevokeObjectParam", this, _pbc);
_RevokeObjectParam(_pbc);
_pbc->RevokeObjectParam(WSZGUID_OPID_DocObjClientSite);
//
// If the error code is a mapped error code (by URLMON), get the
// real error code from IBinding for display purpose.
//
HRESULT hrDisplay = hrError; // assume they are the same
#define ENABLE_WHEN_GETBINDRESULT_STARTS_WORKING
#ifdef ENABLE_WHEN_GETBINDRESULT_STARTS_WORKING
if (hrError>=INET_E_ERROR_FIRST && hrError<=INET_E_ERROR_LAST) {
//
// We come here when _pib==NULL, if URLMON synchronously fails
// (such as a bad protocol).
//
// Assert(_pib);
//
if (_pib) {
CLSID clsid;
LPWSTR pwszError = NULL;
HRESULT hresT=_pib->GetBindResult(&clsid, (DWORD *)&hrDisplay, &pwszError, NULL);
DebugMsg(TF_SHDBINDING, TEXT("DOH::OnStopBinding called GetBindResult %x->%x (%x)"), hrError, hrDisplay, hresT);
if (SUCCEEDED(hresT)) {
//
// BUGBUG: URLMON returns a native Win32 error.
//
if (hrDisplay && SUCCEEDED(hrDisplay)) {
hrDisplay = HRESULT_FROM_WIN32(hrDisplay);
}
if (pwszError) {
OleFree(pwszError);
}
}
}
}
#endif
//
// HACK: If the object is associated with IE/Shell itself, but has
// no CLSID, we'll force MSHTML.
//
if (_fSelfAssociated && (hrError==MK_E_INVALIDEXTENSION || hrError==REGDB_E_CLASSNOTREG)) {
hrError = _HandleSelfAssociate();
}
if (_pib) {
SYSTEMTIME HTMLDate;
// get the expire info
// The HTTP rules for expiration are
// Expires: 0 expire immediately
// if Expires: <= Date: expire immediately
// if Expires: bad format expire immediately
IWinInetHttpInfo *phi;
if (SUCCEEDED(_pib->QueryInterface(IID_IWinInetHttpInfo, (LPVOID*)&phi))) {
BYTE abBuffer[256]; // We don't care about this data, just
DWORD cbBuffer=sizeof(abBuffer); // whether it exists or not
HRESULT hr;
DWORD dwSize = sizeof(SYSTEMTIME);
BOOL fExpiresExists = FALSE;
if (phi->QueryInfo(HTTP_QUERY_LAST_MODIFIED, &abBuffer, &cbBuffer, NULL, 0) == S_OK)
pdoh->_fhasLastModified = TRUE;
if (phi->QueryInfo(HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, &dwStatusCode, &dwStatusCodeSize, NULL, 0) != S_OK) {
dwStatusCode = 0; // failed to get status code
dwStatusCodeSize = 0; // failed to get status code
}
// There's a bug in WinInet which returns S_FALSE for pages w/o
// Expires: headers, when it should return E_FAIL. So we check
// twice to differentiate the case where it simply does not exist,
// and the one where it is malformed.
cbBuffer = sizeof(abBuffer); // don't care about data itself
hr = E_FAIL;
if (phi->QueryInfo(HTTP_QUERY_EXPIRES, &abBuffer, &cbBuffer, NULL, 0) == S_OK) {
fExpiresExists = TRUE;
hr = phi->QueryInfo(HTTP_QUERY_EXPIRES | HTTP_QUERY_FLAG_SYSTEMTIME, &pdoh->_stExpires, &dwSize, NULL, 0);
}
dwSize = sizeof(HTMLDate); // set for If below
if (hr != S_OK) {
// Note: we also check expires time in GetObject(), in
// case MSHTML has parsed a meta tag for it.
// by no expire if no expire set
pdoh->_stExpires.wYear = 0;
// S_FALSE means a malformed Expires: header, which will
// expire immediately.
// BUGBUG tonyci 15oct96 WinInet should only return S_FALSE
// if Expires: actually exists, but it returns it in all
// cases but success.
if ((hr == S_FALSE) && (fExpiresExists)) {
pdoh->_stExpires.wYear = 1;
}
switch (dwStatusCode) {
case HTTP_STATUS_DENIED:
case HTTP_STATUS_PROXY_AUTH_REQ:
pdoh->_stExpires.wYear = 1; // expires in the year 1 (immediate)
break;
default:
break;
}
} else if (phi->QueryInfo(HTTP_QUERY_DATE | HTTP_QUERY_FLAG_SYSTEMTIME, &HTMLDate, &dwSize, NULL, 0) == S_OK) {
// If Date: is >= Expires:, expire immediately
if (CmpSystemtime(&HTMLDate, &pdoh->_stExpires) >= 0) {
DebugMsg(TF_SHDBINDING, TEXT("sd DOH::OnStopBinding Expires: <= Date:"));
pdoh->_stExpires.wYear = 1; // expire immediately
}
}
// This code will decide if we should display a popup error;
// essentially, it detects if we can reasonably assume that
// HTML was returned in the error case; if so, we believe that
// it is an error page, so we let that display rather than a
// popup.
if (dwStatusCode) {
// We got a status code; let's see if we have a
// content-type.
// HTTP retcode 204 is a "succeeded, do nothing" retcode
// So we should always suppress the popup; further, it is
// spec'd to NEVER have content, so we do this before checking
// for content-type.
// So is 100
// BUGBUG: 100 is not in wininet.h
if (dwStatusCode == HTTP_STATUS_NO_CONTENT)
fShouldDisplayError = FALSE;
// BUGBUG: what is max header size?
CHAR szContentType[1024];
DWORD dwContentTypeSize = sizeof(szContentType);
// This code handles a bug in URLMON where it tells us INET_E_DATA_NOT_AVAILABLE when in fact the
// data _was_ available. We don't want any future errors affected by this, so we restrict this
// hack to less than 600, and ONLY for the INET_E_DATA_NOT_AVAILABLE case.
if (hrError == INET_E_DATA_NOT_AVAILABLE && dwStatusCode < 600 &&
phi->QueryInfo(HTTP_QUERY_CONTENT_TYPE, &szContentType, &dwContentTypeSize, NULL, 0) == S_OK)
fShouldDisplayError = FALSE;
}
// Check for Pragma: No-Cache last; it overrides Expires:
cbBuffer = sizeof(abBuffer);
if (phi->QueryInfo(HTTP_QUERY_PRAGMA, &abBuffer, &cbBuffer, NULL, 0) == S_OK) {
if (StrStrI((LPSTR)&abBuffer, TEXT("no-cache")) != NULL)
pdoh->_stExpires.wYear = 1; // expires in the year 1 (immediate)
}
phi->Release();
}
ATOMICRELEASE(_pib);
}
if (pdoh->_hwndProgress) {
ShowWindow(pdoh->_hwndProgress, SW_HIDE);
}
if (_psvPrev) {
ATOMICRELEASE(_psvPrev);
}
//
// If the object does not support IOleObject, treat it as if we failed
// to bind.
//
if (_fBoundToNoOleObject) {
Assert(SUCCEEDED(hrError));
hrError = MK_E_INVALIDEXTENSION;
}
// bugbug:: need to handle navigation in successful proxy response but w/
// 404 error. tonyci 13nov96. for autosearching & autosuffixing
if (FAILED(hrError)) {
TCHAR szURL[MAX_URL_STRING+1];
szURL[0] = TEXT('\0');
if (pdoh->_pmkCur) {
pdoh->_GetCurrentPage(szURL,ARRAYSIZE(szURL));
} else {
Assert((hrError == HRESULT_FROM_WIN32(ERROR_CANCELLED))
|| (hrError == E_ABORT));
}
DebugMsg(TF_SHDBINDING, TEXT("DOH::OnStopBinding hrError=%x"), hrError);
switch(hrError) {
//
// If pmk->BindToObject is failed because of "binding", we should
// offer an option to download it as a file.
//
#ifdef BUG_EXEC_ON_FAILURE
case INET_E_CANNOT_INSTANTIATE_OBJECT:
DebugMsg(TF_SHDBINDING, TEXT("DOH::OnStopBinding IDS_ERR_OLESVR"));
_SetSearchInfo (pdoh->_psp, 0, FALSE, FALSE, FALSE); // reset info
goto Lexec;
case INET_E_CANNOT_LOAD_DATA:
DebugMsg(TF_SHDBINDING, TEXT("DOH::OnStopBinding IDS_ERR_LOAD"));
_SetSearchInfo (pdoh->_psp, 0, FALSE, FALSE, FALSE); // reset info
goto Lexec;
#else
case INET_E_CANNOT_INSTANTIATE_OBJECT:
_SetSearchInfo (pdoh->_psp, 0, FALSE, FALSE, FALSE); // reset info
if (ShellMessageBox(HINST_THISDLL, pdoh->_hwnd,
MAKEINTRESOURCE(IDS_ERR_OLESVR),
MAKEINTRESOURCE(IDS_TITLE),
MB_YESNO|MB_ICONERROR,
szURL) == IDYES) {
CDownLoad_OpenUI(pdoh->_pmkCur, _pbc, FALSE, TRUE, NULL);
}
break;
case INET_E_CANNOT_LOAD_DATA:
_SetSearchInfo (pdoh->_psp, 0, FALSE, FALSE, FALSE); // reset info
// e.g. click on .xls link when doc already open/modified/locked
// and say 'cancel'
if (ShellMessageBox(HINST_THISDLL, pdoh->_hwnd,
MAKEINTRESOURCE(IDS_ERR_LOAD),
MAKEINTRESOURCE(IDS_TITLE),
MB_YESNO|MB_ICONERROR,
szURL) == IDYES) {
CDownLoad_OpenUI(pdoh->_pmkCur, _pbc, FALSE, TRUE, NULL);
}
break;
#endif
//
// NOTES: According to JohannP, URLMON will give us
// REGDB_E_CLASSNOTREG. I'll leave MK_E_INVALIDEXTENSION
// to be compatible with old URLMON (which is harmless).
//
case MK_E_INVALIDEXTENSION:
case REGDB_E_CLASSNOTREG:
_SetSearchInfo (pdoh->_psp, 0, FALSE, FALSE, FALSE); // reset info
#ifdef BUG_EXEC_ON_FAILURE
Lexec: // BUGBUG nash:31526
// for various instantiation errors:
// - for ie3 we suppress messages and force a ShellExec as a
// 2nd try, pretty much always
// - for ie4 we should be more selective (BUGBUG nash:31526)
#endif
#ifdef FEATURE_PICS
/* For data types that don't have a CLSID, we never get a chance
* to block in the CLASSIDAVAILABLE OnProgress notification, so
* we have to block here. However, avoid blocking documents such
* as HTML which we want to download completely so we can get
* ratings strings out of them.
*/
if (!pdoh->_fPicsBlockLate && pdoh->_fbPicsWaitFlags) {
pdoh->_fbPicsWaitFlags &= ~(PICS_WAIT_FOR_INDOC | PICS_WAIT_FOR_END); /* make sure we don't expect indoc ratings */
if (pdoh->_PicsBlockingDialog(szURL) != IDOK) {
pdoh->_CancelPendingNavigation();
break;
}
}
#endif
BeginningTransaction (NULL, NULL, 0, &pwzHeaders);
if (_dwBindVerb==BINDVERB_POST) {
// This is a POST. Do it use the same moniker (modeless)
//
// Notes: The ownership of the data in binfo will be transfered
// to CDownLoad_OpenUIPost. Therefore, we should not call
// ReleaseStgMedium(&binfo.stgmedData) here.
//
DWORD grfBINDF;
BINDINFO binfo = { sizeof(BINDINFO) };
GetBindInfo(&grfBINDF, &binfo);
// If our POST was really a redirected POST, it will have
// turned into a GET. In this case, we need to release
// ownership of the data and pretend like the whole thing
// was a GET to start with.
if (binfo.dwBindVerb==BINDVERB_GET)
{
WCHAR wszUrl[INTERNET_MAX_URL_LENGTH];
ReleaseStgMedium(&binfo.stgmedData);
Assert (_pszRedirectedURL);
MultiByteToWideChar(CP_ACP, 0, _pszRedirectedURL, -1, (LPWSTR)&wszUrl, ARRAYSIZE(wszUrl));
CDownLoad_OpenUIURL((LPWSTR)&wszUrl, NULL, pwzHeaders,
FALSE /* fSync */, FALSE /* fSaveAs */, _fBoundToNoOleObject);
pwzHeaders = NULL; // ownership is to CDownload now
}
else {
Assert(binfo.dwBindVerb==BINDVERB_POST);
// Collect the headers associated with this xact
// These will be freed where we call ReleaseStgMedium() in
// OpenUIPost
CDownLoad_OpenUI(pdoh->_pmkCur, _pbc, FALSE /* fSync */, FALSE /* fSaveAs */, _fBoundToNoOleObject /* fSafe */, pwzHeaders, BINDVERB_POST, grfBINDF, &binfo);
pwzHeaders = NULL; // ownership is to CDownload now
DebugMsg(TF_SHDBINDING, TEXT("DOH::OnStopBinding just called CDownLoad_OpenUIPost"));
}
} else {
// Otherwise, spawn another thread and get it there.
// NOTE: If UnBind gets called then pdoh->_pmkCur will be NULL
// and URLMON is most likely returning a bogus error code. So
// we'll check the pointer and prevent from blowing up.
if (pdoh->_pmkCur)
{
CDownLoad_OpenUI(pdoh->_pmkCur, pdoh->_pbcCur, FALSE, FALSE, _fBoundToNoOleObject, pwzHeaders);
pwzHeaders = NULL; // ownership is to CDownload now
}
}
if (pwzHeaders)
CoTaskMemFree(pwzHeaders);
break;
// URLMON failed to bind because it didn't know what to do with
// with this URL. Lets check and see if the Shell should handle
// it via a helper app (news:, mailto:, telnet:, etc.)
case INET_E_UNKNOWN_PROTOCOL:
_SetSearchInfo (pdoh->_psp, 0, FALSE, FALSE, FALSE); // reset info
{
LPTSTR pszBadProtoURL;
if (_pszRedirectedURL)
pszBadProtoURL = _pszRedirectedURL;
else
pszBadProtoURL = szURL;
// Here we check to see if it is a URL we really want to shellexecute
// so it is handled by helper apps.....else it really is an error
if (ShouldShellExecURL( pszBadProtoURL )) {
// We need to decode this before passing it on to someone.
UCHAR szDecodedURL[INTERNET_MAX_URL_LENGTH];
DWORD cbDecodedURL = sizeof(szDecodedURL);
PrepareURLForExternalApp (pszBadProtoURL, (CHAR *)&szDecodedURL, &cbDecodedURL);
// Yes, according to documentation <= 32 means error!
if (ShellExecute( NULL, NULL, (CHAR *)&szDecodedURL, NULL, NULL, SW_SHOWNORMAL ) <= (HINSTANCE) 32) {
if(!bFrameIsSilent){
IE_ErrorMsgBox(pdoh->_psb, pdoh->_hwnd, hrDisplay, szError,
(CHAR *)&szDecodedURL, IDS_CANTSHELLEX, MB_OK | MB_ICONSTOP );
}
}
} else {
if(!bFrameIsSilent){
IE_ErrorMsgBox(pdoh->_psb, pdoh->_hwnd, hrDisplay,
szError, pszBadProtoURL,IDS_INVALIDURL, MB_OK|MB_ICONSTOP);
}
}
break;
}
case E_ABORT:
case HRESULT_FROM_WIN32(ERROR_CANCELLED):
_SetSearchInfo (pdoh->_psp, 0, FALSE, FALSE, FALSE); // reset info
break;
#ifdef BUG_EXEC_ON_FAILURE
case E_NOINTERFACE: // BUGBUG nash:31526
DebugMsg(TF_SHDBINDING, TEXT("DOH::OnStopBinding E_NOINTERFACE"));
goto Lexec;
#endif
case INET_E_RESOURCE_NOT_FOUND:
case INET_E_DATA_NOT_AVAILABLE:
if (_HandleFailedNavigationSearch(&fShouldDisplayError, dwStatusCode, pdoh, hrDisplay, (LPTSTR) &szURL, szError) != S_OK)
fShouldDisplayError = TRUE;
// intentional fallthrough to default to popup if needed
default:
{
if (fShouldDisplayError) {
_SetSearchInfo (pdoh->_psp, 0, FALSE, FALSE, FALSE); // reset info
if (!bFrameIsSilent)
IE_ErrorMsgBox(pdoh->_psb, pdoh->_hwnd, hrDisplay, szError,szURL,IDS_INVALIDURL, MB_OK|MB_ICONSTOP);
}
}
break;
}
//
// Prepare for the case where the container keep us visible
// after hitting this code (Explorer does, IE doesn't).
//
pdoh->_fDrawBackground = TRUE;
// In the case of quickly jumping to another link, we end up with
// a _hwnd being NULL and we were invalidating the desktop. So,
// I check for NULL here before calling InvalidateRect.
if(pdoh->_hwnd)
InvalidateRect(pdoh->_hwnd, NULL, TRUE);
//
// Tell the browser to cancel the pending navigation only
// if it has not been canceled by the browser itself.
//
if (!pdoh->_fCanceledByBrowser) {
pdoh->_CancelPendingNavigation();
} else {
DebugMsg(TF_SHDNAVIGATE|TF_SHDPROGRESS,
TEXT("DOH::::OnStopBinding not calling _CancelPendingNav"));
}
}
else
{
BOOL bDidNavigate = FALSE;
// It is still possible that our Proxy failed to find the server but
// gave us HTML. If this is the case, and the user has "find sites"
// set, we should go ahead and start trying to do our automatic
// navigation stuff.
if (dwStatusCode && DO_SEARCH_ON_STATUSCODE(dwStatusCode)) {
if (_HandleFailedNavigationSearch(&fShouldDisplayError, dwStatusCode, pdoh, hrDisplay, NULL, szError) == S_OK) {
bDidNavigate = TRUE;
}
// Note, since the Proxy will have given us HTML in this case,
// we will never display an error dialog.
}
if (!bDidNavigate) {
_SetSearchInfo (pdoh->_psp, 0, FALSE, FALSE, FALSE); // reset info
if (pdoh->_pmkCur)
{
TCHAR szUrl[MAX_URL_STRING+1];
TCHAR szDecodedUrl[MAX_URL_STRING+1];
DWORD cbDecodedUrl = SIZEOF(szDecodedUrl);
WCHAR wszUrl[MAX_URL_STRING+1];
pdoh->_GetCurrentPage(szUrl,ARRAYSIZE(szUrl));
if(InternetCanonicalizeUrl(szUrl, szDecodedUrl, &cbDecodedUrl, ICU_DECODE | ICU_NO_ENCODE))
{
if (pdoh->_pszLocation)
lstrcat(szDecodedUrl, pdoh->_pszLocation);
MultiByteToWideChar(CP_ACP, 0, szDecodedUrl, -1, wszUrl, ARRAYSIZE(wszUrl));
if(!bFrameIsSilent)
AddUrlToUrlHistoryStg(wszUrl, NULL, pdoh->_pwb, FALSE);
}
}
} // if !bDidNavigate
} // if failed(hrerror) ... else
// Released here because we may need it for OpenUI() w/ POST verb
ATOMICRELEASE(_pbc);
if (_pbscChained) {
#ifndef NO_DELEGATION
CHAINMSG("OnStopBinding", hrError);
_pbscChained->OnStopBinding(hrError, szError);
#endif
ATOMICRELEASE(_pbscChained);
}
if (_pnegotiateChained) {
ATOMICRELEASE(_pnegotiateChained);
}
pdoh->_SetStatusText(TEXT(""));
if (pdoh->_pbcCur) {
ATOMICRELEASE(pdoh->_pbcCur);
}
if (_pszHeaders)
{
LocalFree(_pszHeaders);
_pszHeaders = NULL;
}
if (_hszPostData)
{
GlobalFree(_hszPostData);
_hszPostData = NULL;
}
// NOTES: Guard against last Release by _RevokeObjectParam
Release();
return S_OK;
}
void CDocObjectHost::CBindStatusCallback::AbortBinding(void)
{
if (_pib)
{
DebugMsg(0, TEXT("sdv TR AbortBinding Calling _pib->Abort"));
//
// Notes: OnStopBinding(E_ABORT) will be called from _pib->Abort
//
HRESULT hresT = _pib->Abort();
DebugMsg(TF_SHDBINDING, TEXT("sdv TR AbortBinding Called _pib->Abort (%x)"), hresT);
// URLMon may call our OnStopBinding asynchronously.
#if 0
Assert(_pib==NULL);
Assert(_pbc==NULL);
Assert(_psvPrev==NULL);
#endif
}
}
//========================================================================
// class CShdAdviseSink
//========================================================================
class CShdAdviseSink : public IAdviseSink
{
public:
// *** IUnknown methods ***
virtual STDMETHODIMP QueryInterface(REFIID riid, LPVOID * ppvObj);
virtual STDMETHODIMP_(ULONG) AddRef(void) ;
virtual STDMETHODIMP_(ULONG) Release(void);
// *** IAdviseSink methods ***
virtual void __stdcall OnDataChange(
FORMATETC *pFormatetc,
STGMEDIUM *pStgmed);
virtual void __stdcall OnViewChange(
DWORD dwAspect,
LONG lindex);
virtual void __stdcall OnRename(
IMoniker *pmk);
virtual void __stdcall OnSave( void);
virtual void __stdcall OnClose( void);
CShdAdviseSink(IBrowserService* pwb, IOleObject* pole);
~CShdAdviseSink();
protected:
UINT _cRef;
IOleObject* _pole;
DWORD _dwConnection;
};
//
// BUGBUG: We'd better maintain the list of those CShdAdviseSink
// per-thread so that we don't leak all those oleobjects when
// the thread is terminated before those objects are closed.
//
void CShdAdviseSink_Advise(IBrowserService* pwb, IOleObject* pole)
{
IAdviseSink* padv = new CShdAdviseSink(pwb, pole);
// If pole->Advise succeeds, it will addreff to IAdviseSink.
padv->Release();
}
CShdAdviseSink::CShdAdviseSink(IBrowserService* pwb, IOleObject* pole)
: _cRef(1)
{
Assert(pole);
DebugMsg(DM_ADVISE, "CShdAdviseSink(%x) being constructed", this);
HRESULT hres = pole->Advise(this, &_dwConnection);
if (SUCCEEDED(hres)) {
_pole = pole;
pole->AddRef();
DebugMsg(DM_ADVISE, "CShdAdviseSink(%x) called pole->Advise. new _cRef=%d (%x)", this, _cRef, _dwConnection);
}
}
CShdAdviseSink::~CShdAdviseSink()
{
DebugMsg(DM_ADVISE, "CShdAdviseSink(%x) being destroyed", this);
if (_pole) {
ATOMICRELEASE(_pole);
}
}
ULONG CShdAdviseSink::AddRef()
{
_cRef++;
DebugMsg(TF_SHDREF, TEXT("CShdAdviseSink(%x)::AddRef called, new _cRef=%d"), this, _cRef);
return _cRef;
}
ULONG CShdAdviseSink::Release()
{
_cRef--;
DebugMsg(TF_SHDREF, TEXT("CShdAdviseSink(%x)::Release called, new _cRef=%d"), this, _cRef);
if (_cRef > 0)
return _cRef;
delete this;
return 0;
}
HRESULT CShdAdviseSink::QueryInterface(REFIID riid, LPVOID * ppvObj)
{
if (IsEqualIID(riid, IID_IAdviseSink) ||
IsEqualIID(riid, IID_IUnknown))
{
*ppvObj = (IAdviseSink*)this;
}
else
{
*ppvObj = NULL;
return E_NOINTERFACE;
}
AddRef();
return NOERROR;
}
void CShdAdviseSink::OnDataChange(
FORMATETC *pFormatetc,
STGMEDIUM *pStgmed)
{
}
void CShdAdviseSink::OnViewChange(
DWORD dwAspect,
LONG lindex)
{
}
void CShdAdviseSink::OnRename(
IMoniker *pmk)
{
}
void CShdAdviseSink::OnSave( void)
{
}
void CShdAdviseSink::OnClose( void)
{
DebugMsg(DM_ADVISE, TEXT("CShdAdviseSink(%x)::OnClose called. Calling Unadvise. _cRef=%d"), this, _cRef);
HRESULT hres;
AddRef();
Assert(_pole);
if (_pole) // paranoia
{
hres = _pole->Unadvise(_dwConnection);
ATOMICRELEASE(_pole);
DebugMsg(DM_ADVISE, TEXT("CShdAdviseSink(%x)::OnClose. Called Unadvise(%x). new _cRef=%d"), this, hres, _cRef);
}
Release();
}
/// adding property sheet pages
HRESULT CDocObjectHost::AddPages(LPFNADDPROPSHEETPAGE lpfnAddPage, LPARAM lParam)
{
HRESULT hres = S_OK;
IShellPropSheetExt *pspse;
CHomePropSheetPage hpg; // maximum size structure
hpg.page.dwSize = sizeof(hpg.page);
Assert(hpg.page.dwFlags == PSP_DEFAULT);
hpg.page.hInstance = HINST_THISDLL;
hpg.page.lParam = (LPARAM)(LPVOID)this;
/*
* Create a property sheet page for required page, including imported File
* Types property sheet.
*/
// add stuff that the docobj itself has.
if (_pole && SUCCEEDED(_pole->QueryInterface(IID_IShellPropSheetExt, (LPVOID*)&pspse))) {
hres = pspse->AddPages(lpfnAddPage, lParam);
pspse->Release();
}
return hres;
}
//
// GetSyncMode
//
// Returns the syncmode the cache is set to. On failure, returns the
// passed in default.
DWORD GetSyncMode (DWORD dwDefault)
{
INTERNET_CACHE_CONFIG_INFO CacheConfigInfo;
DWORD dwCCIBufSize = sizeof(CacheConfigInfo);
memset (&CacheConfigInfo, 0, sizeof(CacheConfigInfo));
// if our API succeeds, our new default is the return value
if (GetUrlCacheConfigInfo (&CacheConfigInfo, &dwCCIBufSize,
CACHE_CONFIG_SYNC_MODE_FC))
dwDefault = CacheConfigInfo.dwSyncMode;
return dwDefault;
}
int CmpSystemtime(SYSTEMTIME *pst1, SYSTEMTIME *pst2)
{
int iRet;
if (pst1->wYear < pst2->wYear)
iRet = -1;
else if (pst1->wYear > pst2->wYear)
iRet = 1;
else if (pst1->wMonth < pst2->wMonth)
iRet = -1;
else if (pst1->wMonth > pst2->wMonth)
iRet = 1;
else if (pst1->wDay < pst2->wDay)
iRet = -1;
else if (pst1->wDay > pst2->wDay)
iRet = 1;
else if (pst1->wHour < pst2->wHour)
iRet = -1;
else if (pst1->wHour > pst2->wHour)
iRet = 1;
else if (pst1->wMinute < pst2->wMinute)
iRet = -1;
else if (pst1->wMinute > pst2->wMinute)
iRet = 1;
else if (pst1->wSecond < pst2->wSecond)
iRet = -1;
else if (pst1->wSecond > pst2->wSecond)
iRet = 1;
else
iRet = 0;
return(iRet);
}
BOOL ComparePrefixAndMovePast (LPSTR *ppsz, LPSTR pszFormat) {
BOOL b = FALSE;
CHAR *pszIndex;
CHAR *pszIndex2;
DWORD cbpsz = lstrlen(*ppsz);
LPSTR pszEndOfPrefix;
pszEndOfPrefix = StrChrIA (*ppsz, '.');
if (!pszEndOfPrefix)
return FALSE;
// If the first % occurs to the right of the first ., we will
// assume the format string has no prefix, and exit.
pszIndex = StrChrA(pszFormat, '.');
pszIndex2 = StrChrA(pszFormat, '%');
if ((!pszIndex) || (pszIndex2 && (pszIndex > pszIndex2)))
return b;
if (!StrCmpNIA(pszFormat, *ppsz, (pszIndex - pszFormat))) {
b = TRUE;
if (*(pszEndOfPrefix + 1))
*ppsz = pszEndOfPrefix + 1;
}
return b;
}
HRESULT MungeUrlForSearch(LPWSTR pwzOut, LPWSTR wzURL, LPSTR szFormat)
{
CHAR *pszSuffix;
LPSTR pszEnd;
CHAR szTmpURL[MAX_URL_STRING];
CHAR szTmpResult[MAX_URL_STRING];
URL_COMPONENTS uc;
HRESULT hr = E_FAIL;
DWORD rc = 0;
DWORD cb = 0;
LPBYTE p = NULL;
if ((!pwzOut) || (!wzURL) || (!szFormat))
return E_FAIL;
*pwzOut = '\0';
// Break the URL apart into its components, munge the hostname,
// and reassemble it
ZeroMemory (&uc, sizeof(uc));
uc.dwStructSize = sizeof(uc);
p = (LPBYTE) LocalAlloc(LPTR, INTERNET_MAX_SCHEME_LENGTH + INTERNET_MAX_HOST_NAME_LENGTH + INTERNET_MAX_URL_LENGTH + INTERNET_MAX_URL_LENGTH + 4);
if (!p)
goto free_and_exit;
uc.dwSchemeLength = INTERNET_MAX_SCHEME_LENGTH;
uc.lpszScheme = (LPSTR) p;
uc.dwHostNameLength = INTERNET_MAX_HOST_NAME_LENGTH;
uc.lpszHostName = (LPSTR) uc.lpszScheme + uc.dwSchemeLength;
uc.dwUrlPathLength = INTERNET_MAX_URL_LENGTH;
uc.lpszUrlPath = (LPSTR) uc.lpszHostName + uc.dwHostNameLength;
uc.dwExtraInfoLength = INTERNET_MAX_URL_LENGTH;
uc.lpszExtraInfo = (LPSTR) uc.lpszUrlPath + uc.dwUrlPathLength;
cb = WideCharToMultiByte(CP_ACP, 0, wzURL, -1, szTmpURL, ARRAYSIZE(szTmpURL), NULL, NULL);
ASSERT (cb);
rc = InternetCrackUrlA (szTmpURL, cb, 0, &uc);
if (!rc && cb > 2) {
LPSTR pszHostName;
LPSTR pszCurrent = (LPSTR) &szTmpURL;
// The most likely reason we would fail here is because the url did not
// have a scheme. So we'll try to fake some stuff out; we'll also
// handle the reassembly differently below.
while (*pszCurrent && !IsCharAlphaNumericA(*pszCurrent)) {
pszCurrent = CharNext(pszCurrent);
}
pszHostName = pszCurrent;
// BUGBUG: stripping all leading non-alpha chars??
// should i add them back? 19nov96 tonyci
pszCurrent = (pszHostName + StrCSpnA(pszHostName, "/\\?"));
// If StrCSpnA() fails, it returns the index to end-of-string/NULL
if (pszCurrent && *pszCurrent) {
lstrcpyn (uc.lpszUrlPath, pszCurrent, uc.dwUrlPathLength);
} else {
uc.lpszUrlPath = NULL;
uc.dwUrlPathLength = NULL;
// pszCurrent is a pointer to the NULL at end-of-string
}
ASSERT(pszCurrent);
lstrcpyn (uc.lpszHostName, pszHostName, (pszCurrent - pszHostName) + 1);
// Clear unused elements
uc.lpszScheme = NULL;
uc.dwSchemeLength = 0;
uc.lpszExtraInfo = NULL;
uc.dwExtraInfoLength = 0;
}
// rc is used again below
// Ok, now parse the hostname
pszEnd = uc.lpszHostName + lstrlenA(uc.lpszHostName);
// Strip the suffix if they have one
pszSuffix = StrRChrIA (uc.lpszHostName, pszEnd, '.');
if (pszSuffix && (pszEnd - pszSuffix == 4))
{
*pszSuffix = NULL; // terminate at the last .
} else
pszSuffix = NULL;
// Check for prefixes and skip them
ComparePrefixAndMovePast(&uc.lpszHostName, szFormat);
uc.dwHostNameLength = wsprintf(szTmpURL, szFormat, uc.lpszHostName);
uc.lpszHostName = (LPSTR) &szTmpURL;
if (!rc) {
if (uc.lpszUrlPath)
lstrcat(szTmpURL, uc.lpszUrlPath); // BUGBUG: can overflow
lstrcpyn (szTmpResult, szTmpURL, ARRAYSIZE(szTmpResult));
} else {
cb = ARRAYSIZE(szTmpResult);
rc = InternetCreateUrlA (&uc, 0, (LPSTR) &szTmpResult, &cb);
ASSERT (rc);
if (!rc) {
hr = E_FAIL;
goto free_and_exit;
}
}
if (MultiByteToWideChar(CP_ACP, 0, szTmpResult, -1, pwzOut, MAX_URL_STRING))
hr = S_OK;
free_and_exit:
LocalFree(p);
return hr;
}
const SA_BSTRGUID s_sstrSearchIndex = {
38 * SIZEOF(WCHAR),
L"{265b75c0-4158-11d0-90f6-00c04fd497ea}"
};
//extern const SA_BSTRGUID s_sstrSearchFlags;
const SA_BSTRGUID s_sstrSearchFlags = {
38 * SIZEOF(WCHAR),
L"{265b75c1-4158-11d0-90f6-00c04fd497ea}"
};
HRESULT _GetSearchInfo (IServiceProvider *psp, LPDWORD pdwIndex, LPBOOL pfAllowSearch, LPBOOL pfContinueSearch, LPBOOL pfSentToEngine) {
HRESULT hr = E_FAIL;
DWORD dwFlags = 0;
if (psp) {
IWebBrowser2 *pWB2 = NULL;
hr = psp->QueryService(SID_SHlinkFrame, IID_IWebBrowser2, (LPVOID*)&pWB2);
if (pWB2 && SUCCEEDED(hr)) {
VARIANT v;
VariantInit (&v);
if (pdwIndex) {
v.vt = VT_I4;
if (SUCCEEDED(pWB2->GetProperty((BSTR)s_sstrSearchIndex.wsz, &v))) {
if (v.vt == VT_I4)
*pdwIndex = v.lVal;
}
}
if (pfAllowSearch || pfContinueSearch || pfSentToEngine) {
v.vt = VT_I4;
if (SUCCEEDED(pWB2->GetProperty((BSTR)s_sstrSearchFlags.wsz, &v))) {
if (v.vt == VT_I4)
dwFlags = v.lVal;
}
}
if (pfAllowSearch)
*pfAllowSearch = ((dwFlags & 0x01) ? TRUE : FALSE);
if (pfContinueSearch)
*pfContinueSearch = ((dwFlags & 0x02) ? TRUE : FALSE);
if (pfSentToEngine)
*pfSentToEngine = ((dwFlags & 0x04) ? TRUE : FALSE);
pWB2->Release();
}
}
return hr;
}
HRESULT _SetSearchInfo (IServiceProvider *psp, DWORD dwIndex, BOOL fAllowSearch, BOOL fContinueSearch, BOOL fSentToEngine) {
HRESULT hr = E_FAIL;
DWORD dwFlags = 0;
dwFlags = (fAllowSearch ? 0x01 : 0) +
(fContinueSearch ? 0x02 : 0) +
(fSentToEngine ? 0x04 : 0);
if (psp) {
IWebBrowser2 *pWB2 = NULL;
hr = psp->QueryService(SID_SHlinkFrame, IID_IWebBrowser2, (LPVOID*)&pWB2);
if (pWB2 && SUCCEEDED(hr)) {
VARIANT v;
VariantInit (&v);
v.vt = VT_I4;
v.lVal = dwIndex;
pWB2->PutProperty((BSTR)s_sstrSearchIndex.wsz, v);
v.vt = VT_I4;
v.lVal = dwFlags;
pWB2->PutProperty((BSTR)s_sstrSearchFlags.wsz, v);
pWB2->Release();
}
}
return hr;
}
LONG _GetSearchFormatString(DWORD dwIndex, LPSTR psz, DWORD cbpsz) {
HKEY hk;
LONG lhr;
CHAR szValue[REGSTR_MAX_VALUE_LENGTH];
DWORD cbValue = ARRAYSIZE(szValue);
DWORD dwType;
CHAR szData[MAX_SEARCH_FORMAT_STRING];
DWORD cbData = ARRAYSIZE(szData);
if (!psz || cbpsz == 0)
return 0;
*psz = '\0';
lhr=RegOpenKey(HKEY_CURRENT_USER, REGSTR_PATH_SEARCHSTRINGS, &hk);
if (lhr == ERROR_SUCCESS) {
// Add 1 to skip default value
lhr = RegEnumValueA(hk, dwIndex+1, (LPSTR) &szValue, &cbValue, 0, &dwType, (LPBYTE) &szData, &cbData);
if (lhr == ERROR_SUCCESS) {
if (cbData)
lstrcpynA(psz, (LPSTR) &szData, cbpsz);
}
RegCloseKey(hk);
}
return lhr;
}
//
// S_OK means we successfully did a navigation
// S_FALSE means that we did everything ok, but did not navigate
// E_* means some internal api failed.
//
HRESULT CDocObjectHost::CBindStatusCallback::_HandleFailedNavigationSearch (LPBOOL pfShouldDisplayError, DWORD dwStatusCode, CDocObjectHost *pdoh, HRESULT hrDisplay, TCHAR *szURL, LPCWSTR szError)
{
DWORD dwSearchForExtensions = NO_SUFFIXES;
DWORD dwDo404Search = PROMPTSEARCH;
BOOL bAskUser = TRUE; // rely on init
BOOL bDoSearch = FALSE; // rely on init
HRESULT hres = S_FALSE;
BOOL bFrameIsSilent = FALSE;
BOOL bFrameIsOffline = FALSE;
BOOL bPrepareForSearch = FALSE;
DWORD dwSuffixIndex = 0;
BOOL bAllowSearch = FALSE;
BOOL bContinueSearch = FALSE;
BOOL bSentToEngine = FALSE;
CHAR szSearchFormatStr[MAX_SEARCH_FORMAT_STRING];
if (FAILED(GetSearchKeys(&dwSearchForExtensions, &dwDo404Search))) {
return E_FAIL;
}
// Get any persistent information from the last request
_GetSearchInfo (pdoh->_psp, &dwSuffixIndex, &bAllowSearch, &bContinueSearch, &bSentToEngine);
// Why not use the cached value?
// pdoh->_GetOfflineSilent(&bFrameIsOffline, &bFrameIsSilent);
bFrameIsOffline = _bFrameIsOffline ? TRUE : FALSE;
bFrameIsSilent = _bFrameIsSilent ? TRUE : FALSE;
// if we are at the end of the extension list, turn off extensions
if (dwSearchForExtensions) {
if (_GetSearchFormatString(dwSuffixIndex, (LPSTR) &szSearchFormatStr, ARRAYSIZE(szSearchFormatStr)) != ERROR_SUCCESS) {
dwSearchForExtensions = DONE_SUFFIXES;
lstrcpy ((LPSTR)&szSearchFormatStr, "%s");
}
} else
dwSearchForExtensions = DONE_SUFFIXES;
// don't try a 404 srch if we are still trying suffixes
if (dwSearchForExtensions == SCAN_SUFFIXES)
dwDo404Search = NEVERSEARCH;
// Prepare to do an automatic search if the navigation failed
// and we think a search might be valuable.
bPrepareForSearch = ((bContinueSearch || (bAllowSearch)) &&
SHOULD_DO_SEARCH(dwSearchForExtensions, dwDo404Search) &&
DO_SEARCH_ON_STATUSCODE(dwStatusCode));
if (bPrepareForSearch) {
IShellToolbar* psct;
IOleCommandTarget* poct;
HRESULT hr = E_FAIL;
if (pdoh->_psp)
hr = pdoh->_psp->QueryService(SID_SExplorerToolbar, IID_IShellToolbar, (LPVOID*)&psct);
if (SUCCEEDED(hr) && SUCCEEDED(psct->QueryInterface(IID_IOleCommandTarget, (LPVOID *)&poct))) {
VARIANT varIn;
VARIANT varOut;
VariantInit (&varIn);
VariantInit (&varOut);
// Length of the BSTR buffer we are passing
varIn.vt = VT_I4;
varIn.lVal = MAX_URL_STRING;
// Pointer to buffer we want filled
varOut.vt = VT_BSTR | VT_BYREF;
varOut.byref = SysAllocStringLen(NULL, varIn.lVal);
hr = poct->Exec(&CGID_Explorer, SBCMDID_GETADDRESSBARTEXT, 0, &varIn, &varOut);
// NULL is the first parameter so our ErrorMsgBox
// doesn't call EnableModelessSB()
// If we don't, our pdoh members may be freed
// by the time we return.
if (SUCCEEDED(hr)) {
if (dwSearchForExtensions == SCAN_SUFFIXES) {
bAskUser = FALSE; // don't ask, just scan
bDoSearch = TRUE;
}
if (dwDo404Search == ALWAYSSEARCH) {
bAskUser = FALSE; // don't ask, just search
bDoSearch = TRUE;
}
} else {
bAskUser = FALSE;
}
if (bAskUser) {
DWORD cbDisplayURL = MAX_URL_STRING;
TCHAR szDisplayURL[MAX_URL_STRING];
#ifdef UNICODE
InternetCanonicalizeUrlW (szDisplayURL, szDisplayURL, &cbDisplayURL, ICU_DECODE | ICU_NO_ENCODE | ICU_BROWSER_MODE);
// If ICU() errors out, we don't care, it won't munge the
// string.
#else
if (WideCharToMultiByte(CP_ACP, 0, (LPWSTR) varOut.byref, -1, szDisplayURL, cbDisplayURL, NULL, NULL)) {
InternetCanonicalizeUrlA (szDisplayURL, szDisplayURL, &cbDisplayURL, ICU_DECODE | ICU_NO_ENCODE | ICU_BROWSER_MODE);
// If ICU() errors out, we don't care, it won't munge the
// string.
} else
lstrcpyn (szDisplayURL, szURL, ARRAYSIZE(szDisplayURL));
#endif
// If we ask the user, make sure we don't display another
// error dialog.
*pfShouldDisplayError = FALSE;
hres = S_OK; // everything succeeded so far and we might exit
if (!bFrameIsSilent && IDYES == IE_ErrorMsgBox(NULL, pdoh->_hwnd, hrDisplay, szError, szDisplayURL, IDS_CANTFINDURL, MB_YESNO|MB_ICONSTOP)) {
bDoSearch = TRUE;
} else {
_SetSearchInfo (pdoh->_psp, 0, FALSE, FALSE, FALSE); // reset info
}
}
if (bDoSearch) {
WCHAR wz[MAX_URL_STRING + SEARCHPREFIXLENGTH];
if (dwSearchForExtensions && dwSearchForExtensions != DONE_SUFFIXES) {
MungeUrlForSearch (wz, (LPWSTR) varOut.byref, (LPSTR) &szSearchFormatStr);
} else if (dwDo404Search) {
// add the search prefix
memcpy(wz, SEARCHPREFIX, SEARCHPREFIXSIZE);
memcpy(wz+SEARCHPREFIXLENGTH, varOut.byref, lstrlenW((WCHAR *)varOut.byref)*sizeof(WCHAR));
wz[lstrlenW((WCHAR *)varOut.byref)+SEARCHPREFIXLENGTH] = 0;
} else {
ASSERT(0);
}
if (dwSearchForExtensions && dwSearchForExtensions != DONE_SUFFIXES)
_SetSearchInfo (pdoh->_psp, ++dwSuffixIndex, FALSE, TRUE, FALSE);
else if (dwDo404Search)
_SetSearchInfo (pdoh->_psp, dwSuffixIndex, FALSE, FALSE, TRUE);
else
_SetSearchInfo (pdoh->_psp, 0, FALSE, FALSE, FALSE);
if (!pdoh->_fCanceledByBrowser)
pdoh->_CancelPendingNavigation();
pdoh->_DoAsyncNavigation(wz);
pdoh->_fCanceledByBrowser = TRUE;
*pfShouldDisplayError = FALSE; // Don't display another dialog
hres = S_OK; // we did a navigate
}
VariantClear(&varIn);
VariantClear(&varOut);
poct->Release();
}
if (psct)
psct->Release();
} else if (bSentToEngine && !bFrameIsSilent) {
*pfShouldDisplayError = FALSE;
_SetSearchInfo (pdoh->_psp, 0, FALSE, FALSE, FALSE);
IE_ErrorMsgBox(NULL, pdoh->_hwnd, hrDisplay, szError, szURL, IDS_CANTFINDSEARCH, MB_OK|MB_ICONSTOP);
hres = S_OK;
}
return hres;
} // _HandleFailedNavigationSearch()
// dwSearchForExtensions : 0 do not search
// dwSearchForExtensions : 1 search through list of exts.
// dwSearchForExtensions : 2 move on to autosearch
// 0 = never ask, never search
// 1 = always ask
// 2 = never ask, always search
HRESULT GetSearchKeys (LPDWORD pdwSearchForExtensions, LPDWORD pdwDo404Search)
{
HKEY hkey;
DWORD dwTemp;
Assert (pdwSearchForExtensions);
Assert (pdwDo404Search);
if (RegOpenKey(HKEY_CURRENT_USER, REGSTR_PATH_MAIN, &hkey) == ERROR_SUCCESS) {
DWORD dwType = REG_DWORD;
DWORD cbSize = sizeof(dwTemp);
if (RegQueryValueEx(hkey, REGSTR_VAL_AUTONAVIGATE, 0, &dwType, (LPBYTE)&dwTemp, &cbSize) !=ERROR_SUCCESS) {
dwTemp = SCAN_SUFFIXES; // default is to scan suffixes
}
*pdwSearchForExtensions = dwTemp; // Save SearchForExtensions result
dwType = REG_DWORD;
cbSize = sizeof(dwTemp);
if (RegQueryValueEx(hkey, REGSTR_VAL_AUTOSEARCH, 0, &dwType, (LPBYTE)&dwTemp, &cbSize) !=ERROR_SUCCESS) {
dwTemp = PROMPTSEARCH; // default is to prompt before searching
}
*pdwDo404Search = dwTemp; // Save SearchForExtensions result
RegCloseKey (hkey);
}
return S_OK;
} // GetSearchKeys
//==========================================================================
// IDocHostUIHandler implementation
//==========================================================================
HRESULT CDocObjectHost::ShowContextMenu(DWORD dwID, POINT *ppt, IUnknown *pcmdtReserved, IDispatch *pdispReserved)
{
DebugMsg(DM_DOCHOSTUIHANDLER, TEXT("CDOH::ShowContextMenu called"));
//
// LATER: WebBand in a DesktBar/BrowserBar needs to hook this event
// to popup a customized context menu.
//
return S_FALSE; // Host did not display any UI.
}
HRESULT CDocObjectHost::GetHostInfo(DOCHOSTUIINFO *pInfo)
{
DebugMsg(DM_DOCHOSTUIHANDLER, TEXT("CDOH::GetHostInfo called"));
// Trident does not initialize it. It's defined as [in] parameter.
#if 0
if (pInfo->cbSize < SIZEOF(DOCHOSTUIINFO)) {
return E_INVALIDARG;
}
#endif
pInfo->cbSize = SIZEOF(DOCHOSTUIINFO);
pInfo->dwFlags = DOCHOSTUIFLAG_DISABLE_HELP_MENU; // don't add help menu
pInfo->dwDoubleClick = DOCHOSTUIDBLCLK_DEFAULT; // default
return S_OK;
}
HRESULT CDocObjectHost::ShowUI(
DWORD dwID, IOleInPlaceActiveObject *pActiveObject,
IOleCommandTarget *pCommandTarget, IOleInPlaceFrame *pFrame,
IOleInPlaceUIWindow *pDoc)
{
DebugMsg(DM_DOCHOSTUIHANDLER, TEXT("CDOH::ShowUI called"));
// Host did not display its own UI. Trident will proceed to display its own.
return S_FALSE;
}
HRESULT CDocObjectHost::HideUI(void)
{
DebugMsg(DM_DOCHOSTUIHANDLER, TEXT("CDOH::HideUI called"));
// This one is paired with ShowUI
return S_FALSE;
}
HRESULT CDocObjectHost::UpdateUI(void)
{
DebugMsg(DM_DOCHOSTUIHANDLER, TEXT("CDOH::UpdateUI called"));
// LATER: Isn't this equivalent to OLECMDID_UPDATECOMMANDS?
return S_FALSE;
}
HRESULT CDocObjectHost::EnableModeless(BOOL fEnable)
{
DebugMsg(DM_DOCHOSTUIHANDLER, TEXT("CDOH::EnableModeless called"));
// Called from the Trident when the equivalent member of its
// IOleInPlaceActiveObject is called by the frame. We don't care
// those cases.
return S_OK;
}
HRESULT CDocObjectHost::OnDocWindowActivate(BOOL fActivate)
{
// Called from the Trident when the equivalent member of its
// IOleInPlaceActiveObject is called by the frame. We don't care
// those cases.
return S_OK;
}
HRESULT CDocObjectHost::OnFrameWindowActivate(BOOL fActivate)
{
// Called from the Trident when the equivalent member of its
// IOleInPlaceActiveObject is called by the frame. We don't care
// those cases.
return S_OK;
}
HRESULT CDocObjectHost::ResizeBorder(
LPCRECT prcBorder, IOleInPlaceUIWindow *pUIWindow, BOOL fRameWindow)
{
// Called from the Trident when the equivalent member of its
// IOleInPlaceActiveObject is called by the frame. We don't care
// those cases.
return S_OK;
}
HRESULT CDocObjectHost::TranslateAccelerator(
LPMSG lpMsg, const GUID *pguidCmdGroup, DWORD nCmdID)
{
// Called from the Trident when the equivalent member of its
// IOleInPlaceActiveObject is called by the frame. We don't care
// those cases.
return S_FALSE; // The message was not translated
}
HRESULT CDocObjectHost::GetOptionKeyPath(BSTR *pbstrKey)
{
// Trident will default to its own user options.
*pbstrKey = NULL;
return S_FALSE;
}
HRESULT CDocObjectHost::GetDropTarget(IDropTarget *pDropTarget, IDropTarget **ppDropTarget)
{
DebugMsg(DM_DOCHOSTUIHANDLER, TEXT("CDOH::GetDropTarget called"));
HRESULT hres = S_OK;
if (_dt._pdtDoc) {
ATOMICRELEASE(_dt._pdtDoc);
}
if (pDropTarget) {
if (_dt._pdtFrame == NULL) {
//
// HACK: We strongly assumes that _psb implements IDropTarget
// as well.
//
_psb->QueryInterface(IID_IDropTarget, (LPVOID*)&_dt._pdtFrame);
}
if (_dt._pdtFrame) {
_dt._pdtDoc = pDropTarget;
pDropTarget->AddRef();
*ppDropTarget = &_dt;
AddRef();
DebugMsg(DM_DOCHOSTUIHANDLER, TEXT("CDOH::GetDropTarget returning S_OK"));
Assert(hres == S_OK);
} else {
Assert(0);
hres = E_UNEXPECTED;
}
} else {
hres = E_INVALIDARG;
}
return hres;
}
HRESULT CHostDropTarget::QueryInterface(REFIID riid, LPVOID * ppvObj)
{
if (IsEqualIID(riid, IID_IDropTarget) ||
IsEqualIID(riid, IID_IUnknown))
{
*ppvObj = SAFECAST(this, IDropTarget*);
}
else
{
*ppvObj = NULL;
return E_NOINTERFACE;
}
AddRef();
return NOERROR;
}
ULONG CHostDropTarget::AddRef(void)
{
CDocObjectHost* pdoh = IToClass(CDocObjectHost, _dt, this);
return pdoh->AddRef();
}
ULONG CHostDropTarget::Release(void)
{
CDocObjectHost* pdoh = IToClass(CDocObjectHost, _dt, this);
return pdoh->Release();
}
HRESULT CHostDropTarget::DragEnter(IDataObject *pdtobj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
{
Assert(_pdtDoc);
Assert(_pdtFrame);
DWORD dwEffectFrame = *pdwEffect; // Copy it for frame's droptarget
// Call the document first (the order is NOT significant).
HRESULT hres = _pdtDoc->DragEnter(pdtobj, grfKeyState, pt, pdwEffect);
if (SUCCEEDED(hres)) {
// Let the frame know that we are entering ALWAYS.
_pdtFrame->DragEnter(pdtobj, grfKeyState, pt, &dwEffectFrame);
// If the document refuses it, returns the flags from the frame.
if (*pdwEffect == 0)
*pdwEffect = dwEffectFrame;
}
DebugMsg(DM_DOCHOSTUIHANDLER, TEXT("CHDT::DragEnter returning %x with %x"),
hres, *pdwEffect);
return hres;
}
HRESULT CHostDropTarget::DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
{
Assert(_pdtDoc);
Assert(_pdtFrame);
DWORD dwEffectFrame = *pdwEffect; // Copy it for frame's droptarget
// Call the document first (the order is significant).
HRESULT hres = _pdtDoc->DragOver(grfKeyState, pt, pdwEffect);
// If the document accepts it, let it do.
if (hres==S_OK && *pdwEffect) {
DebugMsg(DM_DOCHOSTUIHANDLER, TEXT("CHDT::DragEnter returning %x with %x (Doc)"),
hres, *pdwEffect);
return S_OK;
}
// Let the frame process it.
*pdwEffect = dwEffectFrame;
hres = _pdtFrame->DragOver(grfKeyState, pt, pdwEffect);
DebugMsg(DM_DOCHOSTUIHANDLER, TEXT("CHDT::DragEnter returning %x with %x (Frame)"),
hres, *pdwEffect);
return hres;
}
HRESULT CHostDropTarget::DragLeave(void)
{
DebugMsg(DM_DOCHOSTUIHANDLER, TEXT("CHDT::DragLeave called"));
Assert(_pdtDoc);
Assert(_pdtFrame);
_pdtDoc->DragLeave();
_pdtFrame->DragLeave();
return S_OK;
}
HRESULT CHostDropTarget::Drop(IDataObject *pdtobj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
{
Assert(_pdtDoc);
Assert(_pdtFrame);
DWORD dwEffectFrame = *pdwEffect; // Copy it for frame's droptarget
// Check if the document wants to accept it or not.
HRESULT hres = _pdtDoc->DragOver(grfKeyState, pt, pdwEffect);
if (hres==S_OK && *pdwEffect) {
// Document accepts it.
hres = _pdtDoc->Drop(pdtobj, grfKeyState, pt, pdwEffect);
_pdtFrame->DragLeave();
DebugMsg(DM_DOCHOSTUIHANDLER, TEXT("CHDT::Drop returning %x with %x (Doc)"),
hres, *pdwEffect);
} else {
// Let the frame process it.
*pdwEffect = dwEffectFrame;
hres = _pdtFrame->Drop(pdtobj, grfKeyState, pt, pdwEffect);
_pdtDoc->DragLeave();
DebugMsg(DM_DOCHOSTUIHANDLER, TEXT("CHDT::Drop returning %x with %x (Frame)"),
hres, *pdwEffect);
}
return hres;
}