9554 lines
297 KiB
Plaintext
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;
|
|
}
|
|
|
|
|