Code/Resource
Windows Develop
Linux-Unix program
Internet-Socket-Network
Web Server
Browser Client
Ftp Server
Ftp Client
Browser Plugins
Proxy Server
Email Server
Email Client
WEB Mail
Firewall-Security
Telnet Server
Telnet Client
ICQ-IM-Chat
Search Engine
Sniffer Package capture
Remote Control
xml-soap-webservice
P2P
WEB(ASP,PHP,...)
TCP/IP Stack
SNMP
Grid Computing
SilverLight
DNS
Cluster Service
Network Security
Communication-Mobile
Game Program
Editor
Multimedia program
Graph program
Compiler program
Compress-Decompress algrithms
Crypt_Decrypt algrithms
Mathimatics-Numerical algorithms
MultiLanguage
Disk/Storage
Java Develop
assembly language
Applications
Other systems
Database system
Embeded-SCM Develop
FlashMX/Flex
source in ebook
Delphi VCL
OS Develop
MiddleWare
MPI
MacOS develop
LabView
ELanguage
Software/Tools
E-Books
Artical/Document
dochost.cpp
Package: shell.rar [view]
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 339k
Category:
Windows Kernel
Development Platform:
Visual C++
- //
- // 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 "iehelpid.h"
- #include "bindcb.h"
- #include "winlist.h"
- #include "droptgt.h"
- #include <mshtml.h> // CLSID_HTMLDocument
- #include <mshtmcid.h>
- #include "resource.h"
- #include <htmlhelp.h>
- #include <prsht.h>
- #include <inetcpl.h>
- #include <optary.h>
- #include "impexp.h"
- #include "impexpwz.h"
- #include "thicket.h"
- #include "uemapp.h"
- #include "iextag.h" // web folders
- #include "browsext.h"
- #include <mluisupp.h>
- // temp, going away once itbar edit stuff moves here
- #define CITIDM_EDITPAGE 10
- // Command group for private communication with CITBar
- // 67077B95-4F9D-11D0-B884-00AA00B60104
- const GUID CGID_PrivCITCommands = { 0x67077B95L, 0x4F9D, 0x11D0, 0xB8, 0x84,
- 0x00, 0xAA, 0x00, 0xB6, 0x01, 0x04 };
- // end temp itbar stuff
- #define DBG_ACCELENTRIES 2
- #define OPT_ACCELENTRIES 1
- #ifdef UNIX
- #include <unixstuff.h>
- #define EXPLORER_EXE "explorer"
- #define IEXPLORE_EXE "iexplorer"
- #define DBG_ACCELENTRIES_WITH_FILEMENU 8
- #define OPT_ACCELENTRIES_WITH_FILEMENU 7
- #else
- #define EXPLORER_EXE "explorer.exe"
- #define IEXPLORE_EXE "iexplore.exe"
- #define DBG_ACCELENTRIES_WITH_FILEMENU 6
- #define OPT_ACCELENTRIES_WITH_FILEMENU 5
- #endif /* UNIX */
- EXTERN_C const GUID IID_IDocHostObject = {0x67431840L, 0xC511, 0x11CF, 0x89, 0xA9, 0x00, 0xA0, 0xC9, 0x05, 0x41, 0x29};
- EXTERN_C const GUID IID_IMimeInfo = {0xF77459A0L, 0xBF9A, 0x11cf, 0xBA, 0x4E, 0x00, 0xC0, 0x4F, 0xD7, 0x08, 0x16};
- EXTERN_C const GUID IID_IsPicsBrowser = {0xF114C2C0L, 0x90BE, 0x11D0, 0x83, 0xB1, 0x00, 0xC0, 0x4F, 0xD7, 0x05, 0xB2};
- #include <shlwapi.h>
- #include <ratings.h>
- #define DM_ZONECROSSING 0
- #define DM_SAVEASHACK 0
- #define DM_MIMEMAPPING 0
- #define DM_SELFASC TF_SHDBINDING
- #define DM_ACCEPTHEADER 0
- #define DM_DEBUGTFRAME 0
- #define DM_DOCHOSTUIHANDLER 0
- #define DM_PREMERGEDMENU 0
- #define DM_FOCUS 0
- #define DM_DOCCP 0
- #define DM_PICS 0
- #define DM_SSL 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, LPCTSTR pszCacheName, LPCTSTR pszDisplay, UINT uiCP);
- LONG _GetSearchFormatString(DWORD dwIndex, LPTSTR psz, DWORD cbpsz);
- DWORD _GetErrorThreshold(DWORD dwError);
- HRESULT GetSearchKeys (LPDWORD pdwSearchForExtensions, LPDWORD pdwDo404Search);
- BOOL IsRegisteredClient(LPCTSTR pszClient);
- // macros
- #define DO_SEARCH_ON_STATUSCODE(x) ((x == 0) || (x == HTTP_STATUS_BAD_GATEWAY) || (x == HTTP_STATUS_GATEWAY_TIMEOUT))
- // Suite Apps Registry keys
- #define NEW_MAIL_DEF_KEY TEXT("Mail")
- #define NEW_NEWS_DEF_KEY TEXT("News")
- #define NEW_CONTACTS_DEF_KEY TEXT("Contacts")
- #define NEW_CALL_DEF_KEY TEXT("Internet Call")
- #define NEW_APPOINTMENT_DEF_KEY TEXT("Appointment")
- #define NEW_MEETING_DEF_KEY TEXT("Meeting")
- #define NEW_TASK_DEF_KEY TEXT("Task")
- #define NEW_TASKREQUEST_DEF_KEY TEXT("Task Request")
- #define NEW_JOURNAL_DEF_KEY TEXT("Journal")
- #define NEW_NOTE_DEF_KEY TEXT("Note")
- #ifdef DEBUG
- DWORD g_dwPerf = 0;
- #endif
- // #include "..shell32fstreex.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_hiconFortezza = NULL;
- HICON g_hiconOffline = NULL;
- HICON g_hiconPrinter = NULL;
- HICON g_hiconScriptErr = NULL;
- HICON g_ahiconState[IDI_STATE_LAST-IDI_STATE_FIRST+1] = { NULL };
- #define MAX_MIXED_STR_LEN 32
- // OpenUIURL is just a wrapper for OpenUI, calling CreateURLMoniker() if the
- // caller only has an URL.
- extern BOOL __cdecl _FormatMessage(LPCSTR szTemplate, LPSTR szBuf, UINT cchBuf, ...);
- #include "asyncrat.h"
- #define MAX_STATUS_SIZE 128
- //
- // Set this flag if we are going to use IHlinkBrowseContext in HLINK.DLL
- // #define HLINK_EXTRA
- //
- #include "dochost.h"
- #define DM_RECYCLE DM_TRACE
- #define DM_BINDAPPHACK TF_SHDAPPHACK
- #define DM_ADVISE TF_SHDLIFE
- #define DM_APPHACK DM_WARNING
- #define NAVMSG3(psz, x, y) TraceMsg(0, "shdv NAV::%s %x %x", psz, x, y)
- #define PAINTMSG(psz,x) TraceMsg(0, "shd TR-PAINT::%s %x", psz, x)
- #define JMPMSG(psz, psz2) TraceMsg(0, "shd TR-CDOV::%s %s", psz, psz2)
- #define JMPMSG2(psz, x) TraceMsg(0, "shd TR-CDOV::%s %x", psz, x)
- #define DOFMSG(psz) TraceMsg(0, "shd TR-DOF::%s", psz)
- #define DOFMSG2(psz, x) TraceMsg(0, "shd TR-DOF::%s %x", psz, x)
- #define URLMSG(psz) TraceMsg(TF_SHDBINDING, "shd TR-DOF::%s", psz)
- #define URLMSG2(psz, x) TraceMsg(TF_SHDBINDING, "shd TR-DOF::%s %x", psz, x)
- #define URLMSG3(psz, x, y) TraceMsg(TF_SHDBINDING, "shd TR-DOF::%s %x %x", psz, x, y)
- #define OIPSMSG(psz) TraceMsg(0, "shd TR-OIPS::%s", psz)
- #define OIPSMSG3(psz, sz, p) TraceMsg(0, "shd TR-OIPS::%s %s,%x", psz, sz,p)
- #define VIEWMSG(psz) TraceMsg(0, "sdv TR CDOV::%s", psz)
- #define VIEWMSG2(psz,xx) TraceMsg(0, "sdv TR CDOV::%s %x", psz,xx)
- #define OPENMSG(psz) TraceMsg(TF_SHDBINDING, "shd OPENING %s", psz)
- #define OPENMSG2(psz, x) TraceMsg(TF_SHDBINDING, "shd OPENING %s %x", psz, x)
- #define HFRMMSG(psz) TraceMsg(0, "shd HFRM::%s", psz)
- #define HFRMMSG2(psz, x, y) TraceMsg(0, "shd HFRM::%s %x %x", psz, x, y)
- #define MNKMSG(psz, psz2) TraceMsg(0, "shd MNK::%s (%s)", psz, psz2)
- #define CHAINMSG(psz, x) TraceMsg(0, "shd CHAIN::%s %x", psz, x)
- #define SHVMSG(psz, x, y) TraceMsg(0, "shd SHV::%s %x %x", psz, x, y)
- #define HOMEMSG(psz, psz2, x) TraceMsg(TF_SHDNAVIGATE, "shd HOME::%s %s %x", psz, psz2, x)
- #define SAVEMSG(psz, x) TraceMsg(0, "shd SAVE::%s %x", psz, x)
- #define PERFMSG(psz, x) TraceMsg(TF_SHDPERF, "PERF::%s %d msec", psz, x)
- static const TCHAR szRegKey_SMIEM[] = TEXT("Software\Microsoft\Internet Explorer\Main");
- static const TCHAR szRegVal_ErrDlgPerErr[] = TEXT("Error Dlg Displayed On Every Error");
- static const TCHAR szRegVal_ErrDlgDetailsOpen[] = TEXT("Error Dlg Details Pane Open");
- ////////////////////////////////////////////////////////////
- // ShabbirS (980917) - BugFix# 34259
- // Repair menuitem in the Help Menu.
- typedef HRESULT (* FIXIEPROC) (BOOL, DWORD);
- void RepairIE()
- {
- HINSTANCE hIESetup;
- FIXIEPROC fpFixIE;
- hIESetup = LoadLibrary(L"IESetup.dll");
- if (hIESetup)
- {
- fpFixIE = (FIXIEPROC) GetProcAddress(hIESetup,"FixIE");
- if (fpFixIE)
- {
- fpFixIE(TRUE,0);
- }
- FreeLibrary(hIESetup);
- }
- }
- BOOL _IsDesktopItem(CDocObjectHost * pdoh)
- {
- BOOL fIsDesktopItem = FALSE;
- IServiceProvider * psb;
- ASSERT(pdoh);
- //Check if we are a desktop component.
- if(SUCCEEDED(pdoh->QueryService(SID_STopLevelBrowser, IID_IServiceProvider, (void **)&psb)))
- {
- LPTARGETFRAME2 ptgf;
- if(SUCCEEDED(psb->QueryService(IID_ITargetFrame2, IID_ITargetFrame2, (void **)&ptgf)))
- {
- DWORD dwOptions;
- if(SUCCEEDED(ptgf->GetFrameOptions(&dwOptions)))
- {
- //Is this a desktop component?
- if(IsFlagSet(dwOptions, FRAMEOPTIONS_DESKTOP))
- fIsDesktopItem = TRUE;
- }
- ptgf->Release();
- }
- psb->Release();
- }
- return fIsDesktopItem;
- }
- BOOL _IsImmediateParentDesktop(CDocObjectHost *pdoh, IServiceProvider *psp)
- {
- BOOL fImmediateParentIsDesktop = FALSE;
- LPTARGETFRAME2 ptgf;
- //First check if this is hosted on desktop.
- if(!_IsDesktopItem(pdoh))
- return FALSE; //This is not a desktop item. So, the immediate parent can't be desktop!
- //We know that this is a desktop item. Check if the immediate parent is desktop
- // or it is hosted too deep on desktop!
- if(psp && SUCCEEDED(psp->QueryService(IID_ITargetFrame2, IID_ITargetFrame2, (void **)&ptgf)))
- {
- LPUNKNOWN pUnkParent;
- //Get it's immediate parent.
- if(SUCCEEDED(ptgf->GetParentFrame(&pUnkParent)))
- {
- if(pUnkParent)
- {
- //Has a parent. So, the immediate parent can't be desktop!
- pUnkParent->Release();
- fImmediateParentIsDesktop = FALSE;
- }
- else
- fImmediateParentIsDesktop = TRUE; //No parent. Must be a desktop comp.
- }
- ptgf->Release();
- }
- return(fImmediateParentIsDesktop);
- }
- //Gets the current display name in wide char
- //
- // If fURL is TRUE, it returns file-URL with file: prefix.
- //
- HRESULT CDocObjectHost::_GetCurrentPageW(LPOLESTR * ppszDisplayName, BOOL fURL)
- {
- 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);
- //
- // special handling just for file: urls.
- //
- if (SUCCEEDED(hres) && _fFileProtocol)
- {
- ASSERT(*ppszDisplayName);
- WCHAR szText[MAX_URL_STRING];
- DWORD cchText = SIZECHARS(szText);
- if (!fURL)
- {
- hres = PathCreateFromUrlW(*ppszDisplayName, szText, &cchText, 0);
- }
- else
- {
- // we need this to be in the normalized form of the URL
- // for internal usage. urlmon keeps them in the funny PATHURL style
- hres = UrlCanonicalizeW(*ppszDisplayName, szText, &cchText, 0);
- }
- if (SUCCEEDED(hres))
- {
- UINT cchDisplayName = lstrlenW(*ppszDisplayName);
- if (cchText > cchDisplayName)
- {
- // need to resize
- CoTaskMemFree(*ppszDisplayName);
- *ppszDisplayName = (WCHAR *)CoTaskMemAlloc((cchText + 1) * SIZEOF(WCHAR));
- if (*ppszDisplayName)
- {
- // go ahead and copy it in
- StrCpyNW(*ppszDisplayName, szText, cchText + 1);
- }
- else
- hres = E_OUTOFMEMORY;
- }
- else
- {
- StrCpyNW(*ppszDisplayName, szText, cchDisplayName + 1);
- }
- }
- else
- OleFree(*ppszDisplayName);
- }
- pbc->Release();
- }
- }
- return hres;
- }
- HRESULT CDocObjectHost::_GetCurrentPage(LPTSTR szBuf, UINT cchMax, BOOL fURL)
- {
- szBuf[0] = 0; // zero out buffer
- WCHAR *pszDisplayName;
- HRESULT hres = _GetCurrentPageW(&pszDisplayName, fURL);
- if (SUCCEEDED(hres))
- {
- StrCpyN(szBuf, pszDisplayName, cchMax);
- OleFree(pszDisplayName);
- }
- return hres;
- }
- void CDocObjectHost_GetCurrentPage(LPARAM that, LPTSTR szBuf, UINT cchMax)
- {
- CDocObjectHost* pdoh = (CDocObjectHost*)that;
- pdoh->_GetCurrentPage(szBuf, cchMax);
- }
- //========================================================================
- // CDocObjectHost members
- //========================================================================
- CDocObjectHost::CDocObjectHost() : _cRef(1), _uState(SVUIA_DEACTIVATE)
- {
- DllAddRef();
- TraceMsg(TF_SHDLIFE, "ctor CDocObjectHost %x", this);
- TraceMsg(DM_DEBUGTFRAME, "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);
- TraceMsg(0, "sdv TR CDOV::constructor HlinkCreateBrowseContext returned %x", hres);
- #endif // HLINK_EXTRA
- _fPicsAccessAllowed = 1; /* assume no ratings checks unless we download */
- _fbPicsWaitFlags = 0;
- ::_RefPicsQueries(); /* we'll free PICS async query list when last dochost is destroyed */
- _pScriptErrList = NULL;
- _fScriptErrDlgOpen = FALSE;
- _strPriorityStatusText = NULL;
- _iString = -1;
- _uiCP = CP_ACP;
- }
- 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);
- ASSERT(_pcmdMergedMenu==NULL);
- if (_pScriptErrList != NULL)
- {
- _pScriptErrList->Release();
- }
- if (_strPriorityStatusText != NULL)
- {
- SysFreeString(_strPriorityStatusText);
- }
- #ifdef HLINK_EXTRA
- ASSERT(_phls == NULL);
- ATOMICRELEASE(_pihlbc);
- #endif // HLINK_EXTRA
- if (_pRatingDetails) {
- ::RatingFreeDetails(_pRatingDetails);
- _pRatingDetails = NULL;
- }
- if (_dwPicsSerialNumber) {
- ::_RemovePicsQuery(_dwPicsSerialNumber);
- _dwPicsSerialNumber = 0;
- }
- if (_hPicsQuery)
- {
- RatingObtainCancel(_hPicsQuery);
- _hPicsQuery = NULL;
- }
- delete _pszPicsURL; /* safe if already NULL */
- _pszPicsURL = NULL;
- ::_ReleasePicsQueries();
- if (_pRootDownload != NULL) {
- ASSERT(0); /* need to destroy this earlier to prevent Trident problems */
- ATOMICRELEASET(_pRootDownload,CPicsRootDownload);
- }
- if (_padvise) {
- _padvise->OnClose();
- ATOMICRELEASE(_padvise);
- }
- if (_pwszRefreshUrl)
- OleFree(_pwszRefreshUrl);
- if (_hmenuBrowser) {
- AssertMsg(0, TEXT("_hmenuBrowser should be NULL!"));
- DestroyMenu(_hmenuBrowser);
- }
- if (_hmenuFrame) {
- DestroyMenu(_hmenuFrame);
- }
- if (_hacc)
- {
- DestroyAcceleratorTable(_hacc);
- _hacc = NULL;
- }
- if (_hinstInetCpl)
- FreeLibrary(_hinstInetCpl);
- if (_ptbStd)
- delete [] _ptbStd;
- if (_pBrowsExt)
- {
- _pBrowsExt->Release();
- }
- // Make it sure that View Window is released (and _psb)
- DestroyHostWindow(); // which will call _CloseMsoView and _UnBind
- _ResetOwners();
- TraceMsg(TF_SHDLIFE, "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, "DocHost: Dumping menus for %#08x %s", (LPVOID)this, pszMsg);
- TraceMsg(TF_ALWAYS, " _hmenuBrowser = %x, _hmenuSet = %x, _hmenuFrame = %x",
- _hmenuBrowser, _hmenuSet, _hmenuFrame);
- TraceMsg(TF_ALWAYS, " _hmenuCur = %x, _hmenuMergedHelp = %x, _hmenuObjHelp = %x",
- _hmenuCur, _hmenuMergedHelp, _hmenuObjHelp);
- _menulist.Dump(pszMsg);
- if (bBreak && IsFlagSet(g_dwBreakFlags, BF_ONDUMPMENU))
- DebugBreak();
- }
- }
- #endif
- HRESULT CDocObjectHost::QueryInterface(REFIID riid, LPVOID * ppvObj)
- {
- static const QITAB qit[] = {
- QITABENT(CDocObjectHost, IOleInPlaceSite),
- QITABENTMULTI(CDocObjectHost, IOleWindow, IOleInPlaceSite),
- QITABENT(CDocObjectHost, IOleClientSite),
- QITABENT(CDocObjectHost, IOleDocumentSite),
- QITABENT(CDocObjectHost, IOleCommandTarget),
- QITABENT(CDocObjectHost, IServiceProvider),
- QITABENT(CDocObjectHost, IViewObject),
- QITABENT(CDocObjectHost, IAdviseSink),
- QITABENT(CDocObjectHost, IDocHostObject),
- QITABENT(CDocObjectHost, IDocHostUIHandler),
- QITABENT(CDocObjectHost, IDocHostShowUI),
- QITABENT(CDocObjectHost, IDispatch),
- QITABENT(CDocObjectHost, IPropertyNotifySink),
- QITABENT(CDocObjectHost, IOleControlSite),
- { 0 },
- };
- return QISearch(this, qit, riid, ppvObj);
- }
- void CDocObjectHost::_ResetOwners()
- {
- _pszLocation = NULL;
- _uiCP = CP_ACP;
- _ReleasePendingObject();
- ATOMICRELEASE(_psv);
- ATOMICRELEASE(_pmsoctView);
- ATOMICRELEASE(_pdvs);
- ATOMICRELEASE(_psb);
- ATOMICRELEASE(_pwb);
- ATOMICRELEASE(_phf);
- ATOMICRELEASE(_pocthf);
- ATOMICRELEASE(_punkSFHistory);
- ATOMICRELEASE(_pmsoctBrowser);
- ATOMICRELEASE(_psp);
- ATOMICRELEASE(_peds);
- ATOMICRELEASE(_pedsHelper);
- ATOMICRELEASE(_pWebOCUIHandler);
- ATOMICRELEASE(_pWebOCShowUI);
- // Release cached OleInPlaceUIWindow of the browser
- ATOMICRELEASE(_pipu);
- // Tell embedded CDocHostUIHandler object to release its references on us.
- _dhUIHandler.SetSite(NULL);
- }
- ULONG CDocObjectHost::AddRef()
- {
- _cRef++;
- TraceMsg(TF_SHDREF, "CDocObjectHost(%x)::AddRef called, new _cRef=%d", this, _cRef);
- return _cRef;
- }
- ULONG CDocObjectHost::Release()
- {
- _cRef--;
- TraceMsg(TF_SHDREF, "CDocObjectHost(%x)::Release called, new _cRef=%d", this, _cRef);
- if (_cRef > 0)
- return _cRef;
- delete this;
- return 0;
- }
- // cut & paste from browseuiitbar.cpp
- int RemoveHiddenButtons(TBBUTTON* ptbn, int iCount)
- {
- int i;
- int iTotal = 0;
- TBBUTTON* ptbn1 = ptbn;
- for (i = 0; i < iCount; i++, ptbn1++) {
- if (!(ptbn1->fsState & TBSTATE_HIDDEN)) {
- if (ptbn1 != ptbn) {
- *ptbn = *ptbn1;
- }
- ptbn++;
- iTotal++;
- }
- }
- return iTotal;
- }
- // We use two different image lists in the TBBUTTON array. The bitmaps for browser-specific buttons
- // cut/copy/paste have been moved to shdocvw, and are therefore obtained from a second image list.
- // MAKELONG(0,1) accesses the first image from this second list. Without a call to MAKELONG there is
- // a 0 in the upper integer, thereby referencing the first list by default.
- static const TBBUTTON c_tbStd[] = {
- {10, DVIDM_SHOWTOOLS, TBSTATE_ENABLED, BTNS_BUTTON, {0,0}, 0, 10},
- {13, DVIDM_MAILNEWS, TBSTATE_ENABLED, BTNS_WHOLEDROPDOWN, {0,0}, 0, 13 },
- { 8, DVIDM_FONTS, TBSTATE_ENABLED, BTNS_WHOLEDROPDOWN, {0,0}, 0, 8 },
- { 7, DVIDM_PRINT, TBSTATE_ENABLED, BTNS_BUTTON, {0,0}, 0, 7 },
- { 9, DVIDM_EDITPAGE, TBSTATE_ENABLED, BTNS_BUTTON, {0,0}, 0, 9 },
- {15, DVIDM_DISCUSSIONS, TBSTATE_ENABLED, BTNS_BUTTON, {0,0}, 0, 15 },
- {MAKELONG(0,1), DVIDM_CUT, TBSTATE_ENABLED, BTNS_BUTTON, {0,0}, 0, 0 },
- {MAKELONG(1,1), DVIDM_COPY, TBSTATE_ENABLED, BTNS_BUTTON, {0,0}, 0, 0 },
- {MAKELONG(2,1), DVIDM_PASTE, TBSTATE_ENABLED, BTNS_BUTTON, {0,0}, 0, 0 },
- {MAKELONG(3,1), DVIDM_ENCODING, TBSTATE_ENABLED, BTNS_WHOLEDROPDOWN, {0,0}, 0, 0 },
- };
- // c_tbStd and c_rest need to match exactly
- static const BROWSER_RESTRICTIONS c_rest[] = {
- REST_BTN_TOOLS,
- REST_BTN_MAIL,
- REST_BTN_FONTS,
- REST_BTN_PRINT,
- REST_BTN_EDIT,
- REST_BTN_DISCUSSIONS,
- REST_BTN_CUT,
- REST_BTN_COPY,
- REST_BTN_PASTE,
- REST_BTN_ENCODING,
- };
- #ifdef DEBUG
- void _AssertRestrictionOrderIsCorrect()
- {
- COMPILETIME_ASSERT(ARRAYSIZE(c_tbStd) == ARRAYSIZE(c_rest));
- for (UINT i = 0; i < ARRAYSIZE(c_tbStd); i++)
- {
- // If any of these rip, it means that c_rest and c_tbStd have
- // gotten out of sync. Need to fix up c_rest to match c_tbStd.
- switch (c_tbStd[i].idCommand)
- {
- case DVIDM_SHOWTOOLS: ASSERT(c_rest[i] == REST_BTN_TOOLS); break;
- case DVIDM_MAILNEWS: ASSERT(c_rest[i] == REST_BTN_MAIL); break;
- case DVIDM_FONTS: ASSERT(c_rest[i] == REST_BTN_FONTS); break;
- case DVIDM_PRINT: ASSERT(c_rest[i] == REST_BTN_PRINT); break;
- case DVIDM_EDITPAGE: ASSERT(c_rest[i] == REST_BTN_EDIT); break;
- case DVIDM_DISCUSSIONS: ASSERT(c_rest[i] == REST_BTN_DISCUSSIONS); break;
- case DVIDM_CUT: ASSERT(c_rest[i] == REST_BTN_CUT); break;
- case DVIDM_COPY: ASSERT(c_rest[i] == REST_BTN_COPY); break;
- case DVIDM_PASTE: ASSERT(c_rest[i] == REST_BTN_PASTE); break;
- case DVIDM_ENCODING: ASSERT(c_rest[i] == REST_BTN_ENCODING); break;
- default: ASSERT(0); break;
- }
- }
- }
- #endif
- BYTE _BtnStateFromRestIfAvailable(BOOL fAvailable, DWORD dwRest)
- {
- if (fAvailable)
- return SHBtnStateFromRestriction(dwRest, TBSTATE_ENABLED);
- return TBSTATE_HIDDEN;
- }
- BOOL CDocObjectHost::_ToolsButtonAvailable()
- {
- OLECMD rgcmd = { OLECMDID_HIDETOOLBARS, 0 };
- if (_pmsoctBrowser)
- _pmsoctBrowser->QueryStatus(NULL, 1, &rgcmd, NULL);
- return (rgcmd.cmdf & OLECMDF_SUPPORTED);
- }
- __inline BYTE CDocObjectHost::_DefToolsButtonState(DWORD dwRest)
- {
- BOOL fAvailable = _ToolsButtonAvailable();
- return _BtnStateFromRestIfAvailable(fAvailable, dwRest);
- }
- static const TCHAR c_szRegKeyCoolbar[] = TEXT("Software\Microsoft\Internet Explorer\Toolbar");
- BYTE CDocObjectHost::_DefFontsButtonState(DWORD dwRest)
- {
- BYTE fsState = TBSTATE_ENABLED;
- // default to whatever the IE4 reg key specifies,
- // or FALSE if reg key not present (clean install)
- if (!SHRegGetBoolUSValue(c_szRegKeyCoolbar, TEXT("ShowFonts"), FALSE, FALSE))
- fsState |= TBSTATE_HIDDEN;
- return SHBtnStateFromRestriction(dwRest, fsState);
- }
- DWORD CDocObjectHost::_DiscussionsButtonCmdf()
- {
- if (SHRegGetBoolUSValue(c_szRegKeyCoolbar,
- TEXT("ShowDiscussionButton"), FALSE, TRUE) &&
- _pmsoctBrowser) {
- OLECMD rgcmds[] = {
- { SBCMDID_DISCUSSIONBAND, 0 },
- };
- static const int buttonsInternal[] = {
- DVIDM_DISCUSSIONS,
- };
- _pmsoctBrowser->QueryStatus(&CGID_Explorer, ARRAYSIZE(rgcmds), rgcmds, NULL);
- return rgcmds[0].cmdf;
- }
- return 0;
- }
- __inline BOOL CDocObjectHost::_DiscussionsButtonAvailable()
- {
- return (_DiscussionsButtonCmdf() & OLECMDF_SUPPORTED);
- }
- __inline BYTE CDocObjectHost::_DefDiscussionsButtonState(DWORD dwRest)
- {
- BOOL fAvailable = _DiscussionsButtonAvailable();
- return _BtnStateFromRestIfAvailable(fAvailable, dwRest);
- }
- BOOL CDocObjectHost::_MailButtonAvailable()
- {
- OLECMD rgcmdMailFavs[] = { { SBCMDID_DOMAILMENU, 0} };
- if (_pmsoctBrowser)
- _pmsoctBrowser->QueryStatus(&CGID_Explorer, ARRAYSIZE(rgcmdMailFavs), rgcmdMailFavs, NULL);
- if (rgcmdMailFavs[0].cmdf & OLECMDF_ENABLED)
- return TRUE;
- return FALSE;
- }
- __inline BYTE CDocObjectHost::_DefMailButtonState(DWORD dwRest)
- {
- BOOL fAvailable = _MailButtonAvailable();
- return _BtnStateFromRestIfAvailable(fAvailable, dwRest);
- }
- // We default the edit button to visible if there is an html editer registered
- BOOL CDocObjectHost::_EditButtonAvailable()
- {
- BOOL fRet = FALSE;
- HKEY hkey = NULL;
- if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CLASSES_ROOT, TEXT(".htm\shell\edit\command"), 0, KEY_READ, &hkey) ||
- ERROR_SUCCESS == RegOpenKeyEx(HKEY_CLASSES_ROOT, TEXT("htmlfile\shell\edit\command"), 0, KEY_READ, &hkey))
- {
- RegCloseKey(hkey);
- fRet = TRUE;
- }
- return fRet;
- }
- __inline BYTE CDocObjectHost::_DefEditButtonState(DWORD dwRest)
- {
- BYTE fsState;
- if (_EditButtonAvailable())
- fsState = TBSTATE_ENABLED;
- else
- fsState = TBSTATE_HIDDEN;
- return SHBtnStateFromRestriction(dwRest, fsState);
- }
- void CDocObjectHost::_MarkDefaultButtons(PTBBUTTON tbStd)
- {
- // We're assuming tbStd is the same size as c_tbStd
- #ifdef DEBUG
- _AssertRestrictionOrderIsCorrect();
- #endif
- DWORD dwRest[ARRAYSIZE(c_tbStd)];
- BOOL fCheckRestriction = SHRestricted2(REST_SPECIFYDEFAULTBUTTONS, NULL, 0);
- for (UINT i = 0; i < ARRAYSIZE(c_rest); i++) {
- if (fCheckRestriction)
- dwRest[i] = SHRestricted2(c_rest[i], NULL, 0);
- else
- dwRest[i] = RESTOPT_BTN_STATE_DEFAULT;
- }
- // We want the Cut, Copy, Paste buttons to default off of the toolbar
- // (but available in the view-toolbars-customize dialog)
- // We set the state of the buttons to TBSTATE_HIDDEN here, but leave them alone
- // in ETCMDID_GETBUTTONS so that they appear in the customize dialog.
- ASSERT(tbStd[6].idCommand == DVIDM_CUT);
- ASSERT(tbStd[7].idCommand == DVIDM_COPY);
- ASSERT(tbStd[8].idCommand == DVIDM_PASTE);
- ASSERT(tbStd[9].idCommand == DVIDM_ENCODING);
- for (i = 6; i <= 9; i++)
- tbStd[i].fsState = SHBtnStateFromRestriction(dwRest[i], tbStd[i].fsState | TBSTATE_HIDDEN);
- ASSERT(tbStd[0].idCommand == DVIDM_SHOWTOOLS);
- tbStd[0].fsState = _DefToolsButtonState(dwRest[0]);
- ASSERT(tbStd[1].idCommand == DVIDM_MAILNEWS);
- tbStd[1].fsState = _DefMailButtonState(dwRest[1]);
- ASSERT(tbStd[2].idCommand == DVIDM_FONTS);
- tbStd[2].fsState = _DefFontsButtonState(dwRest[2]);
- ASSERT(tbStd[3].idCommand == DVIDM_PRINT);
- tbStd[3].fsState = SHBtnStateFromRestriction(dwRest[3], TBSTATE_ENABLED);
- ASSERT(tbStd[4].idCommand == DVIDM_EDITPAGE);
- tbStd[4].fsState = _DefEditButtonState(dwRest[4]);
- ASSERT(tbStd[5].idCommand == DVIDM_DISCUSSIONS);
- tbStd[5].fsState = _DefDiscussionsButtonState(dwRest[5]);
- }
- const GUID* CDocObjectHost::_GetButtonCommandGroup()
- {
- if (_ToolsButtonAvailable())
- return &CLSID_MSOButtons;
- else
- return &CLSID_InternetButtons;
- }
- void CDocObjectHost::_AddButtons(BOOL fForceReload)
- {
- if (!_pBrowsExt)
- return;
- IExplorerToolbar* pxtb;
- if (_psp && SUCCEEDED(_psp->QueryService(SID_SExplorerToolbar, IID_IExplorerToolbar, (LPVOID*)&pxtb)))
- {
- const GUID* pguid = _GetButtonCommandGroup();
- HRESULT hr = pxtb->SetCommandTarget((IOleCommandTarget*)this, pguid,
- VBF_TOOLS | VBF_ADDRESS | VBF_LINKS | VBF_BRAND);
- if (!fForceReload && hr == S_FALSE) {
- // Another dochost already merged the buttons into the toolbar under the
- // same command group, so don't bother re-merging. We just need to initialize
- // _iString, since we're skipping the call to _pBrowsExt->InitButtons below.
- VARIANT var = { VT_I4 };
- IUnknown_Exec(_pBrowsExt, &CLSID_PrivBrowsExtCommands, PBEC_GETSTRINGINDEX, 0, &var, NULL); // should always succeed
- _iString = var.lVal;
- } else {
- UINT nNumExtButtons = 0;
- _pBrowsExt->GetNumButtons(&nNumExtButtons);
- int nNumButtons = nNumExtButtons + ARRAYSIZE(c_tbStd);
- // GetTBArray insures that tbStd != NULL, so we don't need that check here
- TBBUTTON *tbStd = new TBBUTTON[nNumButtons];
- if (tbStd != NULL)
- {
- memcpy(tbStd, c_tbStd, SIZEOF(TBBUTTON) * ARRAYSIZE(c_tbStd));
- UINT iStringIndex = (UINT)-1; // result of adding the string buffer to the toolbar string list
- HRESULT hr = _pBrowsExt->InitButtons(pxtb, &iStringIndex, pguid);
- ASSERT(tbStd[6].idCommand == DVIDM_CUT);
- ASSERT(tbStd[7].idCommand == DVIDM_COPY);
- ASSERT(tbStd[8].idCommand == DVIDM_PASTE);
- ASSERT(tbStd[9].idCommand == DVIDM_ENCODING);
- if (SUCCEEDED(hr) && iStringIndex != -1)
- {
- tbStd[6].iString = iStringIndex;
- tbStd[7].iString = iStringIndex + 1;
- tbStd[8].iString = iStringIndex + 2;
- tbStd[9].iString = iStringIndex + 3;
- _iString = (int)iStringIndex;
- }
- else
- {
- tbStd[6].iString = tbStd[7].iString = tbStd[8].iString = tbStd[9].iString = -1;
- _iString = -1;
- }
- // Add custom buttons to the toolbar array. We pass in the nNumButtons
- // as a *sanity check*...
- _pBrowsExt->GetButtons(&tbStd[ARRAYSIZE(c_tbStd)], nNumExtButtons, TRUE);
- _MarkDefaultButtons(tbStd);
- nNumButtons = RemoveHiddenButtons(tbStd, nNumButtons);
- pxtb->AddButtons(pguid, nNumButtons, tbStd);
- delete [] tbStd;
- }
- }
- pxtb->Release();
- }
- }
- HRESULT CDocObjectHost::UIActivate(UINT uState, BOOL fPrevViewIsDocView)
- {
- TraceMsg(TF_SHDUIACTIVATE, "DOH::UIActivate called %d->%d (this=%x)",
- _uState, uState, this);
- HRESULT hres = S_OK;
- UINT uStatePrev = _uState;
- // We are supposed to update the menu
- if (uState != _uState)
- {
- // There was a state transition.
- //
- _uState = uState;
- // If the new state is SVUIA_DEACTIVATE
- //
- 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)
- {
- // Transition from SVUIA_ACTIVATE_FOCUS->SVUIA_INPLACEACTIVATE
- //
- // 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
- TraceMsg(TF_SHDAPPHACK, "DOH::UIActivate APPHACK calling %x->OnDocWindowActivate (this=%x)",
- piact, this);
- if (piact)
- {
- piact->OnDocWindowActivate(FALSE);
- }
- }
- else if (!(_dwAppHack & BROWSERFLAG_DONTDEACTIVATEMSOVIEW))
- {
- // HACK: In Excel, if we deactiveate the view, it never gets focus again
- // fix for the bug from hell: #20906
- _UIDeactivateMsoView();
- }
- else
- {
- // We're transitioning from SVUIA_ACTIVATE_FOCUS->SVUIA_INPLACEACTIVATE
- // and BROWSERFLAG_DONTDEACTIVATEMSOVIEW is set.
- // call the object's IOleInPlactActiveObject::OnFrameWindowActivate(FALSE);
- IOleInPlaceActiveObject* piact = _xao.GetObject(); // no AddRef
- if (piact)
- {
- piact->OnFrameWindowActivate(FALSE);
- }
- }
- }
- 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();
- _AddButtons(FALSE);
- } else {
- // opening a new document for 1st time (to UIActive or IPActive)
- goto GoSetFocus;
- }
- }
- else
- {
- TraceMsg(TF_SHDUIACTIVATE, "DOH:::UIActivate -- same uState (%x)", _uState);
- GoSetFocus:
- if ((_uState == SVUIA_ACTIVATE_FOCUS)) {
- // see if object is already UIActive.
- if (_ActiveHwnd()) {
- // if it is, we have an hwnd and all we need to do
- // is SetFocus (for compatibility w/ weird guys...)
- if ( IsChildOrSelf( _ActiveHwnd(), GetFocus() ) != S_OK )
- {
- TraceMsg(TF_SHDUIACTIVATE, "DOH:::UIActivate -- calling SetFocus(%x)", _ActiveHwnd());
- SetFocus(_ActiveHwnd());
- }
- }
- else {
- // we're in the OC, and it's IPActive not UIActive.
- // (either that or it's the very 1st time for the main view).
- // NOTE: Due to CBaseBrowser code that defers SVUIA_ACTIVATE_FOCUS until
- // application is active, we can have a top level docobject go
- // SVUIA_INPLACEACTIVE and then on activation of the window,
- // we transition to SVUIA_ACTIVATE_FOCUS, thus never UIActivating
- // the docobject (cf: BUG 62138)
- hres = _DoVerbHelper(FALSE);
- }
- }
- }
- if ((_uState == SVUIA_INPLACEACTIVATE) || (_uState == SVUIA_ACTIVATE_FOCUS))
- _PlaceProgressBar();
- return hres;
- }
- //*** _DoVerbHelper -- DoVerb w/ various hacks
- // NOTES
- // BUGBUG do comments in _OnSetFocus apply here?
- HRESULT CDocObjectHost::_DoVerbHelper(BOOL fOC)
- {
- HRESULT hres = E_FAIL;
- LONG iVerb = OLEIVERB_SHOW;
- MSG msg;
- LPMSG pmsg = NULL;
- if (_uState == SVUIA_INPLACEACTIVATE) {
- iVerb = OLEIVERB_INPLACEACTIVATE;
- }
- else if ((_uState == SVUIA_ACTIVATE_FOCUS)) {
- iVerb = OLEIVERB_UIACTIVATE;
- }
- else {
- TraceMsg(TF_ERROR, "DOC::_DoVerbHelper untested (and probably the wrong iVerb mapping)");
- }
- 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)) {
- TraceMsg(DM_ERROR, "DOC::_DoVerbHelper _pole->DoVerb ##FAILED## %x", hres);
- }
- 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) {
- TraceMsg(TF_SHDLIFE, "ctor CDocObjAssoc(%x) being constructed", this);
- }
- DWORD GetDOCHF(void) { return _dwDOCHF; }
- protected:
- ~CDocObjAssoc() {
- TraceMsg(TF_SHDLIFE, "dtor 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
- {
- *ppvObj = NULL;
- return E_NOINTERFACE;
- }
- AddRef();
- return NOERROR;
- }
- ULONG CDocObjAssoc::AddRef()
- {
- _cRef++;
- TraceMsg(TF_SHDREF, "CDocObjAssoc(%x)::AddRef called, new _cRef=%d", this, _cRef);
- return _cRef;
- }
- ULONG CDocObjAssoc::Release()
- {
- _cRef--;
- TraceMsg(TF_SHDREF, "CDocObjAssoc(%x)::Release called, new _cRef=%d", this, _cRef);
- if (_cRef > 0)
- return _cRef;
- delete this;
- return 0;
- }
- void CDocObjectHost::_IPDeactivateMsoView(IOleDocumentView* pmsov)
- {
- TraceMsg(TF_SHDUIACTIVATE, "DOH::_IPDeactivateMsoView called (this==%x)", this);
- if (pmsov)
- {
- IOleInPlaceObject* pipo = NULL;
- HRESULT hresT = _pole->QueryInterface(IID_IOleInPlaceObject, (LPVOID*)&pipo);
- if (SUCCEEDED(hresT))
- {
- pipo->InPlaceDeactivate();
- pipo->Release();
- }
- pmsov->Show(FALSE);
- }
- }
- void CDocObjectHost::_UIDeactivateMsoView(void)
- {
- TraceMsg(TF_SHDUIACTIVATE, "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) && psite) {
- if (psite!=this) {
- _pmsov->SetInPlaceSite(this);
- } else {
- TraceMsg(TF_SHDAPPHACK, "DOH::_ShowMsoView not calling SetInPlaceSite because it's already set");
- }
- psite->Release();
- } else {
- _pmsov->SetInPlaceSite(this);
- }
- GetClientRect(_hwnd, &_rcView);
- ASSERT(_uState != SVUIA_DEACTIVATE);
- if (_uState != SVUIA_INPLACEACTIVATE // Do this if we're not already SVUIA_INPLACEACTIVE
- || !(_dwAppHack & BROWSERFLAG_MSHTML) // or if it's not Trident (office apps expect this call)
- )
- {
- // Trident is sending progress changed messages here -- and causing Compuserve a problem.
- // Flag the fact that we're UIActivating them, and suppress forwarding ProgressChanged
- // messages to our container when this flag is true. (IE v4.1 bug 54787)
- //
- _fUIActivatingView = TRUE;
- _pmsov->UIActivate(TRUE);
- _fUIActivatingView = FALSE;
- }
- //
- // 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)) {
- TraceMsg(DM_ERROR, "DOC::_ShowMsoView _pmsov->SetRect ##FAILED## %x", hres);
- }
- if (FAILED(hres) && _uState == SVUIA_INPLACEACTIVATE) {
- TraceMsg(TF_SHDAPPHACK, "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;
- TraceMsg(TF_SHDAPPHACK, "HACK: CDOH::_ShowMsoView calling UIActive(TRUE) to work around Word bug");
- _pmsov->UIActivate(TRUE);
- _pmsov->SetRect(&_rcView);
- }
- // This is the other case where Trident sends Progress changed messages.
- //
- _fUIActivatingView = TRUE;
- hres = _pmsov->Show(TRUE);
- _fUIActivatingView = FALSE;
- if (FAILED(hres)) {
- TraceMsg(DM_ERROR, "DOH::_ShowMsoView _pmsov->Show ##FAILED## %x", hres);
- }
- _fDrawBackground = FALSE; /* now that we've shown the object, no need to paint our own background */
- }
- HRESULT CDocObjectHost::_ActivateMsoView()
- {
- _EnableModeless(FALSE);
- #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 && !_fIsHistoricalObject) {
- //
- // Special test case for IHlinkFrame marshaling.
- //
- hres = _phls->Navigate(0, _pszLocation);
- //
- // If this is one of our internal error pages, we can ignore the
- // failure on the bogus location. In this case pwszLocation will
- // be the original url that failed preceeded with a '#'.
- //
- LPOLESTR pwszUrl;
- if (FAILED(hres) && SUCCEEDED(_GetCurrentPageW(&pwszUrl, TRUE)))
- {
- // if it begins with res: it may be our erro page
- if (pwszUrl[0] == L'r' && pwszUrl[1] == L'e' && IsErrorUrl(pwszUrl))
- {
- // It's our internal error page, so ignore the error
- hres = S_OK;
- }
- OleFree(pwszUrl);
- }
- if (FAILED(hres)) {
- TraceMsg(DM_ERROR, "DOC::_ActivateMsoView _phls->Navigate(%s) ##FAILED## %x",
- _pszLocation ? _pszLocation : TEXT(""), hres);
- }
- } else {
- // BUGBUG todo: use _DoVerbHelper? (but careful! ACT_FOCUS different)
- 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)) {
- TraceMsg(DM_ERROR, "DOC::_ActivateMsoView _pole->DoVerb ##FAILED## %x", hres);
- }
- }
- // the doc is activated
- if (SUCCEEDED(hres)) {
- _ReleasePendingObject();
- if (_fHaveParentSite) {
- _HideOfficeToolbars();
- }
- }
- _EnableModeless(TRUE);
- 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)
- {
- 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()"));
- }
- ATOMICRELEASE(_pmsoc);
- }
- void CDocObjectHost::_OnPaint(HDC hdc)
- {
- if (_pmsov && !_ActiveObject())
- {
- HRESULT hres;
- RECT rcClient;
- GetClientRect(_hwnd, &rcClient);
- hres = OleDraw(_pmsov, DVASPECT_CONTENT, hdc, &rcClient);
- TraceMsg(0, "shd TR ::_OnPaint OleDraw returns %x", hres);
- }
- }
- HRESULT _GetDefaultLocation(LPWSTR pszPath, DWORD cchPathSizeIn, UINT id)
- {
- WCHAR szPath[MAX_URL_STRING];
- DWORD cbSize = SIZEOF(szPath);
- DWORD cchPathSize = cchPathSizeIn;
- HRESULT hres = E_FAIL;
- HKEY hkey;
- // BUGBUG: Share this code!!!
- // BUGBUG: This is Internet Explorer Specific
- HKEY hkeyroot = id == IDP_CHANNELGUIDE ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE;
- if (RegOpenKeyW(hkeyroot,
- L"Software\Microsoft\Internet Explorer\Main",
- &hkey)==ERROR_SUCCESS)
- {
- DWORD dwType;
- LPCWSTR pszName;
- switch(id) {
- default:
- ASSERT(0);
- case DVIDM_GOHOME:
- pszName = L"Default_Page_URL";
- break;
- case DVIDM_GOSEARCH:
- pszName = L"Default_Search_URL";
- break;
- case IDP_UPDATE:
- pszName = L"Default_Update_URL";
- break;
- case IDP_CHANNELGUIDE:
- pszName = L"ChannelsURL";
- break;
- }
- if (RegQueryValueExW(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.
- hres = S_OK;
- if(!ParseURLFromOutsideSourceW(szPath, pszPath, &cchPathSize, NULL))
- StrCpyNW(pszPath, szPath, cchPathSizeIn);
- if(IsFileUrlW(pszPath))
- {
- cchPathSize = cchPathSizeIn;
- hres = PathCreateFromUrlW(pszPath, pszPath, &cchPathSize, 0);
- }
- }
- RegCloseKey(hkey);
- }
- HOMEMSG("_GetStdLocation returning",
- (SUCCEEDED(hres) ? pszPath : TEXT("Error")), hres);
- return hres;
- }
- HRESULT _GetStdLocation(LPTSTR pszPath, DWORD cchPathSize, UINT id)
- {
- TCHAR szPathTemp[MAX_URL_STRING];
- DWORD cchTempSize = ARRAYSIZE(szPathTemp);
- HRESULT hres = E_FAIL;
- LPCWSTR pszName = NULL;
- ASSERT(cchPathSize >= cchTempSize); // If we hit this, we will truncate the URL in some cases.
- ASSERT(pszPath && (cchPathSize > 0)); // Not Optional
- pszPath[0] = TEXT('');
- // BUGBUG: Share this code!!!
- // BUGBUG: This is Internet Explorer Specific
- switch(id) {
- default:
- ASSERT(0);
- case DVIDM_GOHOME:
- pszName = L"Start Page";
- break;
- case DVIDM_GOFIRSTHOME:
- case DVIDM_GOFIRSTHOMERO:
- pszName = L"First Home Page";
- break;
- case DVIDM_GOSEARCH:
- pszName = L"Search Page";
- break;
- case DVIDM_SEARCHBAR:
- pszName = L"Search Bar";
- break;
- case DVIDM_GOLOCALPAGE:
- pszName = L"Local Page";
- break;
- }
- hres = URLSubRegQuery(szRegKey_SMIEM, pszName, TRUE,
- szPathTemp, cchTempSize, URLSUB_ALL);
- if (FAILED(hres) &&
- ((DVIDM_GOFIRSTHOME == id) || (DVIDM_GOFIRSTHOMERO == id)))
- {
- // The First Home key doesn't exist so use the home key.
- pszName = TEXT("Start Page");
- hres = URLSubRegQuery(szRegKey_SMIEM, pszName, TRUE,
- szPathTemp, cchTempSize, URLSUB_ALL);
- id = DVIDM_GOHOME;
- }
- if (SUCCEEDED(hres))
- {
- // When reading a URL from registry, treat it like it was typed
- // in on the address bar.
- if(ParseURLFromOutsideSourceW(szPathTemp, pszPath, &cchPathSize, NULL))
- {
- if(IsFileUrlW(pszPath))
- hres = PathCreateFromUrlW(pszPath, pszPath, &cchPathSize, 0);
- }
- }
- if (DVIDM_GOFIRSTHOME == id) // Delete that FIRSTHOME key
- {
- HUSKEY hUSKey;
- if (ERROR_SUCCESS == SHRegOpenUSKey(szRegKey_SMIEM, KEY_WRITE, NULL, &hUSKey, FALSE))
- {
- SHRegDeleteUSValue(hUSKey, TEXT("First Home Page"), SHREGDEL_DEFAULT);
- SHRegCloseUSKey(hUSKey);
- }
- hres = S_OK;
- }
- HOMEMSG("_GetStdLocation returning",
- (SUCCEEDED(hres) ? pszPath : TEXT("Error")), hres);
- return hres;
- }
- HRESULT WINAPI _GetDefaultLocation(UINT idp, LPWSTR pszPath, UINT cchMax)
- {
- switch (idp)
- {
- case IDP_UPDATE:
- case IDP_CHANNELGUIDE:
- URLSubLoadString(NULL, IDS_DEF_UPDATE+(idp-IDP_UPDATE), pszPath, cchMax, URLSUB_ALL);
- break;
- default:
- _GetDefaultLocation(pszPath, cchMax, (idp == IDP_SEARCH) ? DVIDM_GOSEARCH : DVIDM_GOHOME);
- break;
- }
- return S_OK;
- }
- HRESULT WINAPI SHDGetPageLocation(HWND hwndOwner, UINT idp, LPWSTR 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_CHANNELGUIDE:
- ASSERT(IDP_CHANNELGUIDE-IDP_UPDATE == IDS_DEF_CHANNELGUIDE-IDS_DEF_UPDATE);
- if (FAILED(_GetDefaultLocation(pszPath, cchMax, idp)))
- {
- _GetDefaultLocation(idp, pszPath, cchMax);
- }
- break;
- default:
- ASSERT(idp==IDP_START || idp==IDP_SEARCH);
- hres = _GetStdLocation(pszPath, cchMax,
- (idp == IDP_SEARCH) ? DVIDM_GOSEARCH : DVIDM_GOHOME);
- if (FAILED(hres))
- {
- _GetDefaultLocation(idp, pszPath, cchMax);
- }
- break;
- }
- if (SUCCEEDED(hres))
- {
- hres = IECreateFromPath(pszPath, ppidlOut);
- if (FAILED(hres))
- {
- // IECreateFromPath() above could have failed if the default location
- // was invalid. (Like file://server_no_exist/
- _GetDefaultLocation(idp, pszPath, cchMax);
- hres = IECreateFromPath(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;
- if (FAILED(CLSIDFromString(szCLSID, &clsid))) {
- TraceMsg(DM_WARNING, "CDOH::_RMTC CLSIDFromString(%x) failed", szCLSID);
- continue;
- }
- TraceMsg(DM_MIMEMAPPING, "CDOH::_RMTC RegEnumKey found %s", szCLSID);
- HKEY hkeyCLSID;
- if (RegOpenKey(hkey, szCLSID, &hkeyCLSID) == ERROR_SUCCESS)
- {
- for (int iValue=0; ; iValue++)
- {
- CHAR szFormatName[128];
- DWORD dwType;
- DWORD cchValueName = ARRAYSIZE(szFormatName);
- //
- // Keep the name ansi because it needs to get
- // passed to urlmon's RegisterMediaTypeClass as
- // ansi.
- //
- if (RegEnumValueA(hkeyCLSID, iValue, szFormatName, &cchValueName, NULL,
- &dwType, NULL, NULL)==ERROR_SUCCESS)
- {
- TraceMsg(DM_MIMEMAPPING, "CDOH::_RMTC RegEnumValue found %s", szFormatName);
- LPSTR psz = StrDupA(szFormatName);
- if (psz) {
- DSA_InsertItem(hdsaCls, 0xffff, &clsid);
- if (DSA_InsertItem(g_hdsaStr, 0xffff, &psz)<0) {
- LocalFree(psz);
- break;
- }
- }
- } else {
- break;
- }
- }
- RegCloseKey(hkeyCLSID);
- } else {
- TraceMsg(DM_WARNING, "CDOH::_RMTC RegOpenKey(%s) failed", szCLSID);
- }
- }
- RegCloseKey(hkey);
- } else {
- TraceMsg(0, "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),
- (LPCSTR*)DSA_GetItemPtr(g_hdsaStr, 0),
- (CLSID*)DSA_GetItemPtr(g_hdsaCls, 0), 0);
- TraceMsg(DM_MIMEMAPPING, "CDOH::_StartAsyncBinding RegisterMTC returns %x", hres);
- }
- // Now see if the container has anything that needs to be registered
- //
- 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);
- TraceMsg(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;
- }
- HRESULT _RegisterAcceptHeaders(IBindCtx* pbc, IShellBrowser* psb)
- {
- return RegisterDefaultAcceptHeaders(pbc, psb);
- }
- HRESULT GetAmbientBoolProp(IExpDispSupport* peds, DISPID dispid, BOOL *pb)
- {
- VARIANT var = {0};
- // Assume failure
- *pb = FALSE;
- HRESULT hres = peds->OnInvoke(dispid, IID_NULL, NULL, DISPATCH_PROPERTYGET, (DISPPARAMS *)&g_dispparamsNoArgs, &var, NULL, NULL);
- if (SUCCEEDED(hres))
- {
- // VB returns success with VT_EMPTY, so we can't assert here
- if (var.vt == VT_BOOL)
- {
- *pb = (var.boolVal) ? TRUE : FALSE;
- }
- else
- {
- // Even though VB says VT_EMPTY, we don't know what other containers
- // might shove in here. Make sure we clean up.
- //
- VariantClear(&var);
- }
- }
- else
- {
- hres = E_FAIL;
- }
- return hres;
- }
- HRESULT CDocObjectHost::_GetOfflineSilent(BOOL *pbIsOffline, BOOL *pbIsSilent)
- {
- if (_peds)
- {
- if (pbIsOffline)
- GetAmbientBoolProp(_peds, DISPID_AMBIENT_OFFLINEIFNOTCONNECTED, pbIsOffline);
- if (pbIsSilent)
- GetAmbientBoolProp(_peds, DISPID_AMBIENT_SILENT, pbIsSilent);
- }
- else
- {
- if (pbIsOffline)
- *pbIsOffline = FALSE;
- if (pbIsSilent)
- *pbIsSilent = FALSE;
- }
- return S_OK;
- }
- /*
- Callback function for RatingObtainQuery
- */
- void RatingObtainQueryCallback(DWORD dwUserData, HRESULT hr, LPCSTR pszRating, LPVOID lpvInpageRating)
- {
- TraceMsg(DM_PICS, "RatingObtainQueryCallback given result %x", hr);
- /* 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 (IS_RATINGS_ENABLED() && ::RatingEnabledQuery() == S_OK) {
- TraceMsg(DM_PICS, "CDOH::_StartPicsQuery entered with ratings enabled");
- BOOL fEnforce = TRUE;
- if (_pszPicsURL != NULL) {
- delete _pszPicsURL;
- _pszPicsURL = NULL;
- }
- LPOLESTR pwszRawURL = NULL;
- if (SUCCEEDED(_GetCurrentPageW(&pwszRawURL, TRUE))) {
- /* We have to call CoInternetGetSecurityUrl to convert pluggable
- * protocols into known schemes, so we know whether we need to
- * enforce ratings on them.
- */
- LPOLESTR pwszSecurityURL = NULL;
- if (SUCCEEDED(CoInternetGetSecurityUrl(pwszRawURL, &pwszSecurityURL,
- PSU_SECURITY_URL_ONLY, 0)))
- {
- // List of protocols for which we never enforce ratings.
- if (!StrCmpNIW(pwszSecurityURL, L"file:", 5) ||
- !StrCmpNIW(pwszSecurityURL, L"about:", 6) ||
- !StrCmpNIW(pwszSecurityURL, L"mk:", 3)) {
- fEnforce = FALSE;
- }
- else {
- Str_SetPtr(&_pszPicsURL, pwszSecurityURL);
- }
- OleFree(pwszSecurityURL);
- }
- OleFree(pwszRawURL);
- }
- if (fEnforce) {
- TraceMsg(DM_PICS, "CDOH::_StartPicsQuery (%s) turning on wait flags", _pszPicsURL);
- _fbPicsWaitFlags = PICS_WAIT_FOR_ASYNC
- | PICS_WAIT_FOR_INDOC
- | PICS_WAIT_FOR_END
- | PICS_WAIT_FOR_ROOT
- ;
- _fPicsAccessAllowed = 0;
- HRESULT hr;
- _dwPicsSerialNumber = ::_AddPicsQuery(_hwnd);
- if (_dwPicsSerialNumber == 0)
- hr = E_OUTOFMEMORY;
- else
- {
- //
- // The ratings apis are ansi.
- //
- CHAR szURL[MAX_URL_STRING];
- SHUnicodeToAnsi(_pszPicsURL, szURL, ARRAYSIZE(szURL));
- hr = RatingObtainQuery(szURL, _dwPicsSerialNumber, RatingObtainQueryCallback, &_hPicsQuery);
- }
- if (FAILED(hr)) {
- TraceMsg(DM_PICS, "CDOH::_StartPicsQuery no async query queued");
- ::_RemovePicsQuery(_dwPicsSerialNumber);
- _dwPicsSerialNumber = 0;
- _fbPicsWaitFlags &= ~PICS_WAIT_FOR_ASYNC;
- }
- else {
- TraceMsg(DM_PICS, "CDOH::_StartPicsQuery async query queued");
- }
- }
- }
- }
- void CDocObjectHost::_GotLabel(HRESULT hres, LPVOID pDetails, BYTE bfSource)
- {
- TraceMsg(DM_PICS, "CDOH::_GotLabel hres=%x, source=%x, waitflags=%x", hres, (DWORD)bfSource, (DWORD)_fbPicsWaitFlags);
- /* If we've already gotten a result from this or a more significant source,
- * ignore this one.
- */
- if (!(_fbPicsWaitFlags & bfSource)) {
- TraceMsg(DM_PICS, "CDOH::_GotLabel already got label from that source");
- 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)) {
- TraceMsg(DM_PICS, "CDOH::_GotLabel label error and may be multiple");
- 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;
- TraceMsg(DM_PICS, "CDOH::_GotLabel, waitflags now %x", (DWORD)_fbPicsWaitFlags);
- if (hres == S_OK) {
- TraceMsg(DM_PICS, "CDOH::_GotLabel allowing access");
- ::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(LPCTSTR pszLabel)
- {
- BYTE bFlag = (_pRootDownload != NULL) ? PICS_WAIT_FOR_ROOT : PICS_WAIT_FOR_INDOC;
- TraceMsg(DM_PICS, "CDOH::_HandleInDocumentLabel source %x gave label %s", (DWORD)bFlag, pszLabel);
- if (!(_fbPicsWaitFlags & bFlag)) {
- TraceMsg(DM_PICS, "CDOH::_HandleInDocumentLabel rejecting based on waitflags %x", (DWORD)_fbPicsWaitFlags);
- return;
- }
- LPVOID pDetails = NULL;
- //
- // Ratings has only ansi apis!
- //
- CHAR szURL[MAX_URL_STRING];
- SHUnicodeToAnsi(_pszPicsURL, szURL, ARRAYSIZE(szURL));
- UINT cbMultiByte = WideCharToMultiByte(CP_ACP, 0, pszLabel,
- -1, NULL, 0, NULL, NULL);
- if (cbMultiByte > 0) {
- char *pszLabelAnsi = new char[cbMultiByte+1];
- if (pszLabelAnsi != NULL)
- {
- if (WideCharToMultiByte(CP_ACP, 0, pszLabel, -1, pszLabelAnsi,
- cbMultiByte+1, NULL, NULL))
- {
- HRESULT hres = ::RatingCheckUserAccess(NULL, szURL,
- pszLabelAnsi, NULL, _dwPicsLabelSource,
- &pDetails);
- _GotLabel(hres, pDetails, bFlag);
- }
- delete [] pszLabelAnsi;
- }
- }
- }
- void CDocObjectHost::_HandleDocumentEnd(void)
- {
- BYTE bFlag = (_pRootDownload != NULL) ? PICS_WAIT_FOR_ROOT : PICS_WAIT_FOR_END;
- TraceMsg(DM_PICS, "CDOH::_HandleDocumentEnd -- no more PICS labels from source %x", (DWORD)bFlag);
- if (_pRootDownload != NULL) {
- ::PostMessage(_hwnd, WM_PICS_ROOTDOWNLOADCOMPLETE, 0, 0);
- }
- else {
- /* End of document; revoke the IOleCommandTarget we gave to the document,
- * so it won't send us any more notifications.
- */
- VARIANTARG v;
- v.vt = VT_UNKNOWN;
- v.lVal = 0;
- IUnknown_Exec(_pole, &CGID_ShellDocView, SHDVID_CANSUPPORTPICS, 0, &v, NULL);
- }
- if (!(_fbPicsWaitFlags & bFlag)) {
- TraceMsg(DM_PICS, "CDOH::_HandleDocumentEnd skipping due to waitflags %x", (DWORD)_fbPicsWaitFlags);
- return;
- }
- _fbPicsWaitFlags &= ~PICS_WAIT_FOR_INDOC; /* we know we won't get any more indoc labels */
- LPVOID pDetails = NULL;
- //
- // Ratings has only ansi apis!
- //
- CHAR szURL[MAX_URL_STRING];
- SHUnicodeToAnsi(_pszPicsURL, szURL, ARRAYSIZE(szURL));
- HRESULT hres = ::RatingCheckUserAccess(NULL, szURL, NULL, NULL, _dwPicsLabelSource, &pDetails);
- _GotLabel(hres, pDetails, bFlag);
- if (_pRootDownload == NULL) {
- if (_fbPicsWaitFlags)
- _StartPicsRootQuery(_pszPicsURL);
- }
- }
- /* This function parses the URL being downloaded and, if the URL doesn't
- * already refer to the root document of the site, sets up a subordinate
- * CDocObjectHost to download that root document, so we can get ratings
- * out of it.
- */
- void CDocObjectHost::_StartPicsRootQuery(LPCTSTR pszURL)
- {
- if (_fbPicsWaitFlags & PICS_WAIT_FOR_ROOT) {
- BOOL fQueued = FALSE;
- TraceMsg(DM_PICS, "CDOH::_StartPicsRootQuery parsing %s", pszURL);
- WCHAR wszRootURL[MAX_URL_STRING+1];
- DWORD cchResult;
- /* The pszURL we're passed is actually the result of calling
- * CoInternetGetSecurityUrl, and so may not be the scheme that
- * the caller is browsing to. To support pluggable protocols
- * determining the root location themselves, we first use the
- * URL reported by _GetCurrentPage, which may refer to a
- * pluggable protocol; if that fails, we use the more standard
- * URL.
- */
- HRESULT hres = INET_E_DEFAULT_ACTION;
- LPOLESTR pwszURL = NULL;
- if (SUCCEEDED(_GetCurrentPageW(&pwszURL, TRUE))) {
- hres = CoInternetParseUrl(pwszURL, PARSE_ROOTDOCUMENT, 0, wszRootURL,
- ARRAYSIZE(wszRootURL), &cchResult, 0);
- OleFree(pwszURL);
- }
- if (pszURL != NULL && (hres == INET_E_DEFAULT_ACTION || hres == E_FAIL)) {
- /* Pluggable protocol doesn't support PARSE_ROOTDOCUMENT. Use the
- * more standard URL we were supplied with.
- */
- hres = CoInternetParseUrl(pszURL, PARSE_ROOTDOCUMENT, 0, wszRootURL,
- ARRAYSIZE(wszRootURL), &cchResult, 0);
- }
- if (SUCCEEDED(hres)) {
- IMoniker *pmk = NULL;
- hres = MonikerFromURL(wszRootURL, &pmk);
- if (SUCCEEDED(hres)) {
- BOOL fFrameIsSilent = FALSE;
- BOOL fFrameIsOffline = FALSE;
- this->_GetOfflineSilent(&fFrameIsOffline, &fFrameIsSilent);
- _pRootDownload = new CPicsRootDownload(this, &_ctPics, fFrameIsOffline, fFrameIsSilent);
- if (_pRootDownload != NULL) {
- TraceMsg(DM_PICS, "CDOH::_StartPicsRootQuery starting download");
- hres = _pRootDownload->StartDownload(pmk);
- if (SUCCEEDED(hres))
- fQueued = TRUE;
- }
- }
- if (pmk != NULL)
- pmk->Release();
- }
- if (!fQueued) {
- _fbPicsWaitFlags &= ~PICS_WAIT_FOR_ROOT;
- TraceMsg(DM_PICS, "CDOH::_StartPicsRootQuery queueing failed, waitflags now %x", (DWORD)_fbPicsWaitFlags);
- if (!_fbPicsWaitFlags) {
- _HandlePicsChecksComplete();
- }
- }
- }
- else {
- TraceMsg(DM_PICS, "CDOH::_StartPicsRootQuery no query queued, waitflags=%x", (DWORD)_fbPicsWaitFlags);
- }
- }
- 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;
- BOOL bSuppressUI = (_bsc._bFrameIsSilent || _IsDesktopItem(SAFECAST(this, CDocObjectHost*))) ? TRUE : FALSE;
- #ifdef DEBUG
- PERFMSG(TEXT("_StartAsyncBinding Calling pmk->BindToObject"), GetCurrentTime()-g_dwPerf);
- g_dwPerf = GetCurrentTime();
- #endif
- #ifdef DEBUG
- if (g_dwPrototype & 0x00000800) {
- TraceMsg(DM_TRACE, "CDOH::_StartAsyncBinding skipping CLSID mapping");
- }
- else
- #endif
- {
- // Register overriding mime->CLSID mapping
- _RegisterMediaTypeClass(pbc);
- }
- // Register accept headers
- _RegisterAcceptHeaders(pbc, _psb);
- if (_pwb)
- _pwb->SetNavigateState(BNS_BEGIN_NAVIGATE);
- _StartPicsQuery();
- //
- // BUGBUG - Crazy sync/async behavior of URLMON. - zekel - 6-AUG-97
- // any of the following may occur:
- //
- // 1. SUCCESS or FAILURE: we receive sync E_PENDING from BindToObject,
- // and then get an Async HRESULT on OnStopBinding().
- // this is the most common case and the basic design.
- //
- // 2. SUCCESS: we receive sync S_OK from BindToObject and
- // need to complete the async behavior on our BSCB ourself
- // since urlmon started but did not finish.
- //
- // 3. SUCCESS: while inside BindToObject(), we receive sync S_OK
- // from OnStopBinding(), and then BindToObject returns with S_OK.
- //
- // 4. FAILURE: simplest case is an error being returned from BindToObject()
- // but without an any OnStopBinding() so we need to complete
- // the async behavior on our BSCB ourself since urlmon started but did not finish.
- // this usually occurs when accessing local files.
- //
- // 5. FAILURE: while inside BindToObject(), we receive sync S_OK from OnStopBinding(),
- // and then BindToObject returns with some other error that needs to be handled.
- // this occurs with some malformed urls.
- //
- // 6. FAILURE: while inside BindToObject(), we receive a sync error from OnStopBinding(),
- // and then BindToObject returns with some other error (usually E_FAIL).
- // we need to trust the first one. this occurs when wininet
- // returns syncronous errors, and its error is the one returned in OnStopBinding()
- //
- // 7. FAILURE: while inside BindToObject(), we receive a sync error from OnStopBinding(),
- // and then BindToObject returns with E_PENDING. which we think means everything
- // is going great, and urlmon thinks it is done. this happens with a file: to
- // a resource that is not hostable. we need to show the download UI.
- //
- // in order to support all the errors in the most consistent and safe manner,
- // we defer any errors in OnStopBinding() if they are delivered synchronously
- // on BindToObject(). the OnStopBinding() error always overrides the BindToObject()
- // error, but any error will always override any success.
- //
- ASSERT(S_OK == _hrOnStopBinding);
- _fSyncBindToObject = TRUE;
- URLMSG(TEXT("_StartAsyncBinding calling pmk->BindToObject"));
- hres = pmk->BindToObject(pbc, NULL, IID_IUnknown, (LPVOID*)&punk);
- URLMSG3(TEXT("_StartAsyncBinding pmk->BindToObject returned"), hres, punk);
- _fSyncBindToObject = FALSE;
- if (SUCCEEDED(_hrOnStopBinding) && (SUCCEEDED(hres) || hres==E_PENDING))
- {
- hres = S_OK;
- if (_bsc._pbc) {
- //
- // In case OnStopBinding hasn't been called.
- //
- 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 {
- //
- // OnStopBinding has been already called.
- //
- if (punk)
- {
- AssertMsg(0, TEXT("CDOH::_StartAsyncBinding pmk->BindToObject returned punk after calling OnStopBinding")); // Probably URLMON bug.
- punk->Release();
- }
- }
- }
- else
- {
- // Binding failed.
- TraceMsg(DM_WARNING, "CDOH::_StartAsyncBinding failed (%x)", hres);
- //
- // BUGBUG - Urlmon is inconsistent in it's error handling - zekel - 4-AUG-97
- // urlmon can return errors in three different ways from BindToObject()
- // 1. it can return back a simple syncronous error. without calling OnStopBinding()
- //
- // 2. it can return a sync error,
- // but call OnStopBinding() with S_OK first on the same thread;
- //
- // 3. it can return a sync error,
- // but also call OnStopBinding() with the real Error first on the same thread.
- //
- // 4. it can return E_PENDING,
- // but already have called OnStopBinding() with the real error.
- //
- // SOLUTIONS:
- // in all cases of error in OnStopBinding(), we will now postpone the OnStopBinding processing util after
- // we have returned from the BindToObject(). we try to use the best error.
- // we allow successful OnStopBinding() to pass through unmolested, and trap
- // the error here if necessary.
- //
- if (FAILED(_hrOnStopBinding))
- hres = _hrOnStopBinding;
- if (_bsc._pbc)
- _bsc.OnStopBinding(hres, NULL);
- else if (!bSuppressUI)
- {
- //
- // OnStopBinding was already called, but with a success
- // so we need to handle the error here. this happens
- // with some invalid URLs like http:/server
- //
- // Fix for W98 webtv app. If we're in a frame don't
- // blow away the frame set to dispaly the error.
- //
- if (!_fHaveParentSite)
- _bsc._NavigateToErrorPage(ERRORPAGE_SYNTAX, this, FALSE);
- }
- ASSERT(_bsc._pbc==NULL);
- }
- return hres;
- }
- void CDocObjectHost::_ReleasePendingObject(BOOL fIfInited)
- {
- HRESULT hres;
- IOleObject *polePending;
- #ifdef TRIDENT_NEEDS_LOCKRUNNING
- IRunnableObject *pro;
- #endif
- if (fIfInited == FALSE && _fPendingWasInited == FALSE)
- return;
- if (_punkPending)
- {
- if (_fCreatingPending)
- {
- _fAbortCreatePending = 1;
- return;
- }
- if (!_fPendingNeedsInit && !IsSameObject(_punkPending, _pole))
- {
- hres = _punkPending->QueryInterface(IID_IOleObject, (LPVOID *) &polePending);
- if (SUCCEEDED(hres)) {
- LPOLECLIENTSITE pcs;
- if (SUCCEEDED(polePending->GetClientSite(&pcs)) && pcs)
- {
- if (pcs == SAFECAST(this, LPOLECLIENTSITE))
- {
- polePending->SetClientSite(NULL);
- }
- pcs->Release();
- }
- polePending->Release();
- }
- }
- #ifdef TRIDENT_NEEDS_LOCKRUNNING
- // TRIDENT NO LONGER SUPPORTS IRunnableObject
- hres = _punkPending->QueryInterface(IID_IRunnableObject, (LPVOID *) &pro);
- if (SUCCEEDED(hres))
- {
- hres = pro->LockRunning(FALSE, TRUE);
- pro->Release();
- }
- #endif
- SAFERELEASE(_punkPending);
- _fPendingWasInited = FALSE;
- }
- }
- void CDocObjectHost::_ReleaseOleObject(BOOL fIfInited)
- {
- TraceMsg(DM_DEBUGTFRAME, "CDocObjectHost::_ReleaseOleObject called %x (%x)", _pole, this);
- // Minimize impact by cleaning up in affected cases only.
- if (fIfInited == FALSE && _fPendingWasInited == FALSE)
- return;
- // 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 (IsSameObject(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);
- }
- }
- //
- // This member releases all the interfaces to the DocObject, which is
- // essentially the reverse of _Bind.
- //
- void CDocObjectHost::_UnBind(void)
- {
- ATOMICRELEASE(_pmsot);
- ASSERT(!_pmsov); // paranoia
- ATOMICRELEASE(_pmsov);
- ASSERT(!_pmsoc); // paranoia
- 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 this is NOT MSHTML, cache the OLE server so that we don't
- // need to restart or load the OLE server again.
- //
- if (!(_dwAppHack & (BROWSERFLAG_MSHTML | BROWSERFLAG_DONTCACHESERVER)))
- {
- IBrowserService *pbs;
- if(SUCCEEDED(QueryService(SID_STopLevelBrowser, IID_IBrowserService, (LPVOID *)&pbs)))
- {
- pbs->CacheOLEServer(_pole);
- pbs->Release();
- }
- }
- TraceMsg(DM_ADVISE, "CDocObjectHost::_UnBind about to call Close of %x", _pole);
- _pole->Close(OLECLOSE_NOSAVE);
- _ReleaseOleObject();
- }
- _ReleasePendingObject();
- ATOMICRELEASE(_pstg);
- ATOMICRELEASE(_pbcCur);
- 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);
- TraceMsg(DM_BINDAPPHACK, "_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);
- TraceMsg(DM_BINDAPPHACK, "_PostBindAppHack StgCreateDocFile(NULL) returned %x", hres);
- if (SUCCEEDED(hres))
- {
- IOleObject* poleCopy = NULL;
- hres = OleCreateFromData(pdt, IID_IOleObject, OLERENDER_NONE,
- NULL, this, _pstg, (LPVOID*)&poleCopy);
- TraceMsg(DM_BINDAPPHACK, "_PostBindAppHack OleCreateFromData(IOleObject) returned %x", hres);
- if (SUCCEEDED(hres)) {
- _fCantSaveBack = TRUE;
- ATOMICRELEASE(_pole);
- _pole = poleCopy;
- }
- }
- pdt->Release();
- }
- }
- //
- // This function get the UserClassID from the object and opens the regkey
- // for that CLSID and returns. If pdwAppHack is non-NULL AND CLSID is
- // CLSID_HTMLDocument, we skip all and returns the default apphack flag.
- // This is a perf optimization, but prevents us from setting browser
- // flags for Trident, which is fine. (SatoNa)
- //
- HKEY _GetUserCLSIDKey(IOleObject* pole, const CLSID* pclsid, DWORD* pdwAppHack)
- {
- HKEY hkey = NULL; // assume error
- HRESULT hres;
- CLSID clsid = CLSID_NULL;
- if (pole) {
- hres = pole->GetUserClassID(&clsid);
- // GetUserClassID is optional, can return E_FAIL, then is defined to be
- // the same as that returned by IPersist::GetClassID. cf, msdev documentation
- // for GetUserClassID
- if (FAILED(hres))
- {
- hres = IUnknown_GetClassID(pole, &clsid);
- }
- } else if (pclsid) {
- clsid = *pclsid;
- hres = S_OK;
- }
- else
- {
- return NULL;
- }
- //
- // Notice that we check for two CLSIDs to see if this is MSHTML.
- //
- if (pdwAppHack)
- {
- static const IID IID_IVBOleObj =
- {0xb88c9640, 0x14e0, 0x11d0, { 0xb3, 0x49, 0x0, 0xa0, 0xc9, 0xa, 0xea, 0x82 } };
- LPUNKNOWN pVBOleObj;
- if( IsEqualGUID(clsid, CLSID_HTMLDocument)
- || IsEqualGUID(clsid, CLSID_MHTMLDocument)
- || IsEqualGUID(clsid, CLSID_HTMLPluginDocument) )
- {
- TraceMsg(TF_SHDAPPHACK, "_GetUserCLSID this is Trident. Skip opening reg key");
- *pdwAppHack = BROWSERFLAG_NEVERERASEBKGND | BROWSERFLAG_SUPPORTTOP
- | BROWSERFLAG_MSHTML;
- return NULL;
- }
- else if (pole && SUCCEEDED(pole->QueryInterface(IID_IVBOleObj, (void**)&pVBOleObj) ))
- {
- // If the object answers to IID_IVBOleObj, it's a VB doc object and shouldn't be cached.
- //
- pVBOleObj->Release();
- *pdwAppHack = BROWSERFLAG_DONTCACHESERVER;
- }
- }
- //
- // 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)) {
- TCHAR szBuf[50]; // 50 is enough for GUID
- SHStringFromGUID(clsid, szBuf, ARRAYSIZE(szBuf));
- TraceMsg(DM_BINDAPPHACK, "_PostBindAppHack GetUserClassID = %s", szBuf);
- TCHAR szKey[60]; // 60 is enough for CLSID\{CLSID_XX}
- wnsprintf(szKey, ARRAYSIZE(szKey), TEXT("CLSID\%s"), szBuf);
- if (RegOpenKey(HKEY_CLASSES_ROOT, szKey, &hkey)!=ERROR_SUCCESS)
- {
- TraceMsg(DM_WARNING, "_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, TEXT("BrowserFlags"), NULL,
- &dwType, (LPBYTE)pdwData, &cbSize)==ERROR_SUCCESS
- && (dwType==REG_DWORD || (dwType==REG_BINARY && cbSize==SIZEOF(*pdwData))))
- {
- fSuccess = TRUE;
- }
- else
- {
- //
- // Unlike IE3, we make it absolutely sure that the type of object
- // has either "DocObject" key or "BrowseInPlace" key under the
- // ProgID. We can't rely on QI(IID_IOleDocument) because MFC 4.2
- // has a bug and returns S_OK to it. As far as I know, MS-Paint
- // and OmniPage pro are affected by this. We could individually
- // address each of them, but it's probably impossible to catch
- // all. This change has a small risk of breaking existing DocObject
- // server which does not have neither key. If we find such a
- // server, we'll address those individually (which is much easier
- // than covering all MFC apps). (SatoNa)
- //
- TCHAR ach[MAX_PATH];
- LONG cb;
- BOOL fBrowsable = FALSE;
- if ((cb=SIZEOF(ach)) && RegQueryValue(hkey, TEXT("DocObject"), ach, &cb) == ERROR_SUCCESS)
- fBrowsable = TRUE;
- else if ((cb=SIZEOF(ach)) && RegQueryValue(hkey, TEXT("BrowseInPlace"), ach, &cb) == ERROR_SUCCESS)
- fBrowsable = TRUE;
- if (!fBrowsable) {
- TraceMsg(DM_WARNING, "_GetAppHackKey this is neither DocObject or BrowseInPlace");
- *pdwData = BROWSERFLAG_DONTINPLACE;
- }
- }
- RegCloseKey(hkey);
- }
- return fSuccess;
- }
- void GetAppHackFlags(IOleObject* pole, const CLSID* pclsid, DWORD* pdwAppHack)
- {
- HKEY hkey = _GetUserCLSIDKey(pole, pclsid, pdwAppHack);
- if (hkey)
- {
- TCHAR szValue[MAX_PATH];
- LONG cb = SIZEOF(szValue);
- if (RegQueryValue(hkey, TEXT("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
- //
- _GetAppHackKey(szValue, pdwAppHack);
- if (!(*pdwAppHack & BROWSERFLAG_REPLACE)) {
- typedef struct _APPHACK {
- LPCTSTR pszProgID;
- DWORD dwAppHack;
- } APPHACK;
- //
- // We no longer need to disable in-place activation of
- // MS-PAINT because we look for "BrowseInPlace" or
- // "DocObject" key
- //
- // { "Paint.Picture", BROWSERFLAG_DONTINPLACE },
- //
- const static APPHACK s_aah[] = {
- { TEXT("Excel.Sheet.5"), BROWSERFLAG_OPENCOPY },
- { TEXT("Excel.Chart.5"), BROWSERFLAG_OPENCOPY },
- { TEXT("SoundRec"), BROWSERFLAG_OPENVERB },
- { TEXT("Word.Document.6"), BROWSERFLAG_SETHOSTNAME },
- { TEXT("Word.Document.8"), BROWSERFLAG_DONTUIDEACTIVATE | BROWSERFLAG_SETHOSTNAME },
- { TEXT("PowerPoint.Show.8"), BROWSERFLAG_DONTUIDEACTIVATE | BROWSERFLAG_PRINTPROMPTUI },
- { TEXT("Excel.Sheet.8"), BROWSERFLAG_DONTDEACTIVATEMSOVIEW | BROWSERFLAG_INITNEWTOKEEP },
- { TEXT("Excel.Chart.8"), BROWSERFLAG_DONTDEACTIVATEMSOVIEW | BROWSERFLAG_INITNEWTOKEEP },
- { TEXT("ABCFlowCharter6.Document"), BROWSERFLAG_DONTINPLACE },
- { TEXT("ABCFlowCharter7.Document"), BROWSERFLAG_DONTINPLACE },
- { TEXT("FlowCharter7.Document"), BROWSERFLAG_DONTINPLACE },
- { TEXT("ChannelFile"), BROWSERFLAG_DONTAUTOCLOSE },
- { TEXT("Visio.Drawing.5"), BROWSERFLAG_ENABLETOOLSBTN | BROWSERFLAG_SAVEASWHENCLOSING },
- { TEXT("Visio.Drawing.4"), BROWSERFLAG_ENABLETOOLSBTN | BROWSERFLAG_SAVEASWHENCLOSING }
- };
- const static TCHAR s_ActiveMoveCtx[] = TEXT("AMOVIE.ActiveMovieControl");
- if (!StrCmpN(szValue, s_ActiveMoveCtx, ARRAYSIZE(s_ActiveMoveCtx)-1))
- {
- *pdwAppHack = BROWSERFLAG_DONTAUTOCLOSE;
- }
- else
- {
- for (int i=0; i<ARRAYSIZE(s_aah); i++) {
- if (StrCmp(szValue, s_aah[i].pszProgID)==0)
- {
- *pdwAppHack |= s_aah[i].dwAppHack;
- break;
- }
- }
- }
- }
- TraceMsg(DM_BINDAPPHACK, "_GetAppHack ProgID=%s, *pdwAppHack=%x",
- szValue, *pdwAppHack);
- } else {
- TraceMsg(DM_BINDAPPHACK, "_GetAppHack RegQueryValue(ProgID) failed");
- }
- RegCloseKey(hkey);
- }
- }
- DWORD CDocObjectHost::_GetAppHack(void)
- {
- ASSERT(_pole);
- if (!_fHaveAppHack && _pole)
- {
- _dwAppHack = 0; // Assume no hack
- _fHaveAppHack = TRUE;
- ::GetAppHackFlags(_pole, NULL, &_dwAppHack);
- }
- return _pole ? _dwAppHack : 0;
- }
- 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;
- 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);
- }
- TraceMsg(0, "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(LPCWSTR szPath)
- {
- LPCTSTR pszExtension = PathFindExtension(szPath);
- BOOL bRet = FALSE;
- CHAR szBuf[MAX_PATH];
- CHAR szExt[_MAX_EXT];
- //
- // SHVerbExistsN is ansi only.
- //
- SHUnicodeToAnsi(pszExtension, szExt, ARRAYSIZE(szExt));
- if (SHVerbExistsNA(szExt, "open", szBuf, SIZECHARS (szBuf))) {
- TraceMsg(TF_SHDBINDING, "IsAssociatedWithIE(%s) found %s as open command", szPath, szBuf);
- LPCSTR pszFound;
- if ( (pszFound=StrStrIA(szBuf, IEXPLORE_EXE))
- || (pszFound=StrStrIA(szBuf, EXPLORER_EXE)) ) {
- if (pszFound==szBuf || *AnsiPrev(szBuf, pszFound)=='\') {
- bRet = TRUE;
- }
- }
- }
- TraceMsg(DM_SELFASC, "IsAssociatedWithIE(%s) returning %d", szPath, bRet);
- return bRet;
- }
- UINT CDocObjectHost::_PicsBlockingDialog(LPCTSTR pszURL)
- {
- pszURL = _pszPicsURL;
- TraceMsg(DM_PICS, "CDOH::_PicsBlockingDialog(%s)", pszURL);
- _StartPicsRootQuery(pszURL);
- _fDrawBackground = TRUE;
- ::InvalidateRect(_hwnd, NULL, TRUE); /* mega cheesy, but only way to get browser window erased */
- /* 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) {
- TraceMsg(DM_PICS, "CDOH::_PicsBlockingDialog entering msg loop, waitflags=%x", (DWORD)_fbPicsWaitFlags);
- MSG msg;
- if (GetMessage(&msg, NULL, 0, 0)) {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
- }
- if (!_fPicsAccessAllowed) {
- TraceMsg(DM_PICS, "CDOH::_PicsBlockingDialog, access denied");
- // If this is silent-mode (no UI == screensaver), always deny access
- // without any dialog.
- BOOL fFrameIsSilent = FALSE; // Assume non-silent
- _GetOfflineSilent(NULL, &fFrameIsSilent);
- if (fFrameIsSilent) {
- TraceMsg(DM_PICS, "CDOH::_PicsBlockingDialog access denied in silent mode, aborting");
- return IDCANCEL;
- }
- _EnableModeless(FALSE);
- HRESULT hres = S_OK;
- IOleCommandTarget *pcmdtTop;
- if (SUCCEEDED(QueryService(SID_STopLevelBrowser, IID_IOleCommandTarget, (void **)&pcmdtTop))) {
- VARIANTARG v = { 0 };
- v.vt = VT_INT_PTR;
- v.byref = _pRatingDetails;
- hres = pcmdtTop->Exec(&CGID_ShellDocView, SHDVID_PICSBLOCKINGUI, 0, &v, NULL);
- pcmdtTop->Release();
- }
- UINT uRet = (hres == S_OK) ? IDOK : IDCANCEL;
- _EnableModeless(TRUE);
- _fPicsAccessAllowed = (uRet == IDOK);
- TraceMsg(DM_PICS, "CDOH::_PicsBlockingDialog returning %d", uRet);
- return uRet;
- }
- else {
- TraceMsg(DM_PICS, "CDOH::_PicsBlockingDialog, access allowed");
- return IDOK;
- }
- }
- HRESULT CDocObjectHost::_MayHaveVirus(REFCLSID rclsid)
- {
- //
- // We'll call this function twice if the file is associated
- // with a bogus CLSID (such as ImageComposer).
- //
- if (_fConfirmed) {
- TraceMsg(TF_SHDAPPHACK, "CDOH::_MayHaveVirus called twice. Return S_OK");
- return S_OK;
- }
- TraceMsg(TF_SHDPROGRESS, "DOH::_MayHaveVirus called");
- LPWSTR pwzProgID = NULL;
- HRESULT hresT = E_FAIL;
- if (SUCCEEDED(ProgIDFromCLSID(rclsid, &pwzProgID)))
- {
- if (StrCmpI(pwzProgID, TEXT("htmlfile"))!=0
- && StrCmpI(pwzProgID, TEXT("htmlfile_FullWindowEmbed"))!=0
- && StrCmpI(pwzProgID, TEXT("mhtmlfile"))!=0
- && StrCmpI(pwzProgID, TEXT("xmlfile"))!=0
- && StrCmpI(pwzProgID, TEXT("xslfile"))!=0)
- {
- TCHAR szURL[MAX_URL_STRING];
- TCHAR * pszURL = szURL;
- hresT = _GetCurrentPage(szURL, ARRAYSIZE(szURL), TRUE);
- if (SUCCEEDED(hresT)) {
- UINT uRet = IDOK;
- if (_fbPicsWaitFlags || !_fPicsAccessAllowed) {
- _fbPicsWaitFlags &= ~(PICS_WAIT_FOR_INDOC | PICS_WAIT_FOR_END); /* indoc ratings only on htmlfile */
- TraceMsg(DM_PICS, "CDOH::_MayHaveVirus found non-HTML, waitflags now %x", (DWORD)_fbPicsWaitFlags);
- uRet = _PicsBlockingDialog(szURL);
- }
- if (uRet == IDOK) {
- TraceMsg(TF_SHDPROGRESS, "DOH::_MayHaveVirus calling MayOpenSafeDialogOpenDialog(%s)", pwzProgID);
- if (_bsc._pszRedirectedURL && *_bsc._pszRedirectedURL)
- pszURL = _bsc._pszRedirectedURL;
- uRet = MayOpenSafeOpenDialog(_hwnd, pwzProgID, pszURL, NULL, NULL, _uiCP);
- _fCalledMayOpenSafeDlg = TRUE;
- }
- switch(uRet) {
- case IDOK:
- //
- // Set this flag to avoid poppping this dialog box twice.
- //
- _fConfirmed = TRUE;
- break; // continue download
- case IDD_SAVEAS:
- CDownLoad_OpenUI(_pmkCur, _bsc._pbc, FALSE, TRUE, NULL, NULL, NULL, NULL, NULL, _bsc._pszRedirectedURL, _uiCP);
- // fall through to abort binding.
- case IDCANCEL:
- hresT = HRESULT_FROM_WIN32(ERROR_CANCELLED);
- break;
- }
- } else {
- TraceMsg(DM_ERROR, "DOH::_MayHaveVirus _GetCurrentPage failed %x", hresT);
- }
- } else {
- TraceMsg(TF_SHDPROGRESS, "DOH::_MayHaveVirus this is htmlfile -- don't call MayOpenSafeDialogOpenDialog");
- _fPicsBlockLate = TRUE;
- }
- OleFree(pwzProgID);
- }
- return hresT;
- }
- STDMETHODIMP CDocObjectHost::SaveObject(void)
- {
- TraceMsg(0, "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;
- TraceMsg(TF_SHDBINDING, "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)
- //
- // NOTE: If trident calls this after DestroyHostWindow, we have nothing
- // to give out. Hopefully this is not bad. (MikeSh)
- TraceMsg(0, "sdv TR: CDOV::GetContainer called");
- if (_psb)
- return _psb->QueryInterface(IID_IOleContainer, (LPVOID*)ppContainer);
- return E_FAIL;
- }
- STDMETHODIMP CDocObjectHost::ShowObject(void)
- {
- TraceMsg(0, "sdv TR: CDOV::ShowObject called");
- return E_NOTIMPL; // As specified in Kraig's document
- }
- STDMETHODIMP CDocObjectHost::OnShowWindow(BOOL fShow)
- {
- TraceMsg(TF_SHDUIACTIVATE, "DOH::OnShowWindow(%d) called (this=%x)", fShow, this);
- return E_NOTIMPL; // As specified in Kraig's document
- }
- STDMETHODIMP CDocObjectHost::RequestNewObjectLayout(void)
- {
- TraceMsg(0, "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)
- {
- // In order for the context menu to work correctly inside IFrames, we
- // need to fail a certain query ONLY for IFrames on desktop.
- if(!IsEqualGUID(guidService, CLSID_HTMLDocument) || !_IsImmediateParentDesktop(this, _psp))
- {
- //
- // Delegate ISP to the _psb.
- //
- if (_psb && _psp)
- return _psp->QueryService(guidService, riid, ppvObj);
- }
- *ppvObj = NULL;
- return E_NOINTERFACE;
- }
- /*----------------------------------------------------------
- Purpose: Remove the submenu(s) that are in _hmenuFrame
- from _hmenuBrowser.
- */
- void CDocObjectHost::_RemoveFrameSubMenus(void)
- {
- HMENU hmenu;
- ASSERT(IS_VALID_HANDLE(_hmenuBrowser, MENU));
- ASSERT(IS_VALID_HANDLE(_hmenuFrame, MENU));
- // The file menu in _hmenuBrowser consists of the file menu from
- // _hmenuFrame and IShellBrowser. The part added by _hmenuFrame
- // 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(_hmenuFrame, 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.
- */
- HRESULT CDocObjectHost::_DestroyBrowserMenu(void)
- {
- TraceMsg(TF_SHDUIACTIVATE, "DOH::_DestroyBrowserMenu called");
- if (_hmenuBrowser) {
- // First remove any submenus that are held by other menus,
- // so we don't blow them away.
- _RemoveFrameSubMenus();
- if (EVAL(_psb)) {
- _psb->RemoveMenusSB(_hmenuBrowser);
- }
- DestroyMenu(_hmenuBrowser);
- _hmenuBrowser = NULL;
- }
- return S_OK;
- }
- HRESULT CDocObjectHost::_CreateBrowserMenu(LPOLEMENUGROUPWIDTHS pmw)
- {
- TraceMsg(TF_SHDUIACTIVATE, "DOH::_CreateBrowserMenu called");
- if (_hmenuBrowser) {
- return S_OK;
- }
- _hmenuBrowser = CreateMenu();
- if (!_hmenuBrowser) {
- return E_OUTOFMEMORY;
- }
- HRESULT hres = E_FAIL;
- // Allow IShellBrowser a chance to add its menus
- if (EVAL(_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 (!_hmenuFrame)
- {
- _hmenuFrame = LoadMenu(MLGetHinst(), MAKEINTRESOURCE(MID_FOCUS));
- }
- // Get the "File" sub-menu from the shell browser.
- MENUITEMINFO mii;
- mii.cbSize = sizeof(mii);
- mii.fMask = MIIM_SUBMENU;
- if (GetMenuItemInfo(_hmenuBrowser, FCIDM_MENU_FILE, FALSE, &mii))
- {
- HMENU hmenuFileBrowse = mii.hSubMenu;
- // Merge our menuitems into this submenu.
- if (_hmenuFrame)
- {
- MENUITEMINFO miiItem;
- miiItem.cbSize = SIZEOF(MENUITEMINFO);
- miiItem.fMask = MIIM_SUBMENU;
- if (GetMenuItemInfo(_hmenuFrame, FCIDM_MENU_FILE, FALSE, &miiItem))
- {
- TCHAR 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);
- }
- }
- }
- }
- }
- else
- {
- TraceMsg(TF_SHDUIACTIVATE, "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;
- int nMenuOffset = 0;
- TraceMsg(TF_SHDUIACTIVATE, "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)) {
- TraceMsg(DM_ERROR, "DOH::InsertMenus _CreateBrpwserMenu failed");
- return hres;
- }
- // Get the "File" sub-menu from the shell browser.
- MENUITEMINFO mii;
- TCHAR szSubMenu[128];
- mii.cbSize = SIZEOF(mii);
- mii.fMask = MIIM_SUBMENU|MIIM_TYPE|MIIM_ID;
- mii.cch = ARRAYSIZE(szSubMenu);
- mii.dwTypeData = szSubMenu;
- if (EVAL(GetMenuItemInfo(_hmenuBrowser, FCIDM_MENU_FILE, FALSE, &mii)))
- {
- ASSERT(szSubMenu == mii.dwTypeData);
- InsertMenuItem(hmenuShared, nMenuOffset++, TRUE, &mii);
- lpMenuWidths->width[0] = 1;
- }
- // Note that we need to re-initialize mii
- mii.cch = ARRAYSIZE(szSubMenu);
- if (EVAL(GetMenuItemInfo(_hmenuBrowser, FCIDM_MENU_EXPLORE, FALSE, &mii)))
- {
- // BUGBUG: GetMenuItemInfo is recursive (why?). The item it retrieves
- // for FCIDM_MENU_EXPLORE can either be the top level Go menu, or if that
- // does not exist (NT5 case), it returns the Go To submenu of View.
- //
- // Code has been added in in the SetMenu implementations of Shell Browser
- // and Dochost to detect the second case, because the menu dispatch list
- // does not recognize this kind of menu merging (80734).
- DeleteMenu(mii.hSubMenu, FCIDM_PREVIOUSFOLDER, MF_BYCOMMAND);
- InsertMenuItem(hmenuShared, nMenuOffset++, TRUE, &mii);
- lpMenuWidths->width[4]++;
- }
- mii.cch = ARRAYSIZE(szSubMenu);
- if (EVAL(GetMenuItemInfo(_hmenuBrowser, FCIDM_MENU_FAVORITES, FALSE, &mii)))
- {
- InsertMenuItem(hmenuShared, nMenuOffset++, TRUE, &mii);
- lpMenuWidths->width[4]++;
- }
- if (_hmenuFrame)
- {
- // Micro-merge the help menu.
- mii.cch = ARRAYSIZE(szSubMenu);
- if (EVAL(GetMenuItemInfo(_hmenuFrame, FCIDM_MENU_HELP, FALSE, &mii)))
- {
- InsertMenuItem(hmenuShared, nMenuOffset++, TRUE, &mii);
- lpMenuWidths->width[5]++;
- }
- }
- DEBUG_CODE( _DumpMenus(TEXT("after InsertMenus"), TRUE); )
- return hres;
- }
- /*----------------------------------------------------------
- Purpose: Different objects may add their own Help menu (like
- Word and Excel). This function detects if the object
- added its own help menu, or if it added items to our
- help menu, or if it is just using our help menu.
- If they added their own help menu, we remove ours.
- */
- void CDocObjectHost::_CompleteHelpMenuMerge(HMENU hmenu)
- {
- HMENU hmenuHelp;
- MENUITEMINFO mii;
- TCHAR szSubMenu[80];
- mii.cbSize = SIZEOF(mii);
- mii.fMask = MIIM_SUBMENU;
- // see if they added anything to our menu
- if (GetMenuItemInfo(_hmenuFrame, FCIDM_MENU_HELP, FALSE, &mii))
- {
- hmenuHelp = mii.hSubMenu;
- int iMenuCount = GetMenuItemCount(mii.hSubMenu);
- // Did the number of items in the help menu change?
- if (iMenuCount != HELP_ITEM_COUNT) {
- // Yes; that means they added something. This has been micro-merged.
- _hmenuMergedHelp = mii.hSubMenu;
- _hmenuObjHelp = GetSubMenu(mii.hSubMenu, iMenuCount -1);
- goto Bail;
- }
- // Our menu didn't change. Now find out if they added their own
- // help menu or if we ARE the help. If they added their own, we need
- // to remove our help menu.
- _hmenuMergedHelp = NULL;
- _hmenuObjHelp = NULL;
- int iCount = GetMenuItemCount(hmenu) - 1;
- int i;
- for (i = iCount ; i >= 0 ; i--) {
- mii.fMask = MIIM_SUBMENU|MIIM_TYPE;
- mii.cch = ARRAYSIZE(szSubMenu);
- mii.dwTypeData = szSubMenu;
- 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
- TCHAR szMenuTitle[80];
- mii.cch = ARRAYSIZE(szMenuTitle);
- mii.dwTypeData = szMenuTitle;
- if (GetMenuItemInfo(hmenu, i-1, TRUE, &mii)) {
- if (!StrCmpI(szMenuTitle, szSubMenu)) {
- // same menu string yank ours
- bRemove = TRUE;
- }
- }
- }
- if (bRemove) {
- RemoveMenu(hmenu, i, MF_BYPOSITION);
- }
- }
- }
- }
- }
- Bail:;
- DEBUG_CODE( _DumpMenus(TEXT("after _CompleteHelpMenuMerge"), TRUE); )
- }
- //
- // IOleInPlaceFrame::SetMenu equivalent
- //
- HRESULT CDocObjectHost::_SetMenu(
- /* [in] */ HMENU hmenuShared, OPTIONAL
- /* [in] */ HOLEMENU holemenu, OPTIONAL
- /* [in] */ HWND hwndActiveObject)
- {
- TraceMsg(TF_SHDUIACTIVATE, "DOH::SetMenus(%x) called (this=%x)",
- hmenuShared, this);