dochost.cpp
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 339k
Category:

Windows Kernel

Development Platform:

Visual C++

  1. //
  2. // NOTES:
  3. //
  4. //  This is the code which enables the explorer hosting (being a container)
  5. // a DocObject (a super set of OLE in-place object). In a nut shell, this
  6. // code creates an object (class CDocObjectHost) which can be plugged into
  7. // the explorer's right pane (by supporting IShellView) is also a DocObject
  8. // container (by supporting IOleClientSite, IOleInPlaceSite, ...).
  9. //
  10. //  This CDocObjectHost directly supports following interfaces:
  11. //
  12. // Group 1 (to be plugged in):
  13. //   IShellView, IDropTarget
  14. // Group 2 (to be a Doc site):
  15. //   IOleClientSite, IOleDocumentSite
  16. // Group 3 (to be a View Site)
  17. //   IOleInPlaceSite
  18. //
  19. //  It also supports following interfaces indirectly via contained object,
  20. // CDocObjectFrame.
  21. //
  22. //  IOleInPlaceFrame, IOleCommandTarget
  23. //
  24. //  The reason we export them separately is because we may need to return
  25. // a different hwnd for GetWindow method. The CDocObjectHost object always
  26. // returns hwnd of the view window, but the CDocObjectFrame returns hwnd
  27. // of the explorer in case the explorer support IOleInPlaceUIWindow.
  28. //
  29. //  It also supports following interface indirectly via contained object,
  30. // CProxyActiveObject.
  31. //
  32. //  IOleInPlaceActiveObject
  33. //
  34. //
  35. //  --------------------------------------------------------
  36. //      Explorer (browser)
  37. //  --------------------------------------------------------
  38. //        ^          |          |
  39. //        |          |          |
  40. //   ISB (+IOIUI)   ISV       IOIAO
  41. //        |          |          |
  42. //        |          V          |
  43. //  ----------------------------V---------------------------
  44. //       CDocObjectHost  CProxyActiveObject CDocObjectFrame
  45. //  ----------------------------------------------^---------
  46. //        ^                |                      |
  47. //        |                |                      |
  48. //  IOCS/IOIPS/IMDS   IO/IOIPO/IMV/IMCT    IOIUI/IOIF/IMCT
  49. //        |                |                      |
  50. //        |                V                      |
  51. //  --------------------------------------------------------
  52. //       DocObject (Doc + View)
  53. //  --------------------------------------------------------
  54. //
  55. #include "priv.h"
  56. #include "iehelpid.h"
  57. #include "bindcb.h"
  58. #include "winlist.h"
  59. #include "droptgt.h"
  60. #include <mshtml.h>     // CLSID_HTMLDocument
  61. #include <mshtmcid.h>
  62. #include "resource.h"
  63. #include <htmlhelp.h>
  64. #include <prsht.h>
  65. #include <inetcpl.h>
  66. #include <optary.h>
  67. #include "impexp.h"
  68. #include "impexpwz.h"
  69. #include "thicket.h"
  70. #include "uemapp.h"
  71. #include "iextag.h"   // web folders
  72. #include "browsext.h"
  73. #include <mluisupp.h>
  74. // temp, going away once itbar edit stuff moves here
  75. #define  CITIDM_EDITPAGE  10
  76. // Command group for private communication with CITBar
  77. // 67077B95-4F9D-11D0-B884-00AA00B60104
  78. const GUID CGID_PrivCITCommands = { 0x67077B95L, 0x4F9D, 0x11D0, 0xB8, 0x84,
  79. 0x00, 0xAA, 0x00, 0xB6, 0x01, 0x04 };
  80. // end temp itbar stuff
  81. #define  DBG_ACCELENTRIES 2
  82. #define  OPT_ACCELENTRIES 1
  83. #ifdef UNIX
  84. #include <unixstuff.h>
  85. #define  EXPLORER_EXE "explorer"
  86. #define  IEXPLORE_EXE "iexplorer"
  87. #define  DBG_ACCELENTRIES_WITH_FILEMENU 8
  88. #define  OPT_ACCELENTRIES_WITH_FILEMENU 7
  89. #else
  90. #define  EXPLORER_EXE "explorer.exe"
  91. #define  IEXPLORE_EXE "iexplore.exe"
  92. #define  DBG_ACCELENTRIES_WITH_FILEMENU 6
  93. #define  OPT_ACCELENTRIES_WITH_FILEMENU 5
  94. #endif /* UNIX */
  95. EXTERN_C const GUID IID_IDocHostObject  = {0x67431840L, 0xC511, 0x11CF, 0x89, 0xA9, 0x00, 0xA0, 0xC9, 0x05, 0x41, 0x29};
  96. EXTERN_C const GUID IID_IMimeInfo       = {0xF77459A0L, 0xBF9A, 0x11cf, 0xBA, 0x4E, 0x00, 0xC0, 0x4F, 0xD7, 0x08, 0x16};
  97. EXTERN_C const GUID IID_IsPicsBrowser   = {0xF114C2C0L, 0x90BE, 0x11D0, 0x83, 0xB1, 0x00, 0xC0, 0x4F, 0xD7, 0x05, 0xB2};
  98. #include <shlwapi.h>
  99. #include <ratings.h>
  100. #define DM_ZONECROSSING 0
  101. #define DM_SAVEASHACK   0
  102. #define DM_MIMEMAPPING  0
  103. #define DM_SELFASC      TF_SHDBINDING
  104. #define DM_ACCEPTHEADER 0
  105. #define DM_DEBUGTFRAME  0
  106. #define DM_DOCHOSTUIHANDLER 0
  107. #define DM_PREMERGEDMENU    0
  108. #define DM_FOCUS        0
  109. #define DM_DOCCP        0
  110. #define DM_PICS         0
  111. #define DM_SSL              0
  112. // WARNING: Never define it in shipping product.
  113. #ifdef DEBUG
  114. // #define TEST_DELAYED_SHOWMSOVIEW
  115. #endif
  116. void CShdAdviseSink_Advise(IBrowserService* pwb, IOleObject* pole);
  117. UINT MayOpenSafeOpenDialog(HWND hwndOwner, LPCTSTR pszFileClass, LPCTSTR pszURL, LPCTSTR pszCacheName, LPCTSTR pszDisplay, UINT uiCP);
  118. LONG _GetSearchFormatString(DWORD dwIndex, LPTSTR psz, DWORD cbpsz);
  119. DWORD _GetErrorThreshold(DWORD dwError);
  120. HRESULT GetSearchKeys (LPDWORD pdwSearchForExtensions, LPDWORD pdwDo404Search);
  121. BOOL IsRegisteredClient(LPCTSTR pszClient);
  122. // macros
  123. #define DO_SEARCH_ON_STATUSCODE(x) ((x == 0) || (x == HTTP_STATUS_BAD_GATEWAY) || (x == HTTP_STATUS_GATEWAY_TIMEOUT))
  124. // Suite Apps Registry keys
  125. #define NEW_MAIL_DEF_KEY            TEXT("Mail")
  126. #define NEW_NEWS_DEF_KEY            TEXT("News")
  127. #define NEW_CONTACTS_DEF_KEY        TEXT("Contacts")
  128. #define NEW_CALL_DEF_KEY            TEXT("Internet Call")
  129. #define NEW_APPOINTMENT_DEF_KEY     TEXT("Appointment")
  130. #define NEW_MEETING_DEF_KEY         TEXT("Meeting")
  131. #define NEW_TASK_DEF_KEY            TEXT("Task")
  132. #define NEW_TASKREQUEST_DEF_KEY     TEXT("Task Request")
  133. #define NEW_JOURNAL_DEF_KEY         TEXT("Journal")
  134. #define NEW_NOTE_DEF_KEY            TEXT("Note")
  135. #ifdef DEBUG
  136. DWORD g_dwPerf = 0;
  137. #endif
  138. // #include "..shell32fstreex.h"              // for IDFOLDER
  139. // HACK:
  140. struct IDFOLDERA
  141. {
  142.     WORD    cb;
  143.     BYTE    bFlags;
  144. };
  145. typedef IDFOLDERA* LPIDFOLDERA;
  146. const ITEMIDLIST s_idNull = { {0} };
  147. //
  148. // Icons are globally shared among multiple threads.
  149. //
  150. HICON g_hiconSSL = NULL;
  151. HICON g_hiconFortezza = NULL;
  152. HICON g_hiconOffline = NULL;
  153. HICON g_hiconPrinter = NULL;
  154. HICON g_hiconScriptErr = NULL;
  155. HICON g_ahiconState[IDI_STATE_LAST-IDI_STATE_FIRST+1] = { NULL };
  156. #define MAX_MIXED_STR_LEN   32
  157. // OpenUIURL is just a wrapper for OpenUI, calling CreateURLMoniker() if the
  158. // caller only has an URL.
  159. extern BOOL __cdecl _FormatMessage(LPCSTR szTemplate, LPSTR szBuf, UINT cchBuf, ...);
  160. #include "asyncrat.h"
  161. #define MAX_STATUS_SIZE 128
  162. //
  163. // Set this flag if we are going to use IHlinkBrowseContext in HLINK.DLL
  164. // #define HLINK_EXTRA
  165. //
  166. #include "dochost.h"
  167. #define DM_RECYCLE      DM_TRACE
  168. #define DM_BINDAPPHACK  TF_SHDAPPHACK
  169. #define DM_ADVISE       TF_SHDLIFE
  170. #define DM_APPHACK      DM_WARNING
  171. #define NAVMSG3(psz, x, y)      TraceMsg(0, "shdv NAV::%s %x %x", psz, x, y)
  172. #define PAINTMSG(psz,x)         TraceMsg(0, "shd TR-PAINT::%s %x", psz, x)
  173. #define JMPMSG(psz, psz2)       TraceMsg(0, "shd TR-CDOV::%s %s", psz, psz2)
  174. #define JMPMSG2(psz, x)         TraceMsg(0, "shd TR-CDOV::%s %x", psz, x)
  175. #define DOFMSG(psz)             TraceMsg(0, "shd TR-DOF::%s", psz)
  176. #define DOFMSG2(psz, x)         TraceMsg(0, "shd TR-DOF::%s %x", psz, x)
  177. #define URLMSG(psz)             TraceMsg(TF_SHDBINDING, "shd TR-DOF::%s", psz)
  178. #define URLMSG2(psz, x)         TraceMsg(TF_SHDBINDING, "shd TR-DOF::%s %x", psz, x)
  179. #define URLMSG3(psz, x, y)      TraceMsg(TF_SHDBINDING, "shd TR-DOF::%s %x %x", psz, x, y)
  180. #define OIPSMSG(psz)            TraceMsg(0, "shd TR-OIPS::%s", psz)
  181. #define OIPSMSG3(psz, sz, p)    TraceMsg(0, "shd TR-OIPS::%s %s,%x", psz, sz,p)
  182. #define VIEWMSG(psz)            TraceMsg(0, "sdv TR CDOV::%s", psz)
  183. #define VIEWMSG2(psz,xx)        TraceMsg(0, "sdv TR CDOV::%s %x", psz,xx)
  184. #define OPENMSG(psz)            TraceMsg(TF_SHDBINDING, "shd OPENING %s", psz)
  185. #define OPENMSG2(psz, x)        TraceMsg(TF_SHDBINDING, "shd OPENING %s %x", psz, x)
  186. #define HFRMMSG(psz)            TraceMsg(0, "shd HFRM::%s", psz)
  187. #define HFRMMSG2(psz, x, y)     TraceMsg(0, "shd HFRM::%s %x %x", psz, x, y)
  188. #define MNKMSG(psz, psz2)       TraceMsg(0, "shd MNK::%s (%s)", psz, psz2)
  189. #define CHAINMSG(psz, x)        TraceMsg(0, "shd CHAIN::%s %x", psz, x)
  190. #define SHVMSG(psz, x, y)       TraceMsg(0, "shd SHV::%s %x %x", psz, x, y)
  191. #define HOMEMSG(psz, psz2, x)   TraceMsg(TF_SHDNAVIGATE, "shd HOME::%s %s %x", psz, psz2, x)
  192. #define SAVEMSG(psz, x)         TraceMsg(0, "shd SAVE::%s %x", psz, x)
  193. #define PERFMSG(psz, x)         TraceMsg(TF_SHDPERF, "PERF::%s %d msec", psz, x)
  194. static const TCHAR  szRegKey_SMIEM[] =              TEXT("Software\Microsoft\Internet Explorer\Main");
  195. static const TCHAR  szRegVal_ErrDlgPerErr[] =       TEXT("Error Dlg Displayed On Every Error");
  196. static const TCHAR  szRegVal_ErrDlgDetailsOpen[] =  TEXT("Error Dlg Details Pane Open");
  197. ////////////////////////////////////////////////////////////
  198. // ShabbirS (980917) - BugFix# 34259
  199. // Repair menuitem in the Help Menu.
  200. typedef HRESULT (* FIXIEPROC) (BOOL, DWORD);
  201. void RepairIE()
  202. {
  203.     HINSTANCE   hIESetup;
  204.     FIXIEPROC   fpFixIE;
  205.     hIESetup = LoadLibrary(L"IESetup.dll");
  206.     if (hIESetup)
  207.     {
  208.         fpFixIE = (FIXIEPROC) GetProcAddress(hIESetup,"FixIE");
  209.         if (fpFixIE)
  210.         {
  211.             fpFixIE(TRUE,0);
  212.         }
  213.         FreeLibrary(hIESetup);
  214.     }
  215. }
  216. BOOL _IsDesktopItem(CDocObjectHost * pdoh)
  217. {
  218.     BOOL fIsDesktopItem = FALSE;
  219.     IServiceProvider  * psb;
  220.     ASSERT(pdoh);
  221.     //Check if we are a desktop component.
  222.     if(SUCCEEDED(pdoh->QueryService(SID_STopLevelBrowser, IID_IServiceProvider, (void **)&psb)))
  223.     {
  224.         LPTARGETFRAME2  ptgf;
  225.         if(SUCCEEDED(psb->QueryService(IID_ITargetFrame2, IID_ITargetFrame2, (void **)&ptgf)))
  226.         {
  227.             DWORD dwOptions;
  228.             if(SUCCEEDED(ptgf->GetFrameOptions(&dwOptions)))
  229.             {
  230.                 //Is this a desktop component?
  231.                 if(IsFlagSet(dwOptions, FRAMEOPTIONS_DESKTOP))
  232.                     fIsDesktopItem = TRUE;
  233.             }
  234.             ptgf->Release();
  235.         }
  236.         psb->Release();
  237.     }
  238.     return fIsDesktopItem;
  239. }
  240. BOOL _IsImmediateParentDesktop(CDocObjectHost *pdoh, IServiceProvider *psp)
  241. {
  242.     BOOL    fImmediateParentIsDesktop = FALSE;
  243.     LPTARGETFRAME2  ptgf;
  244.     //First check if this is hosted on desktop.
  245.     if(!_IsDesktopItem(pdoh))
  246.         return FALSE;     //This is not a desktop item. So, the immediate parent can't be desktop!
  247.     //We know that this is a desktop item. Check if the immediate parent is desktop
  248.     // or it is hosted too deep on desktop!
  249.     if(psp && SUCCEEDED(psp->QueryService(IID_ITargetFrame2, IID_ITargetFrame2, (void **)&ptgf)))
  250.     {
  251.         LPUNKNOWN pUnkParent;
  252.         //Get it's immediate parent.
  253.         if(SUCCEEDED(ptgf->GetParentFrame(&pUnkParent)))
  254.         {
  255.             if(pUnkParent)
  256.             {
  257.                 //Has a parent. So, the immediate parent can't be desktop!
  258.                 pUnkParent->Release();
  259.                 fImmediateParentIsDesktop = FALSE;
  260.             }
  261.             else
  262.                 fImmediateParentIsDesktop = TRUE; //No parent. Must be a desktop comp.
  263.         }
  264.         ptgf->Release();
  265.     }
  266.     return(fImmediateParentIsDesktop);
  267. }
  268. //Gets the current display name in wide char
  269. //
  270. // If fURL is TRUE, it returns file-URL with file: prefix.
  271. //
  272. HRESULT CDocObjectHost::_GetCurrentPageW(LPOLESTR * ppszDisplayName, BOOL fURL)
  273. {
  274.     HRESULT hres = E_FAIL;
  275.     ASSERT(_pmkCur);
  276.     *ppszDisplayName = NULL;
  277.     if (_pmkCur) {
  278.         IBindCtx* pbc;
  279.         hres = CreateBindCtx(0, &pbc);
  280.         if (SUCCEEDED(hres))
  281.         {
  282.             hres = _pmkCur->GetDisplayName(pbc, NULL, ppszDisplayName);
  283.             //
  284.             //  special handling just for file: urls.
  285.             //
  286.             if (SUCCEEDED(hres) && _fFileProtocol)
  287.             {
  288.                 ASSERT(*ppszDisplayName);
  289.                 WCHAR szText[MAX_URL_STRING];
  290.                 DWORD cchText = SIZECHARS(szText);
  291.                 if (!fURL)
  292.                 {
  293.                      hres = PathCreateFromUrlW(*ppszDisplayName, szText, &cchText, 0);
  294.                 }
  295.                 else
  296.                 {
  297.                     //  we need this to be in the normalized form of the URL
  298.                     //  for internal usage.  urlmon keeps them in the funny PATHURL style
  299.                     hres = UrlCanonicalizeW(*ppszDisplayName, szText, &cchText, 0);
  300.                 }
  301.                 if (SUCCEEDED(hres))
  302.                 {
  303.                     UINT cchDisplayName = lstrlenW(*ppszDisplayName);
  304.                     if (cchText > cchDisplayName)
  305.                     {
  306.                         //  need to resize
  307.                         CoTaskMemFree(*ppszDisplayName);
  308.                         *ppszDisplayName = (WCHAR *)CoTaskMemAlloc((cchText + 1) * SIZEOF(WCHAR));
  309.                         if (*ppszDisplayName)
  310.                         {
  311.                             //  go ahead and copy it in
  312.                             StrCpyNW(*ppszDisplayName, szText, cchText + 1);
  313.                         }
  314.                         else
  315.                             hres = E_OUTOFMEMORY;
  316.                     }
  317.                     else
  318.                     {
  319.                         StrCpyNW(*ppszDisplayName, szText, cchDisplayName + 1);
  320.                     }
  321.                 }
  322.                 else
  323.                     OleFree(*ppszDisplayName);
  324.             }
  325.             pbc->Release();
  326.         }
  327.     }
  328.     return hres;
  329. }
  330. HRESULT CDocObjectHost::_GetCurrentPage(LPTSTR szBuf, UINT cchMax, BOOL fURL)
  331. {
  332.     szBuf[0] = 0;   // zero out buffer
  333.     WCHAR *pszDisplayName;
  334.     HRESULT hres = _GetCurrentPageW(&pszDisplayName, fURL);
  335.     if (SUCCEEDED(hres))
  336.     {
  337.         StrCpyN(szBuf, pszDisplayName, cchMax);
  338.         OleFree(pszDisplayName);
  339.     }
  340.     return hres;
  341. }
  342. void CDocObjectHost_GetCurrentPage(LPARAM that, LPTSTR szBuf, UINT cchMax)
  343. {
  344.     CDocObjectHost* pdoh = (CDocObjectHost*)that;
  345.     pdoh->_GetCurrentPage(szBuf, cchMax);
  346. }
  347. //========================================================================
  348. // CDocObjectHost members
  349. //========================================================================
  350. CDocObjectHost::CDocObjectHost() : _cRef(1), _uState(SVUIA_DEACTIVATE)
  351. {
  352.     DllAddRef();
  353.     TraceMsg(TF_SHDLIFE, "ctor CDocObjectHost %x", this);
  354.     TraceMsg(DM_DEBUGTFRAME, "ctor CDocObjectHost %x, %x", this, &_bsc);
  355.     // Initialize proxy objects (which are contained)
  356.     _dof.Initialize(this);
  357.     _xao.Initialize(this);
  358. #ifdef HLINK_EXTRA
  359.     HRESULT hres = HlinkCreateBrowseContext(NULL, IID_IHlinkBrowseContext, (LPVOID*)&_pihlbc);
  360.     TraceMsg(0, "sdv TR CDOV::constructor HlinkCreateBrowseContext returned %x", hres);
  361. #endif // HLINK_EXTRA
  362.     _fPicsAccessAllowed = 1;     /* assume no ratings checks unless we download */
  363.     _fbPicsWaitFlags = 0;
  364.     ::_RefPicsQueries();    /* we'll free PICS async query list when last dochost is destroyed */
  365.     _pScriptErrList = NULL;
  366.     _fScriptErrDlgOpen = FALSE;
  367.     _strPriorityStatusText = NULL;
  368.     _iString = -1;
  369.     _uiCP = CP_ACP;
  370. }
  371. CDocObjectHost::~CDocObjectHost()
  372. {
  373.     ASSERT(_pole==NULL);    // to catch extra release.
  374.     ASSERT(_psp==NULL);     // to cache extra release.
  375.     ASSERT(_hwnd==NULL);
  376.     ASSERT(_pmsoc==NULL);
  377.     ASSERT(_pmsot==NULL);
  378.     ASSERT(_pmsov==NULL);
  379.     ASSERT(_pcmdMergedMenu==NULL);
  380.     if (_pScriptErrList != NULL)
  381.     {
  382.         _pScriptErrList->Release();
  383.     }
  384.     if (_strPriorityStatusText != NULL)
  385.     {
  386.         SysFreeString(_strPriorityStatusText);
  387.     }
  388. #ifdef HLINK_EXTRA
  389.     ASSERT(_phls == NULL);
  390.     ATOMICRELEASE(_pihlbc);
  391. #endif // HLINK_EXTRA
  392.     if (_pRatingDetails) {
  393.         ::RatingFreeDetails(_pRatingDetails);
  394.         _pRatingDetails = NULL;
  395.     }
  396.     if (_dwPicsSerialNumber) {
  397.         ::_RemovePicsQuery(_dwPicsSerialNumber);
  398.         _dwPicsSerialNumber = 0;
  399.     }
  400.     if (_hPicsQuery)
  401.     {
  402.         RatingObtainCancel(_hPicsQuery);
  403.         _hPicsQuery = NULL;
  404.     }
  405.     delete _pszPicsURL;     /* safe if already NULL */
  406.     _pszPicsURL = NULL;
  407.     ::_ReleasePicsQueries();
  408.     if (_pRootDownload != NULL) {
  409.         ASSERT(0);  /* need to destroy this earlier to prevent Trident problems */
  410.         ATOMICRELEASET(_pRootDownload,CPicsRootDownload);
  411.     }
  412.     if (_padvise) {
  413.         _padvise->OnClose();
  414.         ATOMICRELEASE(_padvise);
  415.     }
  416.     if (_pwszRefreshUrl)
  417.         OleFree(_pwszRefreshUrl);
  418.     if (_hmenuBrowser) {
  419.         AssertMsg(0, TEXT("_hmenuBrowser should be NULL!"));
  420.         DestroyMenu(_hmenuBrowser);
  421.     }
  422.     if (_hmenuFrame) {
  423.         DestroyMenu(_hmenuFrame);
  424.     }
  425.     if (_hacc)
  426.     {
  427.         DestroyAcceleratorTable(_hacc);
  428.         _hacc = NULL;
  429.     }
  430.     if (_hinstInetCpl)
  431.         FreeLibrary(_hinstInetCpl);
  432.     if (_ptbStd)
  433.         delete [] _ptbStd;
  434.     if (_pBrowsExt)
  435.     {
  436.         _pBrowsExt->Release();
  437.     }
  438.     // Make it sure that View Window is released (and _psb)
  439.     DestroyHostWindow();        // which will call _CloseMsoView and _UnBind
  440.     _ResetOwners();
  441.     TraceMsg(TF_SHDLIFE, "dtor CDocObjectHost %x", this);
  442.     DllRelease();
  443. }
  444. #ifdef DEBUG
  445. /*----------------------------------------------------------
  446. Purpose: Dump the menu handles for this docobj.  Optionally
  447.          breaks after dumping handles.
  448. Returns:
  449. Cond:    --
  450. */
  451. void
  452. CDocObjectHost::_DumpMenus(
  453.     IN LPCTSTR pszMsg,
  454.     IN BOOL    bBreak)
  455. {
  456.     if (IsFlagSet(g_dwDumpFlags, DF_DEBUGMENU))
  457.     {
  458.         ASSERT(pszMsg);
  459.         TraceMsg(TF_ALWAYS, "DocHost: Dumping menus for %#08x %s", (LPVOID)this, pszMsg);
  460.         TraceMsg(TF_ALWAYS, "   _hmenuBrowser = %x, _hmenuSet = %x, _hmenuFrame = %x",
  461.                  _hmenuBrowser, _hmenuSet, _hmenuFrame);
  462.         TraceMsg(TF_ALWAYS, "   _hmenuCur = %x, _hmenuMergedHelp = %x, _hmenuObjHelp = %x",
  463.                  _hmenuCur, _hmenuMergedHelp, _hmenuObjHelp);
  464.         _menulist.Dump(pszMsg);
  465.         if (bBreak && IsFlagSet(g_dwBreakFlags, BF_ONDUMPMENU))
  466.             DebugBreak();
  467.     }
  468. }
  469. #endif
  470. HRESULT CDocObjectHost::QueryInterface(REFIID riid, LPVOID * ppvObj)
  471. {
  472.     static const QITAB qit[] = {
  473.         QITABENT(CDocObjectHost, IOleInPlaceSite),
  474.         QITABENTMULTI(CDocObjectHost, IOleWindow, IOleInPlaceSite),
  475.         QITABENT(CDocObjectHost, IOleClientSite),
  476.         QITABENT(CDocObjectHost, IOleDocumentSite),
  477.         QITABENT(CDocObjectHost, IOleCommandTarget),
  478.         QITABENT(CDocObjectHost, IServiceProvider),
  479.         QITABENT(CDocObjectHost, IViewObject),
  480.         QITABENT(CDocObjectHost, IAdviseSink),
  481.         QITABENT(CDocObjectHost, IDocHostObject),
  482.         QITABENT(CDocObjectHost, IDocHostUIHandler),
  483.         QITABENT(CDocObjectHost, IDocHostShowUI),
  484.         QITABENT(CDocObjectHost, IDispatch),
  485.         QITABENT(CDocObjectHost, IPropertyNotifySink),
  486.         QITABENT(CDocObjectHost, IOleControlSite),
  487.         { 0 },
  488.     };
  489.     return QISearch(this, qit, riid, ppvObj);
  490. }
  491. void CDocObjectHost::_ResetOwners()
  492. {
  493.     _pszLocation = NULL;
  494.     _uiCP = CP_ACP;
  495.     _ReleasePendingObject();
  496.     ATOMICRELEASE(_psv);
  497.     ATOMICRELEASE(_pmsoctView);
  498.     ATOMICRELEASE(_pdvs);
  499.     ATOMICRELEASE(_psb);
  500.     ATOMICRELEASE(_pwb);
  501.     ATOMICRELEASE(_phf);
  502.     ATOMICRELEASE(_pocthf);
  503.     ATOMICRELEASE(_punkSFHistory);
  504.     ATOMICRELEASE(_pmsoctBrowser);
  505.     ATOMICRELEASE(_psp);
  506.     ATOMICRELEASE(_peds);
  507.     ATOMICRELEASE(_pedsHelper);
  508.     ATOMICRELEASE(_pWebOCUIHandler);
  509.     ATOMICRELEASE(_pWebOCShowUI);
  510.     // Release cached OleInPlaceUIWindow of the browser
  511.     ATOMICRELEASE(_pipu);
  512.     // Tell embedded CDocHostUIHandler object to release its references on us.
  513.     _dhUIHandler.SetSite(NULL);
  514. }
  515. ULONG CDocObjectHost::AddRef()
  516. {
  517.     _cRef++;
  518.     TraceMsg(TF_SHDREF, "CDocObjectHost(%x)::AddRef called, new _cRef=%d", this, _cRef);
  519.     return _cRef;
  520. }
  521. ULONG CDocObjectHost::Release()
  522. {
  523.     _cRef--;
  524.     TraceMsg(TF_SHDREF, "CDocObjectHost(%x)::Release called, new _cRef=%d", this, _cRef);
  525.     if (_cRef > 0)
  526.         return _cRef;
  527.     delete this;
  528.     return 0;
  529. }
  530. // cut & paste from browseuiitbar.cpp
  531. int RemoveHiddenButtons(TBBUTTON* ptbn, int iCount)
  532. {
  533.     int i;
  534.     int iTotal = 0;
  535.     TBBUTTON* ptbn1 = ptbn;
  536.     for (i = 0; i < iCount; i++, ptbn1++) {
  537.         if (!(ptbn1->fsState & TBSTATE_HIDDEN)) {
  538.             if (ptbn1 != ptbn) {
  539.                 *ptbn = *ptbn1;
  540.             }
  541.             ptbn++;
  542.             iTotal++;
  543.         }
  544.     }
  545.     return iTotal;
  546. }
  547. // We use two different image lists in the TBBUTTON array.  The bitmaps for browser-specific buttons
  548. // cut/copy/paste have been moved to shdocvw, and are therefore obtained from a second image list.
  549. // MAKELONG(0,1) accesses the first image from this second list.  Without a call to MAKELONG there is
  550. // a 0 in the upper integer, thereby referencing the first list by default.
  551. static const TBBUTTON c_tbStd[] = {
  552.     {10, DVIDM_SHOWTOOLS,       TBSTATE_ENABLED, BTNS_BUTTON, {0,0}, 0, 10},
  553.     {13, DVIDM_MAILNEWS,        TBSTATE_ENABLED, BTNS_WHOLEDROPDOWN, {0,0}, 0, 13 },
  554.     { 8, DVIDM_FONTS,           TBSTATE_ENABLED, BTNS_WHOLEDROPDOWN, {0,0}, 0, 8 },
  555.     { 7, DVIDM_PRINT,           TBSTATE_ENABLED, BTNS_BUTTON, {0,0}, 0, 7 },
  556.     { 9, DVIDM_EDITPAGE,        TBSTATE_ENABLED, BTNS_BUTTON, {0,0}, 0, 9 },
  557.     {15, DVIDM_DISCUSSIONS,     TBSTATE_ENABLED, BTNS_BUTTON, {0,0}, 0, 15 },
  558.     {MAKELONG(0,1), DVIDM_CUT,             TBSTATE_ENABLED, BTNS_BUTTON, {0,0}, 0, 0 },
  559.     {MAKELONG(1,1), DVIDM_COPY,            TBSTATE_ENABLED, BTNS_BUTTON, {0,0}, 0, 0 },
  560.     {MAKELONG(2,1), DVIDM_PASTE,           TBSTATE_ENABLED, BTNS_BUTTON, {0,0}, 0, 0 },
  561.     {MAKELONG(3,1), DVIDM_ENCODING,        TBSTATE_ENABLED, BTNS_WHOLEDROPDOWN, {0,0}, 0, 0 },
  562. };
  563. // c_tbStd and c_rest need to match exactly
  564. static const BROWSER_RESTRICTIONS c_rest[] = {
  565.     REST_BTN_TOOLS,
  566.     REST_BTN_MAIL,
  567.     REST_BTN_FONTS,
  568.     REST_BTN_PRINT,
  569.     REST_BTN_EDIT,
  570.     REST_BTN_DISCUSSIONS,
  571.     REST_BTN_CUT,
  572.     REST_BTN_COPY,
  573.     REST_BTN_PASTE,
  574.     REST_BTN_ENCODING,
  575. };
  576. #ifdef DEBUG
  577. void _AssertRestrictionOrderIsCorrect()
  578. {
  579.     COMPILETIME_ASSERT(ARRAYSIZE(c_tbStd) == ARRAYSIZE(c_rest));
  580.     for (UINT i = 0; i < ARRAYSIZE(c_tbStd); i++)
  581.     {
  582.         // If any of these rip, it means that c_rest and c_tbStd have
  583.         // gotten out of sync.  Need to fix up c_rest to match c_tbStd.
  584.         switch (c_tbStd[i].idCommand)
  585.         {
  586.             case DVIDM_SHOWTOOLS:       ASSERT(c_rest[i] == REST_BTN_TOOLS);        break;
  587.             case DVIDM_MAILNEWS:        ASSERT(c_rest[i] == REST_BTN_MAIL);         break;
  588.             case DVIDM_FONTS:           ASSERT(c_rest[i] == REST_BTN_FONTS);        break;
  589.             case DVIDM_PRINT:           ASSERT(c_rest[i] == REST_BTN_PRINT);        break;
  590.             case DVIDM_EDITPAGE:        ASSERT(c_rest[i] == REST_BTN_EDIT);         break;
  591.             case DVIDM_DISCUSSIONS:     ASSERT(c_rest[i] == REST_BTN_DISCUSSIONS);  break;
  592.             case DVIDM_CUT:             ASSERT(c_rest[i] == REST_BTN_CUT);          break;
  593.             case DVIDM_COPY:            ASSERT(c_rest[i] == REST_BTN_COPY);         break;
  594.             case DVIDM_PASTE:           ASSERT(c_rest[i] == REST_BTN_PASTE);        break;
  595.             case DVIDM_ENCODING:        ASSERT(c_rest[i] == REST_BTN_ENCODING);     break;
  596.             default:                    ASSERT(0);                                  break;
  597.         }
  598.     }
  599. }
  600. #endif
  601. BYTE _BtnStateFromRestIfAvailable(BOOL fAvailable, DWORD dwRest)
  602. {
  603.     if (fAvailable)
  604.         return SHBtnStateFromRestriction(dwRest, TBSTATE_ENABLED);
  605.     return TBSTATE_HIDDEN;
  606. }
  607. BOOL CDocObjectHost::_ToolsButtonAvailable()
  608. {
  609.     OLECMD rgcmd = { OLECMDID_HIDETOOLBARS, 0 };
  610.     if (_pmsoctBrowser)
  611.         _pmsoctBrowser->QueryStatus(NULL, 1, &rgcmd, NULL);
  612.     return (rgcmd.cmdf & OLECMDF_SUPPORTED);
  613. }
  614. __inline BYTE CDocObjectHost::_DefToolsButtonState(DWORD dwRest)
  615. {
  616.     BOOL fAvailable = _ToolsButtonAvailable();
  617.     return _BtnStateFromRestIfAvailable(fAvailable, dwRest);
  618. }
  619. static const TCHAR c_szRegKeyCoolbar[] = TEXT("Software\Microsoft\Internet Explorer\Toolbar");
  620. BYTE CDocObjectHost::_DefFontsButtonState(DWORD dwRest)
  621. {
  622.     BYTE fsState = TBSTATE_ENABLED;
  623.     // default to whatever the IE4 reg key specifies,
  624.     // or FALSE if reg key not present (clean install)
  625.     if (!SHRegGetBoolUSValue(c_szRegKeyCoolbar, TEXT("ShowFonts"), FALSE, FALSE))
  626.         fsState |= TBSTATE_HIDDEN;
  627.     return SHBtnStateFromRestriction(dwRest, fsState);
  628. }
  629. DWORD CDocObjectHost::_DiscussionsButtonCmdf()
  630. {
  631.     if (SHRegGetBoolUSValue(c_szRegKeyCoolbar,
  632.                                 TEXT("ShowDiscussionButton"), FALSE, TRUE) &&
  633.        _pmsoctBrowser) {
  634.         OLECMD rgcmds[] = {
  635.             { SBCMDID_DISCUSSIONBAND, 0 },
  636.         };
  637.         static const int buttonsInternal[] = {
  638.             DVIDM_DISCUSSIONS,
  639.         };
  640.         _pmsoctBrowser->QueryStatus(&CGID_Explorer, ARRAYSIZE(rgcmds), rgcmds, NULL);
  641.         return rgcmds[0].cmdf;
  642.     }
  643.     return 0;
  644. }
  645. __inline BOOL CDocObjectHost::_DiscussionsButtonAvailable()
  646. {
  647.     return (_DiscussionsButtonCmdf() & OLECMDF_SUPPORTED);
  648. }
  649. __inline BYTE CDocObjectHost::_DefDiscussionsButtonState(DWORD dwRest)
  650. {
  651.     BOOL fAvailable = _DiscussionsButtonAvailable();
  652.     return _BtnStateFromRestIfAvailable(fAvailable, dwRest);
  653. }
  654. BOOL CDocObjectHost::_MailButtonAvailable()
  655. {
  656.     OLECMD rgcmdMailFavs[] = { { SBCMDID_DOMAILMENU, 0} };
  657.     if (_pmsoctBrowser)
  658.         _pmsoctBrowser->QueryStatus(&CGID_Explorer, ARRAYSIZE(rgcmdMailFavs), rgcmdMailFavs, NULL);
  659.     if (rgcmdMailFavs[0].cmdf & OLECMDF_ENABLED)
  660.         return TRUE;
  661.     return FALSE;
  662. }
  663. __inline BYTE CDocObjectHost::_DefMailButtonState(DWORD dwRest)
  664. {
  665.     BOOL fAvailable = _MailButtonAvailable();
  666.     return _BtnStateFromRestIfAvailable(fAvailable, dwRest);
  667. }
  668. // We default the edit button to visible if there is an html editer registered
  669. BOOL CDocObjectHost::_EditButtonAvailable()
  670. {
  671.     BOOL fRet = FALSE;
  672.     HKEY hkey = NULL;
  673.     if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CLASSES_ROOT, TEXT(".htm\shell\edit\command"), 0, KEY_READ, &hkey) ||
  674.         ERROR_SUCCESS == RegOpenKeyEx(HKEY_CLASSES_ROOT, TEXT("htmlfile\shell\edit\command"), 0, KEY_READ, &hkey))
  675.     {
  676.         RegCloseKey(hkey);
  677.         fRet = TRUE;
  678.     }
  679.     return fRet;
  680. }
  681. __inline BYTE CDocObjectHost::_DefEditButtonState(DWORD dwRest)
  682. {
  683.     BYTE fsState;
  684.     if (_EditButtonAvailable())
  685.         fsState = TBSTATE_ENABLED;
  686.     else
  687.         fsState = TBSTATE_HIDDEN;
  688.     return SHBtnStateFromRestriction(dwRest, fsState);
  689. }
  690. void CDocObjectHost::_MarkDefaultButtons(PTBBUTTON tbStd)
  691. {
  692.     // We're assuming tbStd is the same size as c_tbStd
  693. #ifdef DEBUG
  694.     _AssertRestrictionOrderIsCorrect();
  695. #endif
  696.     DWORD dwRest[ARRAYSIZE(c_tbStd)];
  697.     BOOL fCheckRestriction = SHRestricted2(REST_SPECIFYDEFAULTBUTTONS, NULL, 0);
  698.     for (UINT i = 0; i < ARRAYSIZE(c_rest); i++) {
  699.         if (fCheckRestriction)
  700.             dwRest[i] = SHRestricted2(c_rest[i], NULL, 0);
  701.         else
  702.             dwRest[i] = RESTOPT_BTN_STATE_DEFAULT;
  703.     }
  704.     // We want the Cut, Copy, Paste buttons to default off of the toolbar
  705.     // (but available in the view-toolbars-customize dialog)
  706.     // We set the state of the buttons to TBSTATE_HIDDEN here, but leave them alone
  707.     // in ETCMDID_GETBUTTONS so that they appear in the customize dialog.
  708.     ASSERT(tbStd[6].idCommand == DVIDM_CUT);
  709.     ASSERT(tbStd[7].idCommand == DVIDM_COPY);
  710.     ASSERT(tbStd[8].idCommand == DVIDM_PASTE);
  711.     ASSERT(tbStd[9].idCommand == DVIDM_ENCODING);
  712.     for (i = 6; i <= 9; i++)
  713.         tbStd[i].fsState = SHBtnStateFromRestriction(dwRest[i], tbStd[i].fsState | TBSTATE_HIDDEN);
  714.     ASSERT(tbStd[0].idCommand == DVIDM_SHOWTOOLS);
  715.     tbStd[0].fsState = _DefToolsButtonState(dwRest[0]);
  716.     ASSERT(tbStd[1].idCommand == DVIDM_MAILNEWS);
  717.     tbStd[1].fsState = _DefMailButtonState(dwRest[1]);
  718.     ASSERT(tbStd[2].idCommand == DVIDM_FONTS);
  719.     tbStd[2].fsState = _DefFontsButtonState(dwRest[2]);
  720.     ASSERT(tbStd[3].idCommand == DVIDM_PRINT);
  721.     tbStd[3].fsState = SHBtnStateFromRestriction(dwRest[3], TBSTATE_ENABLED);
  722.     ASSERT(tbStd[4].idCommand == DVIDM_EDITPAGE);
  723.     tbStd[4].fsState = _DefEditButtonState(dwRest[4]);
  724.     ASSERT(tbStd[5].idCommand == DVIDM_DISCUSSIONS);
  725.     tbStd[5].fsState = _DefDiscussionsButtonState(dwRest[5]);
  726. }
  727. const GUID* CDocObjectHost::_GetButtonCommandGroup()
  728. {
  729.     if (_ToolsButtonAvailable())
  730.         return &CLSID_MSOButtons;
  731.     else
  732.         return &CLSID_InternetButtons;
  733. }
  734. void CDocObjectHost::_AddButtons(BOOL fForceReload)
  735. {
  736.     if (!_pBrowsExt)
  737.         return;
  738.     IExplorerToolbar* pxtb;
  739.     if (_psp && SUCCEEDED(_psp->QueryService(SID_SExplorerToolbar, IID_IExplorerToolbar, (LPVOID*)&pxtb)))
  740.     {
  741.         const GUID* pguid = _GetButtonCommandGroup();
  742.         HRESULT hr = pxtb->SetCommandTarget((IOleCommandTarget*)this, pguid,
  743.                         VBF_TOOLS | VBF_ADDRESS | VBF_LINKS | VBF_BRAND);
  744.         if (!fForceReload && hr == S_FALSE) {
  745.             // Another dochost already merged the buttons into the toolbar under the
  746.             // same command group, so don't bother re-merging.  We just need to initialize
  747.             // _iString, since we're skipping the call to _pBrowsExt->InitButtons below.
  748.             VARIANT var = { VT_I4 };
  749.             IUnknown_Exec(_pBrowsExt, &CLSID_PrivBrowsExtCommands, PBEC_GETSTRINGINDEX, 0, &var, NULL);   // should always succeed
  750.             _iString = var.lVal;
  751.         } else {
  752.             UINT nNumExtButtons = 0;
  753.             _pBrowsExt->GetNumButtons(&nNumExtButtons);
  754.             int nNumButtons = nNumExtButtons + ARRAYSIZE(c_tbStd);
  755.             // GetTBArray insures that tbStd != NULL, so we don't need that check here
  756.             TBBUTTON    *tbStd = new TBBUTTON[nNumButtons];
  757.             if (tbStd != NULL)
  758.             {
  759.                 memcpy(tbStd, c_tbStd, SIZEOF(TBBUTTON) * ARRAYSIZE(c_tbStd));
  760.                 UINT iStringIndex = (UINT)-1;  // result of adding the string buffer to the toolbar string list
  761.                 HRESULT hr = _pBrowsExt->InitButtons(pxtb, &iStringIndex, pguid);
  762.                 ASSERT(tbStd[6].idCommand == DVIDM_CUT);
  763.                 ASSERT(tbStd[7].idCommand == DVIDM_COPY);
  764.                 ASSERT(tbStd[8].idCommand == DVIDM_PASTE);
  765.                 ASSERT(tbStd[9].idCommand == DVIDM_ENCODING);
  766.                 if (SUCCEEDED(hr) && iStringIndex != -1)
  767.                 {
  768.                     tbStd[6].iString = iStringIndex;
  769.                     tbStd[7].iString = iStringIndex + 1;
  770.                     tbStd[8].iString = iStringIndex + 2;
  771.                     tbStd[9].iString = iStringIndex + 3;
  772.                     _iString = (int)iStringIndex;
  773.                 }
  774.                 else
  775.                 {
  776.                     tbStd[6].iString = tbStd[7].iString = tbStd[8].iString = tbStd[9].iString = -1;
  777.                     _iString = -1;
  778.                 }
  779.                 // Add custom buttons to the toolbar array.  We pass in the nNumButtons
  780.                 // as a *sanity check*...
  781.                 _pBrowsExt->GetButtons(&tbStd[ARRAYSIZE(c_tbStd)], nNumExtButtons, TRUE);
  782.                 _MarkDefaultButtons(tbStd);
  783.                 nNumButtons = RemoveHiddenButtons(tbStd, nNumButtons);
  784.                 pxtb->AddButtons(pguid, nNumButtons, tbStd);
  785.                 delete [] tbStd;
  786.             }
  787.         }
  788.         pxtb->Release();
  789.     }
  790. }
  791. HRESULT CDocObjectHost::UIActivate(UINT uState, BOOL fPrevViewIsDocView)
  792. {
  793.     TraceMsg(TF_SHDUIACTIVATE, "DOH::UIActivate called %d->%d (this=%x)",
  794.              _uState, uState, this);
  795.     HRESULT hres = S_OK;
  796.     UINT uStatePrev = _uState;
  797.     // We are supposed to update the menu
  798.     if (uState != _uState)
  799.     {
  800.         // There was a state transition.
  801.         //
  802.         _uState = uState;
  803.         // If the new state is SVUIA_DEACTIVATE
  804.         //
  805.         if (_uState == SVUIA_DEACTIVATE)
  806.         {
  807.             //
  808.             //  When we are deactivating (we are navigating away)
  809.             // we UIDeactivate the current MsoView.
  810.             //
  811.             _UIDeactivateMsoView();
  812.             _IPDeactivateMsoView(_pmsov);
  813.             _DestroyBrowserMenu();
  814.         }
  815.         else if (_uState == SVUIA_INPLACEACTIVATE && uStatePrev == SVUIA_ACTIVATE_FOCUS)
  816.         {
  817.             // Transition from SVUIA_ACTIVATE_FOCUS->SVUIA_INPLACEACTIVATE
  818.             //
  819.             // BUGBUG: If we set this DONT_UIDEACTIVATE, then we stop calling
  820.             //  UIActivate(FALSE) when a DocObject in a frameset looses a focus.
  821.             //  It will solve some problems with Office apps (Excel, PPT), which
  822.             //  InPlaceDeactivate when we call UIActivate(FALSE). We want to treat
  823.             //  it as a bug, but unfortunately DocObject spec says that's OK.
  824.             //
  825.             //   Putting this work around, however, slightly confuses MSHTML
  826.             //  (both classic and Trident). Once it's UIActivated, it keep
  827.             //  thinking that it's UIActivated and never calls onUIActivate.
  828.             //  Until we figure out what's the right implementation,
  829.             //  we can't turn this on.             (SatoNa -- 11/04/96).
  830.             //
  831.             _GetAppHack(); // get if we don't have it yet.
  832.             if (_dwAppHack & BROWSERFLAG_DONTUIDEACTIVATE) {
  833.                 //
  834.                 // HACK: We are supposed to just call UIActivate(FALSE) when
  835.                 //  another DocObject (in the case of a frame set) became
  836.                 //  UIActivated. Excel/PPT, however, InplaceDeactivate instead.
  837.                 //  To work around, SriniK suggested us to call
  838.                 //  OnDocWindowActivate(FALSE). (SatoNa)
  839.                 //
  840.                 IOleInPlaceActiveObject* piact = _xao.GetObject(); // no AddRef
  841.                 TraceMsg(TF_SHDAPPHACK, "DOH::UIActivate APPHACK calling %x->OnDocWindowActivate (this=%x)",
  842.                          piact, this);
  843.                 if (piact)
  844.                 {
  845.                     piact->OnDocWindowActivate(FALSE);
  846.                 }
  847.             }
  848.             else if (!(_dwAppHack & BROWSERFLAG_DONTDEACTIVATEMSOVIEW))
  849.             {
  850.                 // HACK: In Excel, if we deactiveate the view, it never gets focus again
  851.                 // fix for the bug from hell: #20906
  852.                 _UIDeactivateMsoView();
  853.             }
  854.             else
  855.             {
  856.                 // We're transitioning from SVUIA_ACTIVATE_FOCUS->SVUIA_INPLACEACTIVATE
  857.                 // and BROWSERFLAG_DONTDEACTIVATEMSOVIEW is set.
  858.                 // call the object's IOleInPlactActiveObject::OnFrameWindowActivate(FALSE);
  859.                 IOleInPlaceActiveObject* piact = _xao.GetObject(); // no AddRef
  860.                 if (piact)
  861.                 {
  862.                     piact->OnFrameWindowActivate(FALSE);
  863.                 }
  864.             }
  865.         }
  866.         else if (uStatePrev == SVUIA_DEACTIVATE)
  867.         {
  868.             //
  869.             //  If UIActivate is called either
  870.             // (1) when the binding is pending; _bsc._pbc!=NULL
  871.             // (2) when the async binding is done; _bsc._pole!=NULL
  872.             //
  873.             SHVMSG("UIActivate about to call _Bind", _bsc._pbc, NULL);
  874.             if (_pole == NULL && _bsc._pbc)
  875.             {
  876.                 ASSERT(_pmkCur);
  877.                 IBindCtx* pbc = _bsc._pbc;
  878.                 pbc->AddRef();
  879.                 HRESULT hresT = _BindSync(_pmkCur, _bsc._pbc, _bsc._psvPrev);
  880.                 pbc->Release();
  881.                 ASSERT(_bsc._pbc==NULL);
  882.                 ASSERT(_bsc._psvPrev==NULL);
  883.                 ASSERT(_bsc._pbscChained==NULL);
  884.             }
  885.             hres = _EnsureActivateMsoView();
  886.             _AddButtons(FALSE);
  887.         } else {
  888.             // opening a new document for 1st time (to UIActive or IPActive)
  889.             goto GoSetFocus;
  890.         }
  891.     }
  892.     else
  893.     {
  894.         TraceMsg(TF_SHDUIACTIVATE, "DOH:::UIActivate -- same uState (%x)", _uState);
  895. GoSetFocus:
  896.         if ((_uState == SVUIA_ACTIVATE_FOCUS)) {
  897.             // see if object is already UIActive.
  898.             if (_ActiveHwnd()) {
  899.                 // if it is, we have an hwnd and all we need to do
  900.                 // is SetFocus (for compatibility w/ weird guys...)
  901.                 if ( IsChildOrSelf( _ActiveHwnd(), GetFocus() ) != S_OK )
  902.                 {
  903.                     TraceMsg(TF_SHDUIACTIVATE, "DOH:::UIActivate -- calling SetFocus(%x)", _ActiveHwnd());
  904.                     SetFocus(_ActiveHwnd());
  905.                 }
  906.             }
  907.             else {
  908.                 // we're in the OC, and it's IPActive not UIActive.
  909.                 // (either that or it's the very 1st time for the main view).
  910.                 // NOTE: Due to CBaseBrowser code that defers SVUIA_ACTIVATE_FOCUS until
  911.                 // application is active, we can have a top level docobject go
  912.                 // SVUIA_INPLACEACTIVE and then on activation of the window,
  913.                 // we transition to SVUIA_ACTIVATE_FOCUS, thus never UIActivating
  914.                 // the docobject (cf: BUG 62138)
  915.                 hres = _DoVerbHelper(FALSE);
  916.             }
  917.         }
  918.     }
  919.     if ((_uState == SVUIA_INPLACEACTIVATE) || (_uState  == SVUIA_ACTIVATE_FOCUS))
  920.         _PlaceProgressBar();
  921.     return hres;
  922. }
  923. //***   _DoVerbHelper -- DoVerb w/ various hacks
  924. // NOTES
  925. //  BUGBUG do comments in _OnSetFocus apply here?
  926. HRESULT CDocObjectHost::_DoVerbHelper(BOOL fOC)
  927. {
  928.     HRESULT hres = E_FAIL;
  929.     LONG iVerb = OLEIVERB_SHOW;
  930.     MSG msg;
  931.     LPMSG pmsg = NULL;
  932.     if (_uState == SVUIA_INPLACEACTIVATE) {
  933.         iVerb = OLEIVERB_INPLACEACTIVATE;
  934.     }
  935.     else if ((_uState == SVUIA_ACTIVATE_FOCUS)) {
  936.         iVerb = OLEIVERB_UIACTIVATE;
  937.     }
  938.     else {
  939.         TraceMsg(TF_ERROR, "DOC::_DoVerbHelper untested (and probably the wrong iVerb mapping)");
  940.     }
  941.     if (_pedsHelper)
  942.     {
  943.         if (SUCCEEDED(_pedsHelper->GetDoVerbMSG(&msg)))
  944.         {
  945.             pmsg = &msg;
  946.         }
  947.     }
  948.     hres = _pole->DoVerb(iVerb, pmsg, this, (UINT)-1, _hwnd, &_rcView);
  949.     if (hres == OLEOBJ_E_INVALIDVERB && iVerb == OLEIVERB_INPLACEACTIVATE) {
  950.         hres = _pole->DoVerb(OLEIVERB_SHOW, pmsg, this, (UINT)-1, _hwnd, &_rcView);
  951.     }
  952.     if (FAILED(hres)) {
  953.         TraceMsg(DM_ERROR, "DOC::_DoVerbHelper _pole->DoVerb ##FAILED## %x", hres);
  954.     }
  955.     return hres;
  956. }
  957. class CDocObjAssoc : public IUnknown
  958. {
  959. public:
  960.     // *** IUnknown methods ***
  961.     virtual STDMETHODIMP QueryInterface(REFIID riid, LPVOID * ppvObj);
  962.     virtual STDMETHODIMP_(ULONG) AddRef(void) ;
  963.     virtual STDMETHODIMP_(ULONG) Release(void);
  964.     CDocObjAssoc(DWORD dwDOCHF) : _dwDOCHF(dwDOCHF), _cRef(1) {
  965.         TraceMsg(TF_SHDLIFE, "ctor CDocObjAssoc(%x) being constructed", this);
  966.     }
  967.     DWORD GetDOCHF(void) { return _dwDOCHF; }
  968. protected:
  969.     ~CDocObjAssoc() {
  970.         TraceMsg(TF_SHDLIFE, "dtor CDocObjAssoc(%x) being destroyed", this);
  971.     }
  972.     UINT    _cRef;
  973.     DWORD   _dwDOCHF;
  974. };
  975. HRESULT CDocObjAssoc::QueryInterface(REFIID riid, LPVOID * ppvObj)
  976. {
  977.     if (IsEqualIID(riid, IID_IUnknown))
  978.     {
  979.         *ppvObj = SAFECAST(this, IUnknown*);
  980.     }
  981.     else
  982.     {
  983.         *ppvObj = NULL;
  984.         return E_NOINTERFACE;
  985.     }
  986.     AddRef();
  987.     return NOERROR;
  988. }
  989. ULONG CDocObjAssoc::AddRef()
  990. {
  991.     _cRef++;
  992.     TraceMsg(TF_SHDREF, "CDocObjAssoc(%x)::AddRef called, new _cRef=%d", this, _cRef);
  993.     return _cRef;
  994. }
  995. ULONG CDocObjAssoc::Release()
  996. {
  997.     _cRef--;
  998.     TraceMsg(TF_SHDREF, "CDocObjAssoc(%x)::Release called, new _cRef=%d", this, _cRef);
  999.     if (_cRef > 0)
  1000.         return _cRef;
  1001.     delete this;
  1002.     return 0;
  1003. }
  1004. void CDocObjectHost::_IPDeactivateMsoView(IOleDocumentView* pmsov)
  1005. {
  1006.     TraceMsg(TF_SHDUIACTIVATE, "DOH::_IPDeactivateMsoView called (this==%x)", this);
  1007.     if (pmsov)
  1008.     {
  1009.         IOleInPlaceObject* pipo = NULL;
  1010.         HRESULT hresT = _pole->QueryInterface(IID_IOleInPlaceObject, (LPVOID*)&pipo);
  1011.         if (SUCCEEDED(hresT))
  1012.         {
  1013.             pipo->InPlaceDeactivate();
  1014.             pipo->Release();
  1015.         }
  1016.         pmsov->Show(FALSE);
  1017.     }
  1018. }
  1019. void CDocObjectHost::_UIDeactivateMsoView(void)
  1020. {
  1021.     TraceMsg(TF_SHDUIACTIVATE, "DOH::_UIDeactivateMsoView called (this==%x)", this);
  1022.     if (_pmsov)
  1023.     {
  1024.         _pmsov->UIActivate(FALSE);
  1025.     }
  1026. }
  1027. //
  1028. // Hide the office toolbar
  1029. //
  1030. void CDocObjectHost::_HideOfficeToolbars(void)
  1031. {
  1032.     if (_pmsot) {
  1033.         OLECMD rgcmd = { OLECMDID_HIDETOOLBARS, 0 };
  1034.         _pmsot->QueryStatus(NULL, 1, &rgcmd, NULL);
  1035.         // LATCHED means hidden
  1036.         rgcmd.cmdf &= (OLECMDF_SUPPORTED | OLECMDF_LATCHED);
  1037.         // If it's supported and visible (not LATCHED), toggle it.
  1038.         if (rgcmd.cmdf == OLECMDF_SUPPORTED) {
  1039.             _pmsot->Exec(NULL, OLECMDID_HIDETOOLBARS, OLECMDEXECOPT_DONTPROMPTUSER, NULL, NULL);
  1040.         }
  1041.     }
  1042. }
  1043. void CDocObjectHost::_ShowMsoView(void)
  1044. {
  1045.     HRESULT hres;
  1046.     //
  1047.     // HACK: Word97 UIDeactivate when we call SetInPlaceSite even with the
  1048.     //  same in-place site.
  1049.     //
  1050.     IOleInPlaceSite* psite;
  1051.     hres = _pmsov->GetInPlaceSite(&psite);
  1052.     if (SUCCEEDED(hres) && psite) {
  1053.         if (psite!=this) {
  1054.             _pmsov->SetInPlaceSite(this);
  1055.         } else {
  1056.             TraceMsg(TF_SHDAPPHACK, "DOH::_ShowMsoView not calling SetInPlaceSite because it's already set");
  1057.         }
  1058.         psite->Release();
  1059.     } else {
  1060.         _pmsov->SetInPlaceSite(this);
  1061.     }
  1062.     GetClientRect(_hwnd, &_rcView);
  1063.     ASSERT(_uState != SVUIA_DEACTIVATE);
  1064.     if (_uState != SVUIA_INPLACEACTIVATE       // Do this if we're not already SVUIA_INPLACEACTIVE
  1065.         || !(_dwAppHack & BROWSERFLAG_MSHTML)  //   or if it's not Trident (office apps expect this call)
  1066.         )
  1067.     {
  1068.         // Trident is sending progress changed messages here -- and causing Compuserve a problem.
  1069.         // Flag the fact that we're UIActivating them, and suppress forwarding ProgressChanged
  1070.         // messages to our container when this flag is true.  (IE v4.1 bug 54787)
  1071.         //
  1072.         _fUIActivatingView = TRUE;
  1073.         _pmsov->UIActivate(TRUE);
  1074.         _fUIActivatingView = FALSE;
  1075.     }
  1076.     //
  1077.     // HACK:
  1078.     //
  1079.     //  We call _HideOfficeToolbars when our OnUIActivate is called.
  1080.     // SriniK suggested us to do it in order to avoid flashing.
  1081.     // It works well with Excel (3404), but does not work with Word.
  1082.     // Word does not hide its toolbars correctly. To work around that
  1083.     // bug, we call _HideofficeToolbars here again.
  1084.     //
  1085.     _HideOfficeToolbars();
  1086.     hres = _pmsov->SetRect(&_rcView);
  1087.     if (FAILED(hres)) {
  1088.         TraceMsg(DM_ERROR, "DOC::_ShowMsoView _pmsov->SetRect ##FAILED## %x", hres);
  1089.     }
  1090.     if (FAILED(hres) && _uState == SVUIA_INPLACEACTIVATE) {
  1091.         TraceMsg(TF_SHDAPPHACK, "APPHACK# DOH::_ShowMsoView calling UIActivate");
  1092.         // HACKHACK: for word.  they refuse to show if they aren't UIActivated.
  1093.         // if the setrect fails, and we didn't do a UIActivate, do it now.
  1094.         _fDontInplaceActivate = TRUE;
  1095.         TraceMsg(TF_SHDAPPHACK, "HACK: CDOH::_ShowMsoView calling UIActive(TRUE) to work around Word bug");
  1096.         _pmsov->UIActivate(TRUE);
  1097.         _pmsov->SetRect(&_rcView);
  1098.     }
  1099.     // This is the other case where Trident sends Progress changed messages.
  1100.     //
  1101.     _fUIActivatingView = TRUE;
  1102.     hres = _pmsov->Show(TRUE);
  1103.     _fUIActivatingView = FALSE;
  1104.     if (FAILED(hres)) {
  1105.         TraceMsg(DM_ERROR, "DOH::_ShowMsoView _pmsov->Show ##FAILED## %x", hres);
  1106.     }
  1107.     _fDrawBackground = FALSE;   /* now that we've shown the object, no need to paint our own background */
  1108. }
  1109. HRESULT CDocObjectHost::_ActivateMsoView()
  1110. {
  1111.     _EnableModeless(FALSE);
  1112. #ifdef DEBUG
  1113.     PERFMSG(TEXT("_ActivateMsoView"), GetCurrentTime() - g_dwPerf);
  1114.     g_dwPerf = GetCurrentTime();
  1115. #endif
  1116.     HRESULT hres = NOERROR;
  1117.     if (!_phls) {
  1118.         _pole->QueryInterface(IID_IHlinkSource, (LPVOID*)&_phls);
  1119.     }
  1120.     if (_phls && !_fIsHistoricalObject) {
  1121. //
  1122. // Special test case for IHlinkFrame marshaling.
  1123. //
  1124.         hres = _phls->Navigate(0, _pszLocation);
  1125.         //
  1126.         // If this is one of our internal error pages, we can ignore the
  1127.         // failure on the bogus location.  In this case pwszLocation will
  1128.         // be the original url that failed preceeded with a '#'.
  1129.         //
  1130.         LPOLESTR pwszUrl;
  1131.         if (FAILED(hres) && SUCCEEDED(_GetCurrentPageW(&pwszUrl, TRUE)))
  1132.         {
  1133.             // if it begins with res: it may be our erro page
  1134.             if (pwszUrl[0] == L'r' && pwszUrl[1] == L'e' && IsErrorUrl(pwszUrl))
  1135.             {
  1136.                 // It's our internal error page, so ignore the error
  1137.                 hres = S_OK;
  1138.             }
  1139.             OleFree(pwszUrl);
  1140.         }
  1141.         if (FAILED(hres)) {
  1142.             TraceMsg(DM_ERROR, "DOC::_ActivateMsoView _phls->Navigate(%s) ##FAILED## %x",
  1143.                      _pszLocation ? _pszLocation : TEXT(""), hres);
  1144.         }
  1145.     } else {
  1146.         // BUGBUG todo: use _DoVerbHelper? (but careful! ACT_FOCUS different)
  1147.         LONG iVerb = OLEIVERB_SHOW;
  1148.         MSG msg;
  1149.         LPMSG pmsg = NULL;
  1150.         if (_uState == SVUIA_INPLACEACTIVATE) {
  1151.             iVerb = OLEIVERB_INPLACEACTIVATE;
  1152.         }
  1153.         if (_pedsHelper)
  1154.         {
  1155.             if (SUCCEEDED(_pedsHelper->GetDoVerbMSG(&msg)))
  1156.             {
  1157.                 pmsg = &msg;
  1158.             }
  1159.         }
  1160.         hres = _pole->DoVerb(iVerb, pmsg, this, (UINT)-1, _hwnd, &_rcView);
  1161.         if (hres == OLEOBJ_E_INVALIDVERB && iVerb == OLEIVERB_INPLACEACTIVATE)
  1162.             hres = _pole->DoVerb(OLEIVERB_SHOW, pmsg, this, (UINT)-1, _hwnd, &_rcView);
  1163.         if (FAILED(hres)) {
  1164.             TraceMsg(DM_ERROR, "DOC::_ActivateMsoView _pole->DoVerb ##FAILED## %x", hres);
  1165.         }
  1166.     }
  1167.     // the doc is activated
  1168.     if (SUCCEEDED(hres)) {
  1169.         _ReleasePendingObject();
  1170.         if (_fHaveParentSite) {
  1171.             _HideOfficeToolbars();
  1172.         }
  1173.     }
  1174.     _EnableModeless(TRUE);
  1175.     return hres;
  1176. }
  1177. HRESULT CDocObjectHost::_EnsureActivateMsoView()
  1178. {
  1179.     HRESULT hres = E_FAIL;
  1180.     // if we've got an ole object and
  1181.     // either we don't have a view, or we don't have an active view..
  1182.     // do the activation
  1183.     if (_pole)
  1184.     {
  1185.         if (!_pmsov || !_ActiveObject()) {
  1186.             hres = _ActivateMsoView();
  1187.             // Note that we should not UIActivate it here. We should wait
  1188.             // until the DocObject calls our ActivateMe
  1189.             // _ShowMsoView();
  1190.         }
  1191.     }
  1192.     return hres;
  1193. }
  1194. //
  1195. // This member closes the MsoView window and releases interface
  1196. // pointers. This is essentially the reverse of _CreateMsoView.
  1197. //
  1198. void CDocObjectHost::_CloseMsoView(void)
  1199. {
  1200.     ATOMICRELEASE(_pmsot);
  1201.     if (_pmsov)
  1202.     {
  1203.         VIEWMSG(TEXT("_CloseMsoView calling pmsov->UIActivate(FALSE)"));
  1204.         IOleDocumentView* pmsov = _pmsov;
  1205.         _pmsov = NULL;
  1206.         _fDontInplaceActivate = FALSE;
  1207. #ifdef DONT_UIDEACTIVATE
  1208.         if (_uState != SVUIA_DEACTIVATE)
  1209.             pmsov->UIActivate(FALSE);
  1210. #else // DONT_UIDEACTIVATE
  1211.         if (_uState == SVUIA_ACTIVATE_FOCUS)
  1212.             pmsov->UIActivate(FALSE);
  1213. #endif // DONT_UIDEACTIVATE
  1214.         _IPDeactivateMsoView(pmsov);
  1215.         pmsov->CloseView(0);
  1216.         pmsov->SetInPlaceSite(NULL);
  1217.         pmsov->Release();
  1218.         VIEWMSG(TEXT("_CloseMsoView called pmsov->Release()"));
  1219.     }
  1220.     ATOMICRELEASE(_pmsoc);
  1221. }
  1222. void CDocObjectHost::_OnPaint(HDC hdc)
  1223. {
  1224.     if (_pmsov && !_ActiveObject())
  1225.     {
  1226.         HRESULT hres;
  1227.         RECT rcClient;
  1228.         GetClientRect(_hwnd, &rcClient);
  1229.         hres = OleDraw(_pmsov, DVASPECT_CONTENT, hdc, &rcClient);
  1230.         TraceMsg(0, "shd TR ::_OnPaint OleDraw returns %x", hres);
  1231.     }
  1232. }
  1233. HRESULT _GetDefaultLocation(LPWSTR pszPath, DWORD cchPathSizeIn, UINT id)
  1234. {
  1235.     WCHAR szPath[MAX_URL_STRING];
  1236.     DWORD cbSize = SIZEOF(szPath);
  1237.     DWORD cchPathSize = cchPathSizeIn;
  1238.     HRESULT hres = E_FAIL;
  1239.     HKEY hkey;
  1240.     // BUGBUG: Share this code!!!
  1241.     // BUGBUG: This is Internet Explorer Specific
  1242.     HKEY hkeyroot = id == IDP_CHANNELGUIDE ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE;
  1243.     if (RegOpenKeyW(hkeyroot,
  1244.             L"Software\Microsoft\Internet Explorer\Main",
  1245.             &hkey)==ERROR_SUCCESS)
  1246.     {
  1247.         DWORD dwType;
  1248.         LPCWSTR pszName;
  1249.         switch(id) {
  1250.         default:
  1251.             ASSERT(0);
  1252.         case DVIDM_GOHOME:
  1253.             pszName = L"Default_Page_URL";
  1254.             break;
  1255.         case DVIDM_GOSEARCH:
  1256.             pszName = L"Default_Search_URL";
  1257.             break;
  1258.         case IDP_UPDATE:
  1259.             pszName = L"Default_Update_URL";
  1260.             break;
  1261.         case IDP_CHANNELGUIDE:
  1262.             pszName = L"ChannelsURL";
  1263.             break;
  1264.         }
  1265.         if (RegQueryValueExW(hkey, pszName,
  1266.             0, &dwType, (LPBYTE)szPath, &cbSize)==ERROR_SUCCESS)
  1267.         {
  1268.             // When reading a URL from registry, treat it like it was typed
  1269.             // in on the address bar.
  1270.             hres = S_OK;
  1271.             if(!ParseURLFromOutsideSourceW(szPath, pszPath, &cchPathSize, NULL))
  1272.                 StrCpyNW(pszPath, szPath, cchPathSizeIn);
  1273.             if(IsFileUrlW(pszPath))
  1274.             {
  1275.                 cchPathSize = cchPathSizeIn;
  1276.                 hres = PathCreateFromUrlW(pszPath, pszPath, &cchPathSize, 0);
  1277.             }
  1278.         }
  1279.         RegCloseKey(hkey);
  1280.     }
  1281.     HOMEMSG("_GetStdLocation returning",
  1282.             (SUCCEEDED(hres) ? pszPath : TEXT("Error")), hres);
  1283.     return hres;
  1284. }
  1285. HRESULT _GetStdLocation(LPTSTR pszPath, DWORD cchPathSize, UINT id)
  1286. {
  1287.     TCHAR szPathTemp[MAX_URL_STRING];
  1288.     DWORD cchTempSize = ARRAYSIZE(szPathTemp);
  1289.     HRESULT hres = E_FAIL;
  1290.     LPCWSTR pszName = NULL;
  1291.     ASSERT(cchPathSize >= cchTempSize);     // If we hit this, we will truncate the URL in some cases.
  1292.     ASSERT(pszPath && (cchPathSize > 0)); // Not Optional
  1293.     pszPath[0] = TEXT('');
  1294.     // BUGBUG: Share this code!!!
  1295.     // BUGBUG: This is Internet Explorer Specific
  1296.     switch(id) {
  1297.     default:
  1298.         ASSERT(0);
  1299.     case DVIDM_GOHOME:
  1300.         pszName = L"Start Page";
  1301.         break;
  1302.     case DVIDM_GOFIRSTHOME:
  1303.     case DVIDM_GOFIRSTHOMERO:
  1304.         pszName = L"First Home Page";
  1305.         break;
  1306.     case DVIDM_GOSEARCH:
  1307.         pszName = L"Search Page";
  1308.         break;
  1309.     case DVIDM_SEARCHBAR:
  1310.         pszName = L"Search Bar";
  1311.         break;
  1312.     case DVIDM_GOLOCALPAGE:
  1313.         pszName = L"Local Page";
  1314.         break;
  1315.     }
  1316.     hres = URLSubRegQuery(szRegKey_SMIEM, pszName, TRUE,
  1317.                        szPathTemp, cchTempSize, URLSUB_ALL);
  1318.     if (FAILED(hres) &&
  1319.         ((DVIDM_GOFIRSTHOME == id) || (DVIDM_GOFIRSTHOMERO == id)))
  1320.     {
  1321.         // The First Home key doesn't exist so use the home key.
  1322.         pszName = TEXT("Start Page");
  1323.         hres = URLSubRegQuery(szRegKey_SMIEM, pszName, TRUE,
  1324.                            szPathTemp, cchTempSize, URLSUB_ALL);
  1325.         id = DVIDM_GOHOME;
  1326.     }
  1327.     if (SUCCEEDED(hres))
  1328.     {
  1329.         // When reading a URL from registry, treat it like it was typed
  1330.         // in on the address bar.
  1331.         if(ParseURLFromOutsideSourceW(szPathTemp, pszPath, &cchPathSize, NULL))
  1332.         {
  1333.             if(IsFileUrlW(pszPath))
  1334.                 hres = PathCreateFromUrlW(pszPath, pszPath, &cchPathSize, 0);
  1335.         }
  1336.     }
  1337.     if (DVIDM_GOFIRSTHOME == id)    // Delete that FIRSTHOME key
  1338.     {
  1339.         HUSKEY hUSKey;
  1340.         if (ERROR_SUCCESS == SHRegOpenUSKey(szRegKey_SMIEM, KEY_WRITE, NULL, &hUSKey, FALSE))
  1341.         {
  1342.             SHRegDeleteUSValue(hUSKey, TEXT("First Home Page"), SHREGDEL_DEFAULT);
  1343.             SHRegCloseUSKey(hUSKey);
  1344.         }
  1345.         hres = S_OK;
  1346.     }
  1347.     HOMEMSG("_GetStdLocation returning",
  1348.             (SUCCEEDED(hres) ? pszPath : TEXT("Error")), hres);
  1349.     return hres;
  1350. }
  1351. HRESULT WINAPI _GetDefaultLocation(UINT idp, LPWSTR pszPath, UINT cchMax)
  1352. {
  1353.     switch (idp)
  1354.     {
  1355.     case IDP_UPDATE:
  1356.     case IDP_CHANNELGUIDE:
  1357.         URLSubLoadString(NULL, IDS_DEF_UPDATE+(idp-IDP_UPDATE), pszPath, cchMax, URLSUB_ALL);
  1358.         break;
  1359.     default:
  1360.         _GetDefaultLocation(pszPath, cchMax, (idp == IDP_SEARCH) ? DVIDM_GOSEARCH : DVIDM_GOHOME);
  1361.         break;
  1362.     }
  1363.     return S_OK;
  1364. }
  1365. HRESULT WINAPI SHDGetPageLocation(HWND hwndOwner, UINT idp, LPWSTR pszPath, UINT cchMax, LPITEMIDLIST *ppidlOut)
  1366. {
  1367.     TCHAR szBuf[MAX_URL_STRING];
  1368.     if (pszPath==NULL) {
  1369.         pszPath = szBuf;
  1370.         cchMax = ARRAYSIZE(szBuf);
  1371.     }
  1372.     *ppidlOut = NULL;
  1373.     HRESULT hres = S_OK;
  1374.     switch (idp) {
  1375.     case IDP_UPDATE:
  1376.     case IDP_CHANNELGUIDE:
  1377.         ASSERT(IDP_CHANNELGUIDE-IDP_UPDATE == IDS_DEF_CHANNELGUIDE-IDS_DEF_UPDATE);
  1378.         if (FAILED(_GetDefaultLocation(pszPath, cchMax, idp)))
  1379.         {
  1380.             _GetDefaultLocation(idp, pszPath, cchMax);
  1381.         }
  1382.         break;
  1383.     default:
  1384.         ASSERT(idp==IDP_START || idp==IDP_SEARCH);
  1385.         hres = _GetStdLocation(pszPath, cchMax,
  1386.                     (idp == IDP_SEARCH) ? DVIDM_GOSEARCH : DVIDM_GOHOME);
  1387.         if (FAILED(hres))
  1388.         {
  1389.             _GetDefaultLocation(idp, pszPath, cchMax);
  1390.         }
  1391.         break;
  1392.     }
  1393.     if (SUCCEEDED(hres))
  1394.     {
  1395.         hres = IECreateFromPath(pszPath, ppidlOut);
  1396.         if (FAILED(hres))
  1397.         {
  1398.             // IECreateFromPath() above could have failed if the default location
  1399.             // was invalid. (Like file://server_no_exist/
  1400.             _GetDefaultLocation(idp, pszPath, cchMax);
  1401.             hres = IECreateFromPath(pszPath, ppidlOut);
  1402.         }
  1403.         HOMEMSG("SHDGetPageLocation SHILCreateFromPage returned", pszPath, hres);
  1404.     }
  1405.     return hres;
  1406. }
  1407. void CDocObjectHost::_ChainBSC()
  1408. {
  1409.     if (!_bsc._pbscChained && _phf) {
  1410.         // Get "chaigned" bind status, if any
  1411.         IServiceProvider* psp = NULL;
  1412.         HRESULT hres = _phf->QueryInterface(IID_IServiceProvider, (LPVOID*)&psp);
  1413.         CHAINMSG("_StartAsyncBinding hlf->QI returns", hres);
  1414.         if (SUCCEEDED(hres)) {
  1415.             ASSERT(NULL==_bsc._pbscChained);
  1416.             hres = psp->QueryService(SID_SHlinkFrame, IID_IBindStatusCallback, (LPVOID*)&_bsc._pbscChained);
  1417.             CHAINMSG("_StartAsyncBinding psp(hlf)->QS returns", hres);
  1418.             psp->Release();
  1419.             if (SUCCEEDED(hres))
  1420.             {
  1421.                 ASSERT(NULL==_bsc._pnegotiateChained);
  1422.                 _bsc._pbscChained->QueryInterface(IID_IHttpNegotiate, (LPVOID *)&_bsc._pnegotiateChained);
  1423.             }
  1424.         }
  1425.     }
  1426. }
  1427. //
  1428. // WARNING: Following two global variables are shared among multiple-threads
  1429. //  in a thread. Therefore, all right-access must be serialized and all read
  1430. //  access should be blocked when right is going on.
  1431. //
  1432. //   Right now, we just initialize them once (based on the registry setting)
  1433. //  and never update. It allows us to simplify the code quite a bit. If we
  1434. //  need to update, then _RegisterMediaTypeClass should be changed significantlly
  1435. //  so that we can safely handle multiple access to those hdsa's. (SatoNa)
  1436. //
  1437. HDSA g_hdsaCls = NULL;
  1438. HDSA g_hdsaStr = NULL;
  1439. BOOL CDocObjectHost::_BuildClassMapping(void)
  1440. {
  1441.     if (g_hdsaCls) {
  1442.         return (DSA_GetItemCount(g_hdsaCls)==DSA_GetItemCount(g_hdsaStr));
  1443.     }
  1444.     ENTERCRITICAL;
  1445.     if (!g_hdsaCls) {
  1446.         g_hdsaStr = DSA_Create(SIZEOF(LPCSTR), 32);
  1447.         if (g_hdsaStr)
  1448.         {
  1449.             HDSA hdsaCls = DSA_Create(SIZEOF(CLSID), 32);
  1450.             if (hdsaCls)
  1451.             {
  1452.                 HKEY hkey;
  1453.                 if (RegOpenKey(HKEY_LOCAL_MACHINE,
  1454.                         TEXT("Software\Microsoft\Internet Explorer\MediaTypeClass"),
  1455.                         &hkey) == ERROR_SUCCESS)
  1456.                 {
  1457.                     TCHAR szCLSID[64];  // enough for "{CLSID}"
  1458.                     for (int iKey=0;
  1459.                          RegEnumKey(hkey, iKey, szCLSID, SIZEOF(szCLSID))==ERROR_SUCCESS;
  1460.                          iKey++)
  1461.                     {
  1462.                         CLSID clsid;
  1463.                         if (FAILED(CLSIDFromString(szCLSID, &clsid))) {
  1464.                             TraceMsg(DM_WARNING, "CDOH::_RMTC CLSIDFromString(%x) failed", szCLSID);
  1465.                             continue;
  1466.                         }
  1467.                         TraceMsg(DM_MIMEMAPPING, "CDOH::_RMTC RegEnumKey found %s", szCLSID);
  1468.                         HKEY hkeyCLSID;
  1469.                         if (RegOpenKey(hkey, szCLSID, &hkeyCLSID) == ERROR_SUCCESS)
  1470.                         {
  1471.                             for (int iValue=0; ; iValue++)
  1472.                             {
  1473.                                 CHAR szFormatName[128];
  1474.                                 DWORD dwType;
  1475.                                 DWORD cchValueName = ARRAYSIZE(szFormatName);
  1476.                                 //
  1477.                                 // Keep the name ansi because it needs to get
  1478.                                 // passed to urlmon's RegisterMediaTypeClass as
  1479.                                 // ansi.
  1480.                                 //
  1481.                                 if (RegEnumValueA(hkeyCLSID, iValue, szFormatName, &cchValueName, NULL,
  1482.                                                  &dwType, NULL, NULL)==ERROR_SUCCESS)
  1483.                                 {
  1484.                                     TraceMsg(DM_MIMEMAPPING, "CDOH::_RMTC RegEnumValue found %s", szFormatName);
  1485.                                     LPSTR psz = StrDupA(szFormatName);
  1486.                                     if (psz) {
  1487.                                         DSA_InsertItem(hdsaCls, 0xffff, &clsid);
  1488.                                         if (DSA_InsertItem(g_hdsaStr, 0xffff, &psz)<0) {
  1489.                                             LocalFree(psz);
  1490.                                             break;
  1491.                                         }
  1492.                                     }
  1493.                                 } else {
  1494.                                     break;
  1495.                                 }
  1496.                             }
  1497.                             RegCloseKey(hkeyCLSID);
  1498.                         } else {
  1499.                             TraceMsg(DM_WARNING, "CDOH::_RMTC RegOpenKey(%s) failed", szCLSID);
  1500.                         }
  1501.                     }
  1502.                     RegCloseKey(hkey);
  1503.                 } else {
  1504.                     TraceMsg(0, "CDOH::_RMTC RegOpenKey(MediaTypeClass) failed");
  1505.                 }
  1506.                 //
  1507.                 // Update g_hdsaCls at the end so that other thread won't
  1508.                 // access while we are adding items.
  1509.                 //
  1510.                 g_hdsaCls = hdsaCls;
  1511.                 ASSERT(DSA_GetItemCount(g_hdsaCls)==DSA_GetItemCount(g_hdsaStr));
  1512.             }
  1513.         }
  1514.     }
  1515.     LEAVECRITICAL;
  1516.     return (g_hdsaCls && DSA_GetItemCount(g_hdsaCls)==DSA_GetItemCount(g_hdsaStr));
  1517. }
  1518. HRESULT CDocObjectHost::_RegisterMediaTypeClass(IBindCtx* pbc)
  1519. {
  1520.     HRESULT         hres    = S_FALSE; // Assume no mapping
  1521.     if (_BuildClassMapping() && DSA_GetItemCount(g_hdsaCls)) {
  1522.         //
  1523.         // WARNING: This code assumes that g_hdsaCls/g_hdsaStr never
  1524.         //  changes once they are initializes. Read notes above
  1525.         //  those global variables for detail.
  1526.         //
  1527.         hres = RegisterMediaTypeClass(pbc,
  1528.                         DSA_GetItemCount(g_hdsaCls),
  1529.                         (LPCSTR*)DSA_GetItemPtr(g_hdsaStr, 0),
  1530.                         (CLSID*)DSA_GetItemPtr(g_hdsaCls, 0), 0);
  1531.         TraceMsg(DM_MIMEMAPPING, "CDOH::_StartAsyncBinding RegisterMTC returns %x", hres);
  1532.     }
  1533.     // Now see if the container has anything that needs to be registered
  1534.     //
  1535.     if (_psp)
  1536.     {
  1537.         IMimeInfo       *pIMimeInfo;
  1538.         hres = _psp->QueryService(SID_IMimeInfo, IID_IMimeInfo, (LPVOID*)&pIMimeInfo);
  1539.         if (SUCCEEDED(hres))
  1540.         {
  1541.             UINT            cTypes  = 0;
  1542.             LPCSTR          *ppszTypes = NULL;
  1543.             CLSID           *pclsIDs= NULL;
  1544.             ASSERT(pIMimeInfo);
  1545.             hres = pIMimeInfo->GetMimeCLSIDMapping(&cTypes, &ppszTypes, &pclsIDs);
  1546.             if(SUCCEEDED(hres)) {
  1547.                 if(cTypes && ppszTypes && pclsIDs) {
  1548.                     // Last one to register wins, so if the container wants to override what is
  1549.                     // already registered this should do it.
  1550.                     //  URLMon will handle the duplicates corectly.
  1551.                     //
  1552.                     hres = RegisterMediaTypeClass(pbc, cTypes, ppszTypes, pclsIDs, 0);
  1553.                     TraceMsg(DM_MIMEMAPPING, "CDOH::_StartAsyncBinding RegisterMTC for Container returns %x", hres);
  1554.                 }
  1555.                 // RegisterMediaTypeClass should have made copies
  1556.                 // so free the containers allocations as it expects us to do
  1557.                 //
  1558.                 //      CoTaskMemFree(NULL) is OK
  1559.                 //
  1560.                 CoTaskMemFree(ppszTypes);
  1561.                 CoTaskMemFree(pclsIDs);
  1562.             }
  1563.             pIMimeInfo->Release();
  1564.         } else {
  1565.             hres = S_FALSE;
  1566.         }
  1567.     }
  1568.     return hres;
  1569. }
  1570. HRESULT _RegisterAcceptHeaders(IBindCtx* pbc, IShellBrowser* psb)
  1571. {
  1572.     return RegisterDefaultAcceptHeaders(pbc, psb);
  1573. }
  1574. HRESULT GetAmbientBoolProp(IExpDispSupport* peds, DISPID dispid, BOOL *pb)
  1575. {
  1576.     VARIANT var = {0};
  1577.     // Assume failure
  1578.     *pb = FALSE;
  1579.     HRESULT hres = peds->OnInvoke(dispid, IID_NULL, NULL, DISPATCH_PROPERTYGET, (DISPPARAMS *)&g_dispparamsNoArgs, &var, NULL, NULL);
  1580.     if (SUCCEEDED(hres))
  1581.     {
  1582.         // VB returns success with VT_EMPTY, so we can't assert here
  1583.         if (var.vt == VT_BOOL)
  1584.         {
  1585.             *pb = (var.boolVal) ? TRUE : FALSE;
  1586.         }
  1587.         else
  1588.         {
  1589.             // Even though VB says VT_EMPTY, we don't know what other containers
  1590.             // might shove in here. Make sure we clean up.
  1591.             //
  1592.             VariantClear(&var);
  1593.         }
  1594.     }
  1595.     else
  1596.     {
  1597.         hres = E_FAIL;
  1598.     }
  1599.     return hres;
  1600. }
  1601. HRESULT CDocObjectHost::_GetOfflineSilent(BOOL *pbIsOffline, BOOL *pbIsSilent)
  1602. {
  1603.     if (_peds)
  1604.     {
  1605.         if (pbIsOffline)
  1606.             GetAmbientBoolProp(_peds, DISPID_AMBIENT_OFFLINEIFNOTCONNECTED, pbIsOffline);
  1607.         if (pbIsSilent)
  1608.             GetAmbientBoolProp(_peds, DISPID_AMBIENT_SILENT, pbIsSilent);
  1609.     }
  1610.     else
  1611.     {
  1612.         if (pbIsOffline)
  1613.             *pbIsOffline = FALSE;
  1614.         if (pbIsSilent)
  1615.             *pbIsSilent = FALSE;
  1616.     }
  1617.     return S_OK;
  1618. }
  1619. /*
  1620.     Callback function for RatingObtainQuery
  1621. */
  1622. void RatingObtainQueryCallback(DWORD dwUserData, HRESULT hr, LPCSTR pszRating, LPVOID lpvInpageRating)
  1623. {
  1624.     TraceMsg(DM_PICS, "RatingObtainQueryCallback given result %x", hr);
  1625.     /* WARNING: This function is called by MSRATING.DLL on a separate thread,
  1626.      * not the main message loop thread.  Touch nothing in important data
  1627.      * structures not protected by critical sections!
  1628.      *
  1629.      * Merely format up a windows message with the info we have;  we'll handle
  1630.      * this in the main thread, if we ever get there.
  1631.      *
  1632.      * Note that pszRating is ignored, we count on the ratings engine to have
  1633.      * called RatingCheckUserAccess for us and provide the HRESULT.
  1634.      */
  1635.     if (!::_PostPicsMessage(dwUserData, hr, lpvInpageRating))
  1636.         ::RatingFreeDetails(lpvInpageRating);
  1637. }
  1638. void CDocObjectHost::_StartPicsQuery(void)
  1639. {
  1640.     if (IS_RATINGS_ENABLED() && ::RatingEnabledQuery() == S_OK) {
  1641.         TraceMsg(DM_PICS, "CDOH::_StartPicsQuery entered with ratings enabled");
  1642.         BOOL fEnforce = TRUE;
  1643.         if (_pszPicsURL != NULL) {
  1644.             delete _pszPicsURL;
  1645.             _pszPicsURL = NULL;
  1646.         }
  1647.         LPOLESTR pwszRawURL = NULL;
  1648.         if (SUCCEEDED(_GetCurrentPageW(&pwszRawURL, TRUE))) {
  1649.             /* We have to call CoInternetGetSecurityUrl to convert pluggable
  1650.              * protocols into known schemes, so we know whether we need to
  1651.              * enforce ratings on them.
  1652.              */
  1653.             LPOLESTR pwszSecurityURL = NULL;
  1654.             if (SUCCEEDED(CoInternetGetSecurityUrl(pwszRawURL, &pwszSecurityURL,
  1655.                                                    PSU_SECURITY_URL_ONLY, 0)))
  1656.             {
  1657.                 // List of protocols for which we never enforce ratings.
  1658.                 if (!StrCmpNIW(pwszSecurityURL, L"file:", 5) ||
  1659.                     !StrCmpNIW(pwszSecurityURL, L"about:", 6) ||
  1660.                     !StrCmpNIW(pwszSecurityURL, L"mk:", 3)) {
  1661.                     fEnforce = FALSE;
  1662.                 }
  1663.                 else {
  1664.                     Str_SetPtr(&_pszPicsURL, pwszSecurityURL);
  1665.                 }
  1666.                 OleFree(pwszSecurityURL);
  1667.             }
  1668.             OleFree(pwszRawURL);
  1669.         }
  1670.         if (fEnforce) {
  1671.             TraceMsg(DM_PICS, "CDOH::_StartPicsQuery (%s) turning on wait flags", _pszPicsURL);
  1672.             _fbPicsWaitFlags = PICS_WAIT_FOR_ASYNC
  1673.                              | PICS_WAIT_FOR_INDOC
  1674.                              | PICS_WAIT_FOR_END
  1675.                              | PICS_WAIT_FOR_ROOT
  1676.                              ;
  1677.             _fPicsAccessAllowed = 0;
  1678.             HRESULT hr;
  1679.             _dwPicsSerialNumber = ::_AddPicsQuery(_hwnd);
  1680.             if (_dwPicsSerialNumber == 0)
  1681.                 hr = E_OUTOFMEMORY;
  1682.             else
  1683.             {
  1684.                 //
  1685.                 // The ratings apis are ansi.
  1686.                 //
  1687.                 CHAR szURL[MAX_URL_STRING];
  1688.                 SHUnicodeToAnsi(_pszPicsURL, szURL, ARRAYSIZE(szURL));
  1689.                 hr = RatingObtainQuery(szURL, _dwPicsSerialNumber, RatingObtainQueryCallback, &_hPicsQuery);
  1690.             }
  1691.             if (FAILED(hr)) {
  1692.                 TraceMsg(DM_PICS, "CDOH::_StartPicsQuery no async query queued");
  1693.                 ::_RemovePicsQuery(_dwPicsSerialNumber);
  1694.                 _dwPicsSerialNumber = 0;
  1695.                 _fbPicsWaitFlags &= ~PICS_WAIT_FOR_ASYNC;
  1696.             }
  1697.             else {
  1698.                 TraceMsg(DM_PICS, "CDOH::_StartPicsQuery async query queued");
  1699.             }
  1700.         }
  1701.     }
  1702. }
  1703. void CDocObjectHost::_GotLabel(HRESULT hres, LPVOID pDetails, BYTE bfSource)
  1704. {
  1705.     TraceMsg(DM_PICS, "CDOH::_GotLabel hres=%x, source=%x, waitflags=%x", hres, (DWORD)bfSource, (DWORD)_fbPicsWaitFlags);
  1706.     /* If we've already gotten a result from this or a more significant source,
  1707.      * ignore this one.
  1708.      */
  1709.     if (!(_fbPicsWaitFlags & bfSource)) {
  1710.         TraceMsg(DM_PICS, "CDOH::_GotLabel already got label from that source");
  1711.         if (pDetails != NULL)
  1712.             ::RatingFreeDetails(pDetails);
  1713.     }
  1714.     else {
  1715.         /* If the result is an error somehow (label doesn't apply, etc.), and
  1716.          * we can expect more labels from this source, then we don't do anything
  1717.          * except save the rating details if we haven't got any yet.
  1718.          */
  1719.         if (FAILED(hres) && (PICS_MULTIPLE_FLAGS & bfSource)) {
  1720.             TraceMsg(DM_PICS, "CDOH::_GotLabel label error and may be multiple");
  1721.             if (_pRatingDetails == NULL) {
  1722.                 _pRatingDetails = pDetails;
  1723.             }
  1724.             else {
  1725.                 ::RatingFreeDetails(pDetails);
  1726.             }
  1727.         }
  1728.         else {
  1729.             /* Either we got a definitive answer from this rating source, or
  1730.              * this is the only answer we'll get from it.  We clear at least
  1731.              * the flag for this source so we know we've heard from it.  If
  1732.              * the response was not an error, then clear flags for all less
  1733.              * significant sources as well, so that we'll ignore them.  On
  1734.              * the other hand, if this source returned an error, it didn't
  1735.              * give us anything useful, so we keep looking at other sources.
  1736.              */
  1737.             if (SUCCEEDED(hres))
  1738.                 _fbPicsWaitFlags &= bfSource - 1;
  1739.             else
  1740.                 _fbPicsWaitFlags &= ~bfSource;
  1741.             TraceMsg(DM_PICS, "CDOH::_GotLabel, waitflags now %x", (DWORD)_fbPicsWaitFlags);
  1742.             if (hres == S_OK) {
  1743.                 TraceMsg(DM_PICS, "CDOH::_GotLabel allowing access");
  1744.                 ::RatingFreeDetails(pDetails);  /* don't need this if access allowed */
  1745.                 _fPicsAccessAllowed = 1;
  1746.             }
  1747.             else {
  1748.                 /* Access denied or error.  Meaningful details from this result
  1749.                  * can override details from an earlier, less significant
  1750.                  * result.  Only explicitly deny access if not an error,
  1751.                  * though (this handles the valid root label followed by
  1752.                  * invalid in-document label, for example).
  1753.                  */
  1754.                 if (pDetails != NULL) {
  1755.                     if (_pRatingDetails != NULL)
  1756.                         ::RatingFreeDetails(_pRatingDetails);
  1757.                     _pRatingDetails = pDetails;
  1758.                 }
  1759.                 if (SUCCEEDED(hres))
  1760.                     _fPicsAccessAllowed = 0;
  1761.             }
  1762.         }
  1763.     }
  1764.     if (_fPicsBlockLate && !_fbPicsWaitFlags)
  1765.         _HandlePicsChecksComplete();
  1766. }
  1767. void CDocObjectHost::_HandleInDocumentLabel(LPCTSTR pszLabel)
  1768. {
  1769.     BYTE bFlag = (_pRootDownload != NULL) ? PICS_WAIT_FOR_ROOT : PICS_WAIT_FOR_INDOC;
  1770.     TraceMsg(DM_PICS, "CDOH::_HandleInDocumentLabel source %x gave label %s", (DWORD)bFlag, pszLabel);
  1771.     if (!(_fbPicsWaitFlags & bFlag)) {
  1772.         TraceMsg(DM_PICS, "CDOH::_HandleInDocumentLabel rejecting based on waitflags %x", (DWORD)_fbPicsWaitFlags);
  1773.         return;
  1774.     }
  1775.     LPVOID pDetails = NULL;
  1776.     //
  1777.     // Ratings has only ansi apis!
  1778.     //
  1779.     CHAR szURL[MAX_URL_STRING];
  1780.     SHUnicodeToAnsi(_pszPicsURL, szURL, ARRAYSIZE(szURL));
  1781.     UINT cbMultiByte = WideCharToMultiByte(CP_ACP, 0, pszLabel,
  1782.                                            -1, NULL, 0, NULL, NULL);
  1783.     if (cbMultiByte > 0) {
  1784.         char *pszLabelAnsi = new char[cbMultiByte+1];
  1785.         if (pszLabelAnsi != NULL)
  1786.         {
  1787.             if (WideCharToMultiByte(CP_ACP, 0, pszLabel, -1, pszLabelAnsi,
  1788.                                     cbMultiByte+1, NULL, NULL))
  1789.             {
  1790.                 HRESULT hres = ::RatingCheckUserAccess(NULL, szURL,
  1791.                                                        pszLabelAnsi, NULL, _dwPicsLabelSource,
  1792.                                                        &pDetails);
  1793.                 _GotLabel(hres, pDetails, bFlag);
  1794.             }
  1795.             delete [] pszLabelAnsi;
  1796.         }
  1797.     }
  1798. }
  1799. void CDocObjectHost::_HandleDocumentEnd(void)
  1800. {
  1801.     BYTE bFlag = (_pRootDownload != NULL) ? PICS_WAIT_FOR_ROOT : PICS_WAIT_FOR_END;
  1802.     TraceMsg(DM_PICS, "CDOH::_HandleDocumentEnd -- no more PICS labels from source %x", (DWORD)bFlag);
  1803.     if (_pRootDownload != NULL) {
  1804.         ::PostMessage(_hwnd, WM_PICS_ROOTDOWNLOADCOMPLETE, 0, 0);
  1805.     }
  1806.     else {
  1807.         /* End of document;  revoke the IOleCommandTarget we gave to the document,
  1808.          * so it won't send us any more notifications.
  1809.          */
  1810.         VARIANTARG v;
  1811.         v.vt = VT_UNKNOWN;
  1812.         v.lVal = 0;
  1813.         IUnknown_Exec(_pole, &CGID_ShellDocView, SHDVID_CANSUPPORTPICS, 0, &v, NULL);
  1814.     }
  1815.     if (!(_fbPicsWaitFlags & bFlag)) {
  1816.         TraceMsg(DM_PICS, "CDOH::_HandleDocumentEnd skipping due to waitflags %x", (DWORD)_fbPicsWaitFlags);
  1817.         return;
  1818.     }
  1819.     _fbPicsWaitFlags &= ~PICS_WAIT_FOR_INDOC;   /* we know we won't get any more indoc labels */
  1820.     LPVOID pDetails = NULL;
  1821.     //
  1822.     // Ratings has only ansi apis!
  1823.     //
  1824.     CHAR szURL[MAX_URL_STRING];
  1825.     SHUnicodeToAnsi(_pszPicsURL, szURL, ARRAYSIZE(szURL));
  1826.     HRESULT hres = ::RatingCheckUserAccess(NULL, szURL, NULL, NULL, _dwPicsLabelSource, &pDetails);
  1827.     _GotLabel(hres, pDetails, bFlag);
  1828.     if (_pRootDownload == NULL) {
  1829.         if (_fbPicsWaitFlags)
  1830.             _StartPicsRootQuery(_pszPicsURL);
  1831.     }
  1832. }
  1833. /* This function parses the URL being downloaded and, if the URL doesn't
  1834.  * already refer to the root document of the site, sets up a subordinate
  1835.  * CDocObjectHost to download that root document, so we can get ratings
  1836.  * out of it.
  1837.  */
  1838. void CDocObjectHost::_StartPicsRootQuery(LPCTSTR pszURL)
  1839. {
  1840.     if (_fbPicsWaitFlags & PICS_WAIT_FOR_ROOT) {
  1841.         BOOL fQueued = FALSE;
  1842.         TraceMsg(DM_PICS, "CDOH::_StartPicsRootQuery parsing %s", pszURL);
  1843.         WCHAR wszRootURL[MAX_URL_STRING+1];
  1844.         DWORD cchResult;
  1845.         /* The pszURL we're passed is actually the result of calling
  1846.          * CoInternetGetSecurityUrl, and so may not be the scheme that
  1847.          * the caller is browsing to.  To support pluggable protocols
  1848.          * determining the root location themselves, we first use the
  1849.          * URL reported by _GetCurrentPage, which may refer to a
  1850.          * pluggable protocol; if that fails, we use the more standard
  1851.          * URL.
  1852.          */
  1853.         HRESULT hres = INET_E_DEFAULT_ACTION;
  1854.         LPOLESTR pwszURL = NULL;
  1855.         if (SUCCEEDED(_GetCurrentPageW(&pwszURL, TRUE))) {
  1856.             hres = CoInternetParseUrl(pwszURL, PARSE_ROOTDOCUMENT, 0, wszRootURL,
  1857.                                       ARRAYSIZE(wszRootURL), &cchResult, 0);
  1858.             OleFree(pwszURL);
  1859.         }
  1860.         if (pszURL != NULL && (hres == INET_E_DEFAULT_ACTION || hres == E_FAIL)) {
  1861.             /* Pluggable protocol doesn't support PARSE_ROOTDOCUMENT.  Use the
  1862.              * more standard URL we were supplied with.
  1863.              */
  1864.             hres = CoInternetParseUrl(pszURL, PARSE_ROOTDOCUMENT, 0, wszRootURL,
  1865.                                       ARRAYSIZE(wszRootURL), &cchResult, 0);
  1866.         }
  1867.         if (SUCCEEDED(hres)) {
  1868.             IMoniker *pmk = NULL;
  1869.             hres = MonikerFromURL(wszRootURL, &pmk);
  1870.             if (SUCCEEDED(hres)) {
  1871.                 BOOL fFrameIsSilent = FALSE;
  1872.                 BOOL fFrameIsOffline = FALSE;
  1873.                 this->_GetOfflineSilent(&fFrameIsOffline, &fFrameIsSilent);
  1874.                 _pRootDownload = new CPicsRootDownload(this, &_ctPics, fFrameIsOffline, fFrameIsSilent);
  1875.                 if (_pRootDownload != NULL) {
  1876.                     TraceMsg(DM_PICS, "CDOH::_StartPicsRootQuery starting download");
  1877.                     hres = _pRootDownload->StartDownload(pmk);
  1878.                     if (SUCCEEDED(hres))
  1879.                         fQueued = TRUE;
  1880.                 }
  1881.             }
  1882.             if (pmk != NULL)
  1883.                 pmk->Release();
  1884.         }
  1885.         if (!fQueued) {
  1886.             _fbPicsWaitFlags &= ~PICS_WAIT_FOR_ROOT;
  1887.             TraceMsg(DM_PICS, "CDOH::_StartPicsRootQuery queueing failed, waitflags now %x", (DWORD)_fbPicsWaitFlags);
  1888.             if (!_fbPicsWaitFlags) {
  1889.                 _HandlePicsChecksComplete();
  1890.             }
  1891.         }
  1892.     }
  1893.     else {
  1894.         TraceMsg(DM_PICS, "CDOH::_StartPicsRootQuery no query queued, waitflags=%x", (DWORD)_fbPicsWaitFlags);
  1895.     }
  1896. }
  1897. HRESULT CDocObjectHost::_StartAsyncBinding(IMoniker* pmk, IBindCtx* pbc, IShellView* psvPrev)
  1898. {
  1899.     URLMSG(TEXT("_StartAsyncBinding called"));
  1900.     HRESULT hres;
  1901.     ASSERT(_bsc._pbc==NULL && _pole==NULL);
  1902.     _bsc._RegisterObjectParam(pbc);
  1903.     //
  1904.     //  Associate the client site as an object parameter to this
  1905.     // bind context so that Trident can pick it up while processing
  1906.     // IPersistMoniker::Load().
  1907.     //
  1908.     pbc->RegisterObjectParam(WSZGUID_OPID_DocObjClientSite,
  1909.         SAFECAST(this, IOleClientSite*));
  1910.     _ChainBSC();
  1911.     IUnknown* punk = NULL;
  1912.     _bsc._pbc = pbc;
  1913.     pbc->AddRef();
  1914.     // Decide right here whether or not this frame is offline
  1915.     BOOL bFrameIsOffline = FALSE;
  1916.     BOOL bFrameIsSilent = FALSE;
  1917.     this->_GetOfflineSilent(&bFrameIsOffline, &bFrameIsSilent);
  1918.     _bsc._bFrameIsOffline = bFrameIsOffline ? TRUE : FALSE;
  1919.     _bsc._bFrameIsSilent  = bFrameIsSilent ? TRUE : FALSE;
  1920.     BOOL bSuppressUI = (_bsc._bFrameIsSilent || _IsDesktopItem(SAFECAST(this, CDocObjectHost*))) ? TRUE : FALSE;
  1921. #ifdef DEBUG
  1922.     PERFMSG(TEXT("_StartAsyncBinding Calling pmk->BindToObject"), GetCurrentTime()-g_dwPerf);
  1923.     g_dwPerf = GetCurrentTime();
  1924. #endif
  1925. #ifdef DEBUG
  1926.     if (g_dwPrototype & 0x00000800) {
  1927.         TraceMsg(DM_TRACE, "CDOH::_StartAsyncBinding skipping CLSID mapping");
  1928.     }
  1929.     else
  1930. #endif
  1931.     {
  1932.         // Register overriding mime->CLSID mapping
  1933.         _RegisterMediaTypeClass(pbc);
  1934.     }
  1935.     // Register accept headers
  1936.     _RegisterAcceptHeaders(pbc, _psb);
  1937.     if (_pwb)
  1938.         _pwb->SetNavigateState(BNS_BEGIN_NAVIGATE);
  1939.     _StartPicsQuery();
  1940.     //
  1941.     //  BUGBUG - Crazy sync/async behavior of URLMON.  - zekel - 6-AUG-97
  1942.     //  any of the following may occur:
  1943.     //
  1944.     //  1.  SUCCESS or FAILURE:  we receive sync E_PENDING from BindToObject,
  1945.     //      and then get an Async HRESULT on OnStopBinding().
  1946.     //      this is the most common case and the basic design.
  1947.     //
  1948.     //  2.  SUCCESS:  we receive sync S_OK from BindToObject and
  1949.     //      need to complete the async behavior on our BSCB ourself
  1950.     //      since urlmon started but did not finish.
  1951.     //
  1952.     //  3.  SUCCESS:  while inside BindToObject(), we receive sync S_OK
  1953.     //      from OnStopBinding(), and then BindToObject returns with S_OK.
  1954.     //
  1955.     //  4.  FAILURE:  simplest case is an error being returned from BindToObject()
  1956.     //      but without an any OnStopBinding() so we need to complete
  1957.     //      the async behavior on our BSCB ourself since urlmon started but did not finish.
  1958.     //      this usually occurs when accessing local files.
  1959.     //
  1960.     //  5.  FAILURE:  while inside BindToObject(), we receive sync S_OK from OnStopBinding(),
  1961.     //      and then BindToObject returns with some other error that needs to be handled.
  1962.     //      this occurs with some malformed urls.
  1963.     //
  1964.     //  6.  FAILURE:  while inside BindToObject(), we receive a sync error from OnStopBinding(),
  1965.     //      and then BindToObject returns with some other error (usually E_FAIL).
  1966.     //      we need to trust the first one.  this occurs when wininet
  1967.     //      returns syncronous errors, and its error is the one returned in OnStopBinding()
  1968.     //
  1969.     //  7.  FAILURE:  while inside BindToObject(), we receive a sync error from OnStopBinding(),
  1970.     //      and then BindToObject returns with E_PENDING.  which we think means everything
  1971.     //      is going great, and urlmon thinks it is done.  this happens with a file: to
  1972.     //      a resource that is not hostable.  we need to show the download UI.
  1973.     //
  1974.     //  in order to support all the errors in the most consistent and safe manner,
  1975.     //  we defer any errors in OnStopBinding() if they are delivered synchronously
  1976.     //  on BindToObject().  the OnStopBinding() error always overrides the BindToObject()
  1977.     //  error, but any error will always override any success.
  1978.     //
  1979.     ASSERT(S_OK == _hrOnStopBinding);
  1980.     _fSyncBindToObject = TRUE;
  1981.     URLMSG(TEXT("_StartAsyncBinding calling pmk->BindToObject"));
  1982.     hres = pmk->BindToObject(pbc, NULL, IID_IUnknown, (LPVOID*)&punk);
  1983.     URLMSG3(TEXT("_StartAsyncBinding pmk->BindToObject returned"), hres, punk);
  1984.     _fSyncBindToObject = FALSE;
  1985.     if (SUCCEEDED(_hrOnStopBinding) && (SUCCEEDED(hres) || hres==E_PENDING))
  1986.     {
  1987.         hres = S_OK;
  1988.         if (_bsc._pbc) {
  1989.             //
  1990.             // In case OnStopBinding hasn't been called.
  1991.             //
  1992.             if (!_pole) {
  1993.                 if (psvPrev) {
  1994.                     _bsc._psvPrev = psvPrev;
  1995.                     psvPrev->AddRef();
  1996.                 }
  1997.             } else {
  1998.                 URLMSG3(TEXT("_StartAsyncBinding we've already got _pole"), hres, _pole);
  1999.             }
  2000.             //
  2001.             // If moniker happen to return the object synchronously, emulate
  2002.             // OnDataAvailable callback and OnStopBinding.
  2003.             //
  2004.             if (punk)
  2005.             {
  2006.                 _bsc.OnObjectAvailable(IID_IUnknown, punk);
  2007.                 _bsc.OnStopBinding(hres, NULL);
  2008.                 punk->Release();
  2009.                 ASSERT(_bsc._pbc==NULL);
  2010.             }
  2011.         } else {
  2012.             //
  2013.             // OnStopBinding has been already called.
  2014.             //
  2015.             if (punk)
  2016.             {
  2017.                 AssertMsg(0, TEXT("CDOH::_StartAsyncBinding pmk->BindToObject returned punk after calling OnStopBinding")); // Probably URLMON bug.
  2018.                 punk->Release();
  2019.             }
  2020.         }
  2021.     }
  2022.     else
  2023.     {
  2024.         // Binding failed.
  2025.         TraceMsg(DM_WARNING, "CDOH::_StartAsyncBinding failed (%x)", hres);
  2026.         //
  2027.         //  BUGBUG - Urlmon is inconsistent in it's error handling - zekel - 4-AUG-97
  2028.         //  urlmon can return errors in three different ways from BindToObject()
  2029.         //  1.  it can return back a simple syncronous error.  without calling OnStopBinding()
  2030.         //
  2031.         //  2.  it can return a sync error,
  2032.         //          but call OnStopBinding() with S_OK first on the same thread;
  2033.         //
  2034.         //  3.  it can return a sync error,
  2035.         //          but also call OnStopBinding() with the real Error first on the same thread.
  2036.         //
  2037.         //  4.  it can return E_PENDING,
  2038.         //          but already have called OnStopBinding() with the real error.
  2039.         //
  2040.         //  SOLUTIONS:
  2041.         //  in all cases of error in OnStopBinding(), we will now postpone the OnStopBinding processing util after
  2042.         //  we have returned from the BindToObject().  we try to use the best error.
  2043.         //  we allow successful OnStopBinding() to pass through unmolested, and trap
  2044.         //  the error here if necessary.
  2045.         //
  2046.         if (FAILED(_hrOnStopBinding))
  2047.             hres = _hrOnStopBinding;
  2048.         if (_bsc._pbc)
  2049.             _bsc.OnStopBinding(hres, NULL);
  2050.         else if (!bSuppressUI)
  2051.         {
  2052.             //
  2053.             //  OnStopBinding was already called, but with a success
  2054.             //  so we need to handle the error here.  this happens
  2055.             //  with some invalid URLs like http:/server
  2056.             //
  2057.             // Fix for W98 webtv app.  If we're in a frame don't
  2058.             // blow away the frame set to dispaly the error.
  2059.             //
  2060.             if (!_fHaveParentSite)
  2061.                 _bsc._NavigateToErrorPage(ERRORPAGE_SYNTAX, this, FALSE);
  2062.         }
  2063.         ASSERT(_bsc._pbc==NULL);
  2064.     }
  2065.     return hres;
  2066. }
  2067. void CDocObjectHost::_ReleasePendingObject(BOOL fIfInited)
  2068. {
  2069.     HRESULT hres;
  2070.     IOleObject *polePending;
  2071. #ifdef TRIDENT_NEEDS_LOCKRUNNING
  2072.     IRunnableObject *pro;
  2073. #endif
  2074.     if (fIfInited == FALSE && _fPendingWasInited == FALSE)
  2075.         return;
  2076.     if (_punkPending)
  2077.     {
  2078.         if (_fCreatingPending)
  2079.         {
  2080.             _fAbortCreatePending = 1;
  2081.             return;
  2082.         }
  2083.         if (!_fPendingNeedsInit && !IsSameObject(_punkPending, _pole))
  2084.         {
  2085.             hres = _punkPending->QueryInterface(IID_IOleObject, (LPVOID *) &polePending);
  2086.             if (SUCCEEDED(hres)) {
  2087.                 LPOLECLIENTSITE pcs;
  2088.                 if (SUCCEEDED(polePending->GetClientSite(&pcs)) && pcs)
  2089.                 {
  2090.                     if (pcs == SAFECAST(this, LPOLECLIENTSITE))
  2091.                     {
  2092.                         polePending->SetClientSite(NULL);
  2093.                     }
  2094.                     pcs->Release();
  2095.                 }
  2096.                 polePending->Release();
  2097.             }
  2098.         }
  2099. #ifdef TRIDENT_NEEDS_LOCKRUNNING
  2100.         //  TRIDENT NO LONGER SUPPORTS IRunnableObject
  2101.         hres = _punkPending->QueryInterface(IID_IRunnableObject, (LPVOID *) &pro);
  2102.         if (SUCCEEDED(hres))
  2103.         {
  2104.             hres = pro->LockRunning(FALSE, TRUE);
  2105.             pro->Release();
  2106.         }
  2107. #endif
  2108.         SAFERELEASE(_punkPending);
  2109.         _fPendingWasInited = FALSE;
  2110.     }
  2111. }
  2112. void CDocObjectHost::_ReleaseOleObject(BOOL fIfInited)
  2113. {
  2114.     TraceMsg(DM_DEBUGTFRAME, "CDocObjectHost::_ReleaseOleObject called %x (%x)", _pole, this);
  2115.     // Minimize impact by cleaning up in affected cases only.
  2116.     if (fIfInited == FALSE && _fPendingWasInited == FALSE)
  2117.         return;
  2118.     // release _pole object and all the associated QI'ed pointers
  2119.     if (_phls) {
  2120.         _phls->SetBrowseContext(NULL); // probably no need
  2121.         ATOMICRELEASE(_phls);
  2122.     }
  2123.     if (_pvo) {
  2124.         IAdviseSink *pSink;
  2125.         // paranoia: only blow away the advise sink if it is still us
  2126.         if (SUCCEEDED(_pvo->GetAdvise(NULL, NULL, &pSink)) && pSink) {
  2127.             if (pSink == (IAdviseSink *)this) {
  2128.                 _pvo->SetAdvise(0, 0, NULL);
  2129.             } else {
  2130.                 ASSERT(0);  // do we really hit this case?
  2131.             }
  2132.             pSink->Release();
  2133.         }
  2134.         ATOMICRELEASE(_pvo);
  2135.     }
  2136.     if (_pole) {
  2137.         LPOLECLIENTSITE pcs;
  2138.         if (SUCCEEDED(_pole->GetClientSite(&pcs)) && pcs) {
  2139.             if (IsSameObject(pcs, SAFECAST(this, LPOLECLIENTSITE))) {
  2140.                 _pole->SetClientSite(NULL);
  2141.             }
  2142.             pcs->Release();
  2143.         }
  2144.         // Notes: Make it sure that we don't hold a bogus _pole even
  2145.         //  for a moment (while we call Release).
  2146.         ATOMICRELEASE(_pole);
  2147.     }
  2148. }
  2149. //
  2150. // This member releases all the interfaces to the DocObject, which is
  2151. // essentially the reverse of _Bind.
  2152. //
  2153. void CDocObjectHost::_UnBind(void)
  2154. {
  2155.     ATOMICRELEASE(_pmsot);
  2156.     ASSERT(!_pmsov); // paranoia
  2157.     ATOMICRELEASE(_pmsov);
  2158.     ASSERT(!_pmsoc); // paranoia
  2159.     ATOMICRELEASE(_pmsoc);
  2160.     _xao.SetActiveObject(NULL);
  2161.     if (_pole) {
  2162.         // Just in case we're destroyed while we were waiting
  2163.         // for the docobj to display itself.
  2164.         //
  2165.         _RemoveTransitionCapability();
  2166.         //
  2167.         //  If this is NOT MSHTML, cache the OLE server so that we don't
  2168.         // need to restart or load the OLE server again.
  2169.         //
  2170.         if (!(_dwAppHack & (BROWSERFLAG_MSHTML | BROWSERFLAG_DONTCACHESERVER)))
  2171.         {
  2172.             IBrowserService *pbs;
  2173.             if(SUCCEEDED(QueryService(SID_STopLevelBrowser, IID_IBrowserService, (LPVOID *)&pbs)))
  2174.             {
  2175.                 pbs->CacheOLEServer(_pole);
  2176.                 pbs->Release();
  2177.             }
  2178.         }
  2179.         TraceMsg(DM_ADVISE, "CDocObjectHost::_UnBind about to call Close of %x", _pole);
  2180.         _pole->Close(OLECLOSE_NOSAVE);
  2181.         _ReleaseOleObject();
  2182.     }
  2183.     _ReleasePendingObject();
  2184.     ATOMICRELEASE(_pstg);
  2185.     ATOMICRELEASE(_pbcCur);
  2186.     ATOMICRELEASE(_pmkCur);
  2187. }
  2188. //
  2189. // HACK: If we open Excel95 objects directly, Excel goes crazy and eventually
  2190. //  hit GPF. Here is the background info, I've got Office guys (SatoNa).
  2191. //
  2192. // From:        Rajeev Misra (Xenix)
  2193. //
  2194. //   1) Excel does not handle the foll. case very well. Taking a normal file
  2195. //   loading it through IPersistFile:Load and then bringing it up as an
  2196. //   embedded object. The code was always tested so that the embedded
  2197. //   objects always got loaded through ScPrsLoad. I am seeing a bunch of
  2198. //   asserts in Excel that say that this assumption is being destroyed.
  2199. //   ASSERT(_pole);
  2200. //
  2201. // From:        Srini Koppolu
  2202. //
  2203. //   For you, there is only one case, i.e. you always deal with the files. Then your code should look like this
  2204. //
  2205. //     CreateFileMoniker from the file
  2206. //     pUIActiveObject->OnFrameWindowActivate(FALSE);
  2207. //     pmk->BindToObject(IID_IDataObject, &pdobj)
  2208. //     pUIActiveObject->OnFrameWindowActivate(TRUE);
  2209. //     OleCreateFromData()
  2210. //
  2211. //   OnFrameWindowActivate is done to take care of another excel problem.
  2212. //   If you currently have and Excel object UIActive in you and you try to
  2213. //   do IPersistFile::Load on Excel, then it will cause problems.
  2214. //
  2215. void CDocObjectHost::_AppHackForExcel95(void)
  2216. {
  2217.     ASSERT(_pole);
  2218.     HRESULT hres;
  2219.     IDataObject* pdt = NULL;
  2220.     hres = _pole->QueryInterface(IID_IDataObject, (LPVOID*)&pdt);
  2221.     TraceMsg(DM_BINDAPPHACK, "_PostBindAppHack -- QI(IOleDataObject) returned %x", hres);
  2222.     if (SUCCEEDED(hres))
  2223.     {
  2224.         ASSERT(_pstg==NULL);
  2225.         hres = StgCreateDocfile(NULL,
  2226.                 STGM_DIRECT | STGM_CREATE | STGM_READWRITE
  2227.                 | STGM_SHARE_EXCLUSIVE | STGM_DELETEONRELEASE,
  2228.                 0, &_pstg);
  2229.         TraceMsg(DM_BINDAPPHACK, "_PostBindAppHack StgCreateDocFile(NULL) returned %x", hres);
  2230.         if (SUCCEEDED(hres))
  2231.         {
  2232.             IOleObject* poleCopy = NULL;
  2233.             hres = OleCreateFromData(pdt, IID_IOleObject, OLERENDER_NONE,
  2234.                                      NULL, this, _pstg, (LPVOID*)&poleCopy);
  2235.             TraceMsg(DM_BINDAPPHACK, "_PostBindAppHack OleCreateFromData(IOleObject) returned %x", hres);
  2236.             if (SUCCEEDED(hres)) {
  2237.                 _fCantSaveBack = TRUE;
  2238.                 ATOMICRELEASE(_pole);
  2239.                 _pole = poleCopy;
  2240.             }
  2241.         }
  2242.         pdt->Release();
  2243.     }
  2244. }
  2245. //
  2246. //  This function get the UserClassID from the object and opens the regkey
  2247. // for that CLSID and returns. If pdwAppHack is non-NULL AND CLSID is
  2248. // CLSID_HTMLDocument, we skip all and returns the default apphack flag.
  2249. // This is a perf optimization, but prevents us from setting browser
  2250. // flags for Trident, which is fine. (SatoNa)
  2251. //
  2252. HKEY _GetUserCLSIDKey(IOleObject* pole, const CLSID* pclsid, DWORD* pdwAppHack)
  2253. {
  2254.     HKEY hkey = NULL;   // assume error
  2255.     HRESULT hres;
  2256.     CLSID clsid = CLSID_NULL;
  2257.     if (pole) {
  2258.         hres = pole->GetUserClassID(&clsid);
  2259.         //  GetUserClassID is optional, can return E_FAIL, then is defined to be
  2260.         //  the same as that returned by IPersist::GetClassID. cf, msdev documentation
  2261.         //  for GetUserClassID
  2262.         if (FAILED(hres))
  2263.         {
  2264.             hres = IUnknown_GetClassID(pole, &clsid);
  2265.         }
  2266.     } else if (pclsid) {
  2267.         clsid = *pclsid;
  2268.         hres = S_OK;
  2269.     }
  2270.     else
  2271.     {
  2272.         return NULL;
  2273.     }
  2274.     //
  2275.     // Notice that we check for two CLSIDs to see if this is MSHTML.
  2276.     //
  2277.     if (pdwAppHack)
  2278.     {
  2279.         static const IID IID_IVBOleObj =
  2280.             {0xb88c9640, 0x14e0, 0x11d0, { 0xb3, 0x49, 0x0, 0xa0, 0xc9, 0xa, 0xea, 0x82 } };
  2281.         LPUNKNOWN    pVBOleObj;
  2282.         if(     IsEqualGUID(clsid, CLSID_HTMLDocument)
  2283.              || IsEqualGUID(clsid, CLSID_MHTMLDocument)
  2284.              || IsEqualGUID(clsid, CLSID_HTMLPluginDocument) )
  2285.         {
  2286.             TraceMsg(TF_SHDAPPHACK, "_GetUserCLSID this is Trident. Skip opening reg key");
  2287.             *pdwAppHack = BROWSERFLAG_NEVERERASEBKGND | BROWSERFLAG_SUPPORTTOP
  2288.                             | BROWSERFLAG_MSHTML;
  2289.             return NULL;
  2290.         }
  2291.         else if (pole && SUCCEEDED(pole->QueryInterface(IID_IVBOleObj, (void**)&pVBOleObj) ))
  2292.         {
  2293.             // If the object answers to IID_IVBOleObj, it's a VB doc object and shouldn't be cached.
  2294.             //
  2295.             pVBOleObj->Release();
  2296.             *pdwAppHack = BROWSERFLAG_DONTCACHESERVER;
  2297.         }
  2298.     }
  2299.     //
  2300.     // HACK: MSHTML.DLL does not implement GetUserClassID, but
  2301.     //  returns S_OK. That's why we need to check for CLSID_NULL.
  2302.     //
  2303.     if (SUCCEEDED(hres) && !IsEqualGUID(clsid, CLSID_NULL)) {
  2304.         TCHAR szBuf[50];        // 50 is enough for GUID
  2305.         SHStringFromGUID(clsid, szBuf, ARRAYSIZE(szBuf));
  2306.         TraceMsg(DM_BINDAPPHACK, "_PostBindAppHack GetUserClassID = %s", szBuf);
  2307.         TCHAR szKey[60];    // 60 is enough for CLSID\{CLSID_XX}
  2308.         wnsprintf(szKey, ARRAYSIZE(szKey), TEXT("CLSID\%s"), szBuf);
  2309.         if (RegOpenKey(HKEY_CLASSES_ROOT, szKey, &hkey)!=ERROR_SUCCESS)
  2310.         {
  2311.             TraceMsg(DM_WARNING, "_GetUserCLSIDKey RegOpenKey(%s) failed", szKey);
  2312.             // I don't trust RegOpenKey.
  2313.             hkey = NULL;
  2314.         }
  2315.     }
  2316.     return hkey;
  2317. }
  2318. BOOL _GetAppHackKey(LPCTSTR pszProgID, DWORD* pdwData)
  2319. {
  2320.     BOOL fSuccess = FALSE;
  2321.     HKEY hkey;
  2322.     if (RegOpenKey(HKEY_CLASSES_ROOT, pszProgID, &hkey)==ERROR_SUCCESS)
  2323.     {
  2324.         DWORD dwType;
  2325.         DWORD cbSize = SIZEOF(*pdwData);
  2326.         if (RegQueryValueEx(hkey, TEXT("BrowserFlags"), NULL,
  2327.             &dwType, (LPBYTE)pdwData, &cbSize)==ERROR_SUCCESS
  2328.             && (dwType==REG_DWORD || (dwType==REG_BINARY && cbSize==SIZEOF(*pdwData))))
  2329.         {
  2330.             fSuccess = TRUE;
  2331.         }
  2332.         else
  2333.         {
  2334.             //
  2335.             // Unlike IE3, we make it absolutely sure that the type of object
  2336.             // has either "DocObject" key or "BrowseInPlace" key under the
  2337.             // ProgID. We can't rely on QI(IID_IOleDocument) because MFC 4.2
  2338.             // has a bug and returns S_OK to it. As far as I know, MS-Paint
  2339.             // and OmniPage pro are affected by this. We could individually
  2340.             // address each of them, but it's probably impossible to catch
  2341.             // all. This change has a small risk of breaking existing DocObject
  2342.             // server which does not have neither key. If we find such a
  2343.             // server, we'll address those individually (which is much easier
  2344.             // than covering all MFC apps). (SatoNa)
  2345.             //
  2346.             TCHAR ach[MAX_PATH];
  2347.             LONG cb;
  2348.             BOOL fBrowsable = FALSE;
  2349.             if ((cb=SIZEOF(ach)) && RegQueryValue(hkey, TEXT("DocObject"), ach, &cb) == ERROR_SUCCESS)
  2350.                 fBrowsable = TRUE;
  2351.             else if ((cb=SIZEOF(ach)) && RegQueryValue(hkey, TEXT("BrowseInPlace"), ach, &cb) == ERROR_SUCCESS)
  2352.                 fBrowsable = TRUE;
  2353.             if (!fBrowsable) {
  2354.                 TraceMsg(DM_WARNING, "_GetAppHackKey this is neither DocObject or BrowseInPlace");
  2355.                 *pdwData = BROWSERFLAG_DONTINPLACE;
  2356.             }
  2357.         }
  2358.         RegCloseKey(hkey);
  2359.     }
  2360.     return fSuccess;
  2361. }
  2362. void GetAppHackFlags(IOleObject* pole, const CLSID* pclsid, DWORD* pdwAppHack)
  2363. {
  2364.     HKEY hkey = _GetUserCLSIDKey(pole, pclsid, pdwAppHack);
  2365.     if (hkey)
  2366.     {
  2367.         TCHAR szValue[MAX_PATH];
  2368.         LONG cb = SIZEOF(szValue);
  2369.         if (RegQueryValue(hkey, TEXT("ProgID"), szValue, &cb) == ERROR_SUCCESS)
  2370.         {
  2371.             //
  2372.             // First, check if we have an BrowserFlags flag in the registry.
  2373.             // If there is, use it. Otherwise, try hard-coded progIDs as
  2374.             // we did in IE 3.0
  2375.             //
  2376.             _GetAppHackKey(szValue, pdwAppHack);
  2377.             if (!(*pdwAppHack & BROWSERFLAG_REPLACE)) {
  2378.                 typedef struct _APPHACK {
  2379.                     LPCTSTR pszProgID;
  2380.                     DWORD   dwAppHack;
  2381.                 } APPHACK;
  2382.                 //
  2383.                 // We no longer need to disable in-place activation of
  2384.                 // MS-PAINT because we look for "BrowseInPlace" or
  2385.                 // "DocObject" key
  2386.                 //
  2387.                 // { "Paint.Picture", BROWSERFLAG_DONTINPLACE },
  2388.                 //
  2389.                 const static APPHACK s_aah[] = {
  2390.                     { TEXT("Excel.Sheet.5"), BROWSERFLAG_OPENCOPY },
  2391.                     { TEXT("Excel.Chart.5"), BROWSERFLAG_OPENCOPY },
  2392.                     { TEXT("SoundRec"), BROWSERFLAG_OPENVERB },
  2393.                     { TEXT("Word.Document.6"), BROWSERFLAG_SETHOSTNAME },
  2394.                     { TEXT("Word.Document.8"), BROWSERFLAG_DONTUIDEACTIVATE | BROWSERFLAG_SETHOSTNAME },
  2395.                     { TEXT("PowerPoint.Show.8"), BROWSERFLAG_DONTUIDEACTIVATE | BROWSERFLAG_PRINTPROMPTUI },
  2396.                     { TEXT("Excel.Sheet.8"), BROWSERFLAG_DONTDEACTIVATEMSOVIEW | BROWSERFLAG_INITNEWTOKEEP },
  2397.                     { TEXT("Excel.Chart.8"), BROWSERFLAG_DONTDEACTIVATEMSOVIEW | BROWSERFLAG_INITNEWTOKEEP },
  2398.                     { TEXT("ABCFlowCharter6.Document"), BROWSERFLAG_DONTINPLACE },
  2399.                     { TEXT("ABCFlowCharter7.Document"), BROWSERFLAG_DONTINPLACE },
  2400.                     { TEXT("FlowCharter7.Document"), BROWSERFLAG_DONTINPLACE },
  2401.                     { TEXT("ChannelFile"), BROWSERFLAG_DONTAUTOCLOSE },
  2402.                     { TEXT("Visio.Drawing.5"), BROWSERFLAG_ENABLETOOLSBTN | BROWSERFLAG_SAVEASWHENCLOSING },
  2403.                     { TEXT("Visio.Drawing.4"), BROWSERFLAG_ENABLETOOLSBTN | BROWSERFLAG_SAVEASWHENCLOSING }
  2404.                 };
  2405.                 const static TCHAR s_ActiveMoveCtx[] = TEXT("AMOVIE.ActiveMovieControl");
  2406.                 if (!StrCmpN(szValue, s_ActiveMoveCtx, ARRAYSIZE(s_ActiveMoveCtx)-1))
  2407.                 {
  2408.                     *pdwAppHack = BROWSERFLAG_DONTAUTOCLOSE;
  2409.                 }
  2410.                 else
  2411.                 {
  2412.                     for (int i=0; i<ARRAYSIZE(s_aah); i++) {
  2413.                         if (StrCmp(szValue, s_aah[i].pszProgID)==0)
  2414.                         {
  2415.                             *pdwAppHack |= s_aah[i].dwAppHack;
  2416.                             break;
  2417.                         }
  2418.                     }
  2419.                 }
  2420.             }
  2421.             TraceMsg(DM_BINDAPPHACK, "_GetAppHack ProgID=%s, *pdwAppHack=%x",
  2422.                      szValue, *pdwAppHack);
  2423.         } else {
  2424.             TraceMsg(DM_BINDAPPHACK, "_GetAppHack RegQueryValue(ProgID) failed");
  2425.         }
  2426.         RegCloseKey(hkey);
  2427.     }
  2428. }
  2429. DWORD CDocObjectHost::_GetAppHack(void)
  2430. {
  2431.     ASSERT(_pole);
  2432.     if (!_fHaveAppHack && _pole)
  2433.     {
  2434.         _dwAppHack = 0;     // Assume no hack
  2435.         _fHaveAppHack = TRUE;
  2436.         ::GetAppHackFlags(_pole, NULL, &_dwAppHack);
  2437.     }
  2438.     return _pole ? _dwAppHack : 0;
  2439. }
  2440. void CDocObjectHost::_PostBindAppHack(void)
  2441. {
  2442.     _GetAppHack();
  2443.     if (_fAppHackForExcel()) {
  2444.         _AppHackForExcel95();
  2445.     }
  2446. }
  2447. //
  2448. // This member binds to the object specified by a moniker.
  2449. //
  2450. HRESULT CDocObjectHost::_BindSync(IMoniker* pmk, IBindCtx* pbc, IShellView* psvPrev)
  2451. {
  2452.     ASSERT(pbc || !_pole);
  2453.     HRESULT hres = S_OK;
  2454.     ASSERT(_pole==NULL);
  2455.     // Check if we are in the middle of asynchronous binding
  2456.     if (_bsc._fBinding) {
  2457.         // Yes, wait until it's done or cancled/stopped
  2458.         URLMSG(TEXT("_Bind called in the middle of async-binding. Wait in a message loop"));
  2459.         while(_bsc._fBinding) {
  2460.            MSG msg;
  2461.            if (GetMessage(&msg, NULL, 0, 0)) {
  2462.                TranslateMessage(&msg);
  2463.                DispatchMessage(&msg);
  2464.            }
  2465.         }
  2466.         if (!_pole) {
  2467.             hres = E_FAIL;      // BUGBUG: Get the error code from OnStopBinding
  2468.         }
  2469.     } else {
  2470.         // No, bind synchronously
  2471.         URLMSG(TEXT("_Bind. Performing syncronous binding"));
  2472.         hres = pmk->BindToObject(pbc, NULL, IID_IOleObject, (LPVOID*)&_pole);
  2473.     }
  2474.     TraceMsg(0, "sdv TR : _Bind -- pmk->BindToObject(IOleObject) returned %x", hres);
  2475.     _OnBound(hres);
  2476.     return hres;
  2477. }
  2478. void CDocObjectHost::_OnBound(HRESULT hres)
  2479. {
  2480.     if (SUCCEEDED(hres)) {
  2481.         _PostBindAppHack();
  2482.         _InitOleObject();
  2483.     }
  2484. }
  2485. //
  2486. //  This function returns TRUE if the specified file's open command is
  2487. // associated with "explorer.exe" or "iexplore.exe".
  2488. //
  2489. // NOTES: It does not check if the "open" command is actually the default
  2490. //  or not, but that's sufficient in 99.99 cases.
  2491. //
  2492. BOOL IsAssociatedWithIE(LPCWSTR szPath)
  2493. {
  2494.     LPCTSTR pszExtension = PathFindExtension(szPath);
  2495.     BOOL bRet = FALSE;
  2496.     CHAR szBuf[MAX_PATH];
  2497.     CHAR szExt[_MAX_EXT];
  2498.     //
  2499.     // SHVerbExistsN is ansi only.
  2500.     //
  2501.     SHUnicodeToAnsi(pszExtension, szExt, ARRAYSIZE(szExt));
  2502.     if (SHVerbExistsNA(szExt, "open", szBuf, SIZECHARS (szBuf))) {
  2503.         TraceMsg(TF_SHDBINDING, "IsAssociatedWithIE(%s) found %s as open command", szPath, szBuf);
  2504.         LPCSTR pszFound;
  2505.         if ( (pszFound=StrStrIA(szBuf, IEXPLORE_EXE))
  2506.              || (pszFound=StrStrIA(szBuf, EXPLORER_EXE)) ) {
  2507.             if (pszFound==szBuf || *AnsiPrev(szBuf, pszFound)=='\') {
  2508.                 bRet = TRUE;
  2509.             }
  2510.         }
  2511.     }
  2512.     TraceMsg(DM_SELFASC, "IsAssociatedWithIE(%s) returning %d", szPath, bRet);
  2513.     return bRet;
  2514. }
  2515. UINT CDocObjectHost::_PicsBlockingDialog(LPCTSTR pszURL)
  2516. {
  2517.     pszURL = _pszPicsURL;
  2518.     TraceMsg(DM_PICS, "CDOH::_PicsBlockingDialog(%s)", pszURL);
  2519.     _StartPicsRootQuery(pszURL);
  2520.     _fDrawBackground = TRUE;
  2521.     ::InvalidateRect(_hwnd, NULL, TRUE);    /* mega cheesy, but only way to get browser window erased */
  2522.     /* This message loop is used to block in non-HTML cases, where we really
  2523.      * want to block the download process until ratings are checked.  In the
  2524.      * HTML case, this function is never called until the wait flags are all
  2525.      * clear, so the message loop is skipped and we go straight to the denial
  2526.      * dialog.
  2527.      */
  2528.     while (_fbPicsWaitFlags) {
  2529.         TraceMsg(DM_PICS, "CDOH::_PicsBlockingDialog entering msg loop, waitflags=%x", (DWORD)_fbPicsWaitFlags);
  2530.         MSG msg;
  2531.         if (GetMessage(&msg, NULL, 0, 0)) {
  2532.             TranslateMessage(&msg);
  2533.             DispatchMessage(&msg);
  2534.         }
  2535.     }
  2536.     if (!_fPicsAccessAllowed) {
  2537.         TraceMsg(DM_PICS, "CDOH::_PicsBlockingDialog, access denied");
  2538.         // If this is silent-mode (no UI == screensaver), always deny access
  2539.         // without any dialog.
  2540.         BOOL fFrameIsSilent = FALSE;    // Assume non-silent
  2541.         _GetOfflineSilent(NULL, &fFrameIsSilent);
  2542.         if (fFrameIsSilent) {
  2543.             TraceMsg(DM_PICS, "CDOH::_PicsBlockingDialog access denied in silent mode, aborting");
  2544.             return IDCANCEL;
  2545.         }
  2546.         _EnableModeless(FALSE);
  2547.         HRESULT hres = S_OK;
  2548.         IOleCommandTarget *pcmdtTop;
  2549.         if (SUCCEEDED(QueryService(SID_STopLevelBrowser, IID_IOleCommandTarget, (void **)&pcmdtTop))) {
  2550.             VARIANTARG v = { 0 };
  2551.             v.vt = VT_INT_PTR;
  2552.             v.byref = _pRatingDetails;
  2553.             hres = pcmdtTop->Exec(&CGID_ShellDocView, SHDVID_PICSBLOCKINGUI, 0, &v, NULL);
  2554.             pcmdtTop->Release();
  2555.         }
  2556.         UINT uRet = (hres == S_OK) ? IDOK : IDCANCEL;
  2557.         _EnableModeless(TRUE);
  2558.         _fPicsAccessAllowed = (uRet == IDOK);
  2559.         TraceMsg(DM_PICS, "CDOH::_PicsBlockingDialog returning %d", uRet);
  2560.         return uRet;
  2561.     }
  2562.     else {
  2563.         TraceMsg(DM_PICS, "CDOH::_PicsBlockingDialog, access allowed");
  2564.         return IDOK;
  2565.     }
  2566. }
  2567. HRESULT CDocObjectHost::_MayHaveVirus(REFCLSID rclsid)
  2568. {
  2569.     //
  2570.     // We'll call this function twice if the file is associated
  2571.     // with a bogus CLSID (such as ImageComposer).
  2572.     //
  2573.     if (_fConfirmed) {
  2574.         TraceMsg(TF_SHDAPPHACK, "CDOH::_MayHaveVirus called twice. Return S_OK");
  2575.         return S_OK;
  2576.     }
  2577.     TraceMsg(TF_SHDPROGRESS, "DOH::_MayHaveVirus called");
  2578.     LPWSTR pwzProgID = NULL;
  2579.     HRESULT hresT = E_FAIL;
  2580.     if (SUCCEEDED(ProgIDFromCLSID(rclsid, &pwzProgID)))
  2581.     {
  2582.         if (StrCmpI(pwzProgID, TEXT("htmlfile"))!=0
  2583.             && StrCmpI(pwzProgID, TEXT("htmlfile_FullWindowEmbed"))!=0
  2584.             && StrCmpI(pwzProgID, TEXT("mhtmlfile"))!=0
  2585.             && StrCmpI(pwzProgID, TEXT("xmlfile"))!=0
  2586.             && StrCmpI(pwzProgID, TEXT("xslfile"))!=0)
  2587.         {
  2588.             TCHAR szURL[MAX_URL_STRING];
  2589.             TCHAR * pszURL = szURL;
  2590.             hresT = _GetCurrentPage(szURL, ARRAYSIZE(szURL), TRUE);
  2591.             if (SUCCEEDED(hresT)) {
  2592.                 UINT uRet = IDOK;
  2593.                 if (_fbPicsWaitFlags || !_fPicsAccessAllowed) {
  2594.                     _fbPicsWaitFlags &= ~(PICS_WAIT_FOR_INDOC | PICS_WAIT_FOR_END);   /* indoc ratings only on htmlfile */
  2595.                     TraceMsg(DM_PICS, "CDOH::_MayHaveVirus found non-HTML, waitflags now %x", (DWORD)_fbPicsWaitFlags);
  2596.                     uRet = _PicsBlockingDialog(szURL);
  2597.                 }
  2598.                 if (uRet == IDOK) {
  2599.                     TraceMsg(TF_SHDPROGRESS, "DOH::_MayHaveVirus calling MayOpenSafeDialogOpenDialog(%s)", pwzProgID);
  2600.                     if (_bsc._pszRedirectedURL && *_bsc._pszRedirectedURL)
  2601.                         pszURL = _bsc._pszRedirectedURL;
  2602.                     uRet = MayOpenSafeOpenDialog(_hwnd, pwzProgID, pszURL, NULL, NULL, _uiCP);
  2603.                     _fCalledMayOpenSafeDlg = TRUE;
  2604.                 }
  2605.                 switch(uRet) {
  2606.                  case IDOK:
  2607.                     //
  2608.                     // Set this flag to avoid poppping this dialog box twice.
  2609.                     //
  2610.                     _fConfirmed = TRUE;
  2611.                     break;  // continue download
  2612.                  case IDD_SAVEAS:
  2613.                     CDownLoad_OpenUI(_pmkCur, _bsc._pbc, FALSE, TRUE, NULL, NULL, NULL, NULL, NULL, _bsc._pszRedirectedURL, _uiCP);
  2614.                     // fall through to abort binding.
  2615.                  case IDCANCEL:
  2616.                     hresT = HRESULT_FROM_WIN32(ERROR_CANCELLED);
  2617.                     break;
  2618.                 }
  2619.             } else {
  2620.                 TraceMsg(DM_ERROR, "DOH::_MayHaveVirus _GetCurrentPage failed %x", hresT);
  2621.             }
  2622.         } else {
  2623.             TraceMsg(TF_SHDPROGRESS, "DOH::_MayHaveVirus this is htmlfile -- don't call MayOpenSafeDialogOpenDialog");
  2624.             _fPicsBlockLate = TRUE;
  2625.         }
  2626.         OleFree(pwzProgID);
  2627.     }
  2628.     return hresT;
  2629. }
  2630. STDMETHODIMP CDocObjectHost::SaveObject(void)
  2631. {
  2632.     TraceMsg(0, "sdv TR: CDOV::SaveObject called");
  2633.     // BUGBUG: Implemente it later.
  2634.     return S_OK;
  2635. }
  2636. STDMETHODIMP CDocObjectHost::GetMoniker(DWORD dwAssign,
  2637.     DWORD dwWhichMoniker,
  2638.     IMoniker **ppmk)
  2639. {
  2640.     HRESULT hres = E_INVALIDARG;
  2641.     *ppmk = NULL;
  2642.     TraceMsg(TF_SHDBINDING, "CDOH::GetMoniker called dwWhichMoniker=%x", dwWhichMoniker);
  2643.     switch(dwWhichMoniker)
  2644.     {
  2645.     case OLEWHICHMK_OBJREL:
  2646.     case OLEWHICHMK_OBJFULL:
  2647.         if (_pmkCur)
  2648.         {
  2649.             *ppmk = _pmkCur;
  2650.             _pmkCur->AddRef();
  2651.             hres = S_OK;
  2652.         }
  2653.         else
  2654.         {
  2655.             hres = E_UNEXPECTED;
  2656.         }
  2657.         break;
  2658.     }
  2659.     return hres;
  2660. }
  2661. STDMETHODIMP CDocObjectHost::GetContainer(
  2662.     IOleContainer **ppContainer)
  2663. {
  2664.     // BUGBUG: According to CKindel, we should implement this method
  2665.     //  as the way for a DocObject to access IDispatch interface of
  2666.     //  the container (i.e., frame). I'm currently thinking leaving
  2667.     //  all it's non-IUnknown memeber unimplemented. If there is no
  2668.     //  need to enumerates objects, we can simply QI from IShellBrowser
  2669.     //  to IOleContainer and return it. (SatoNa)
  2670.     //
  2671.     // NOTE: If trident calls this after DestroyHostWindow, we have nothing
  2672.     //  to give out. Hopefully this is not bad. (MikeSh)
  2673.     TraceMsg(0, "sdv TR: CDOV::GetContainer called");
  2674.     if (_psb)
  2675.         return _psb->QueryInterface(IID_IOleContainer, (LPVOID*)ppContainer);
  2676.     return E_FAIL;
  2677. }
  2678. STDMETHODIMP CDocObjectHost::ShowObject(void)
  2679. {
  2680.     TraceMsg(0, "sdv TR: CDOV::ShowObject called");
  2681.     return E_NOTIMPL;   // As specified in Kraig's document
  2682. }
  2683. STDMETHODIMP CDocObjectHost::OnShowWindow(BOOL fShow)
  2684. {
  2685.     TraceMsg(TF_SHDUIACTIVATE, "DOH::OnShowWindow(%d) called (this=%x)", fShow, this);
  2686.     return E_NOTIMPL;   // As specified in Kraig's document
  2687. }
  2688. STDMETHODIMP CDocObjectHost::RequestNewObjectLayout(void)
  2689. {
  2690.     TraceMsg(0, "sdv TR: CDOV::RequestNewObjectLayout called");
  2691.     return E_NOTIMPL;   // As specified in Kraig's document
  2692. }
  2693. //
  2694. //  This is the standard way for non-active embedding to access
  2695. // the IHlinkFrame interface. We happened to use our QI to implement
  2696. // this, but the semantics of QueryService is different from QI.
  2697. // It does not necessary return the same object.
  2698. //
  2699. HRESULT CDocObjectHost::QueryService(REFGUID guidService, REFIID riid, void **ppvObj)
  2700. {
  2701.     // In order for the context menu to work correctly inside IFrames, we
  2702.     // need to fail a certain query ONLY for IFrames on desktop.
  2703.     if(!IsEqualGUID(guidService, CLSID_HTMLDocument) || !_IsImmediateParentDesktop(this, _psp))
  2704.     {
  2705.         //
  2706.         //  Delegate ISP to the _psb.
  2707.         //
  2708.         if (_psb && _psp)
  2709.             return _psp->QueryService(guidService, riid, ppvObj);
  2710.     }
  2711.     *ppvObj = NULL;
  2712.     return E_NOINTERFACE;
  2713. }
  2714. /*----------------------------------------------------------
  2715. Purpose: Remove the submenu(s) that are in _hmenuFrame
  2716.          from _hmenuBrowser.
  2717. */
  2718. void CDocObjectHost::_RemoveFrameSubMenus(void)
  2719. {
  2720.     HMENU hmenu;
  2721.     ASSERT(IS_VALID_HANDLE(_hmenuBrowser, MENU));
  2722.     ASSERT(IS_VALID_HANDLE(_hmenuFrame, MENU));
  2723.     // The file menu in _hmenuBrowser consists of the file menu from
  2724.     // _hmenuFrame and IShellBrowser.  The part added by _hmenuFrame
  2725.     // includes a submenu (Send To), which must be removed before
  2726.     // _hmenuBrowser is destroyed.
  2727.     // We could just explicitly remove the Send To submenu.  But to
  2728.     // prevent the expensive bug hunt that it took to find this in the
  2729.     // first place, we're going to iterate thru the menu and, for
  2730.     // any submenus that belong to our template, we'll remove them.
  2731.     int citemFile = 0;
  2732.     UINT nID = 0;
  2733.     // Get the count of menu items in our template's File menu and
  2734.     // the ID of the first menu item.
  2735.     hmenu = GetMenuFromID(_hmenuFrame, FCIDM_MENU_FILE);
  2736.     if (hmenu)
  2737.     {
  2738.         citemFile = GetMenuItemCount(hmenu);
  2739.         nID = GetMenuItemID(hmenu, 0);
  2740.     }
  2741.     // Now look at the browser menu's File menu and, starting at
  2742.     // nID, remove any submenus.
  2743.     hmenu = GetMenuFromID(_hmenuBrowser, FCIDM_MENU_FILE);
  2744.     if (hmenu)
  2745.     {
  2746.         int citem = GetMenuItemCount(hmenu);
  2747.         int iTop;
  2748.         int i;
  2749.         // Where does our template file menu start?
  2750.         for (iTop = 0; iTop < citem; iTop++)
  2751.         {
  2752.             if (GetMenuItemID(hmenu, iTop) == nID)
  2753.             {
  2754.                 // Start at where our template file menu ends and work up
  2755.                 for (i = iTop + citemFile - 1; 0 < citemFile ; i--, citemFile--)
  2756.                 {
  2757.                     HMENU hmenuSub = GetSubMenu(hmenu, i);
  2758.                     if (hmenuSub)
  2759.                         RemoveMenu(hmenu, i, MF_BYPOSITION);
  2760.                 }
  2761.                 break;
  2762.             }
  2763.         }
  2764.     }
  2765. }
  2766. /*----------------------------------------------------------
  2767. Purpose: Destroy the browser menu.
  2768. */
  2769. HRESULT CDocObjectHost::_DestroyBrowserMenu(void)
  2770. {
  2771.     TraceMsg(TF_SHDUIACTIVATE, "DOH::_DestroyBrowserMenu called");
  2772.     if (_hmenuBrowser) {
  2773.         // First remove any submenus that are held by other menus,
  2774.         // so we don't blow them away.
  2775.         _RemoveFrameSubMenus();
  2776.         if (EVAL(_psb)) {
  2777.             _psb->RemoveMenusSB(_hmenuBrowser);
  2778.         }
  2779.         DestroyMenu(_hmenuBrowser);
  2780.         _hmenuBrowser = NULL;
  2781.     }
  2782.     return S_OK;
  2783. }
  2784. HRESULT CDocObjectHost::_CreateBrowserMenu(LPOLEMENUGROUPWIDTHS pmw)
  2785. {
  2786.     TraceMsg(TF_SHDUIACTIVATE, "DOH::_CreateBrowserMenu called");
  2787.     if (_hmenuBrowser) {
  2788.         return S_OK;
  2789.     }
  2790.     _hmenuBrowser = CreateMenu();
  2791.     if (!_hmenuBrowser) {
  2792.         return E_OUTOFMEMORY;
  2793.     }
  2794.     HRESULT hres = E_FAIL;
  2795.     // Allow IShellBrowser a chance to add its menus
  2796.     if (EVAL(_psb))
  2797.         hres = _psb->InsertMenusSB(_hmenuBrowser, pmw);
  2798.     // HACK: Win95 explorer returns E_NOTIMPL
  2799.     if (hres==E_NOTIMPL) {
  2800.         hres = S_OK;
  2801.     }
  2802.     if (SUCCEEDED(hres)) {
  2803.         // Load our menu if not loaded yet
  2804.         if (!_hmenuFrame)
  2805.         {
  2806.             _hmenuFrame = LoadMenu(MLGetHinst(), MAKEINTRESOURCE(MID_FOCUS));
  2807.         }
  2808.         // Get the "File" sub-menu from the shell browser.
  2809.         MENUITEMINFO mii;
  2810.         mii.cbSize = sizeof(mii);
  2811.         mii.fMask = MIIM_SUBMENU;
  2812.         if (GetMenuItemInfo(_hmenuBrowser, FCIDM_MENU_FILE, FALSE, &mii))
  2813.         {
  2814.             HMENU hmenuFileBrowse = mii.hSubMenu;
  2815.             // Merge our menuitems into this submenu.
  2816.             if (_hmenuFrame)
  2817.             {
  2818.                 MENUITEMINFO miiItem;
  2819.                 miiItem.cbSize = SIZEOF(MENUITEMINFO);
  2820.                 miiItem.fMask = MIIM_SUBMENU;
  2821.                 if (GetMenuItemInfo(_hmenuFrame, FCIDM_MENU_FILE, FALSE, &miiItem))
  2822.                 {
  2823.                     TCHAR szItem[128];
  2824.                     HMENU hmenuFileT = miiItem.hSubMenu;
  2825.                     UINT citem = GetMenuItemCount(hmenuFileT);
  2826.                     for (int i=citem-1; i>=0 ; i--)
  2827.                     {
  2828.                         // We need to reset for each item.
  2829.                         miiItem.fMask = MIIM_STATE | MIIM_ID | MIIM_SUBMENU | MIIM_CHECKMARKS | MIIM_TYPE | MIIM_DATA;
  2830.                         miiItem.fType = MFT_STRING;
  2831.                         miiItem.cch = ARRAYSIZE(szItem);
  2832.                         miiItem.dwTypeData = szItem;
  2833.                         miiItem.dwItemData = 0;
  2834.                         if (GetMenuItemInfo(hmenuFileT, i, TRUE, &miiItem)) {
  2835.                             InsertMenuItem(hmenuFileBrowse, 0, TRUE, &miiItem);
  2836.                         }
  2837.                     }
  2838.                 }
  2839.             }
  2840.         }
  2841.         else
  2842.         {
  2843.             TraceMsg(TF_SHDUIACTIVATE, "DOH::_CreateBrowseMenu parent has no File menu (it's probably a browser OC)");
  2844.             ASSERT(0); // DocObject in OC is not supposed to call InsertMenus.
  2845.         }
  2846.     }
  2847.     DEBUG_CODE( _DumpMenus(TEXT("after _CreateBrowserMenu"), TRUE); )
  2848.     return hres;
  2849. }
  2850. //
  2851. // IOleInPlaceFrame::InsertMenus equivalent
  2852. //
  2853. HRESULT CDocObjectHost::_InsertMenus(
  2854.     /* [in] */ HMENU hmenuShared,
  2855.     /* [out][in] */ LPOLEMENUGROUPWIDTHS lpMenuWidths)
  2856. {
  2857.     HRESULT hres = S_OK;
  2858.     int nMenuOffset = 0;
  2859.     TraceMsg(TF_SHDUIACTIVATE, "DOH::InsertMenus called (this=%x)", this);
  2860.     // Assume error (no menu merge)
  2861.     lpMenuWidths->width[0] = 0;
  2862.     lpMenuWidths->width[2] = 0;
  2863.     lpMenuWidths->width[4] = 0;
  2864.     lpMenuWidths->width[5] = 0;
  2865.     // be extra safe and don't attempt menu merging if we're not top level
  2866.     if (_fHaveParentSite)
  2867.         return S_OK;
  2868.     OLEMENUGROUPWIDTHS mw = { {0} };
  2869.     hres = _CreateBrowserMenu(&mw);
  2870.     if (FAILED(hres)) {
  2871.         TraceMsg(DM_ERROR, "DOH::InsertMenus _CreateBrpwserMenu failed");
  2872.         return hres;
  2873.     }
  2874.     // Get the "File" sub-menu from the shell browser.
  2875.     MENUITEMINFO mii;
  2876.     TCHAR szSubMenu[128];
  2877.     mii.cbSize = SIZEOF(mii);
  2878.     mii.fMask = MIIM_SUBMENU|MIIM_TYPE|MIIM_ID;
  2879.     mii.cch = ARRAYSIZE(szSubMenu);
  2880.     mii.dwTypeData = szSubMenu;
  2881.     if (EVAL(GetMenuItemInfo(_hmenuBrowser, FCIDM_MENU_FILE, FALSE, &mii)))
  2882.     {
  2883.         ASSERT(szSubMenu == mii.dwTypeData);
  2884.         InsertMenuItem(hmenuShared, nMenuOffset++, TRUE, &mii);
  2885.         lpMenuWidths->width[0] = 1;
  2886.     }
  2887.     // Note that we need to re-initialize mii
  2888.     mii.cch = ARRAYSIZE(szSubMenu);
  2889.     if (EVAL(GetMenuItemInfo(_hmenuBrowser, FCIDM_MENU_EXPLORE, FALSE, &mii)))
  2890.     {
  2891.         // BUGBUG: GetMenuItemInfo is recursive (why?).  The item it retrieves 
  2892.         // for FCIDM_MENU_EXPLORE can either be the top level Go menu, or if that
  2893.         // does not exist (NT5 case), it returns the Go To submenu of View.  
  2894.         // 
  2895.         // Code has been added in in the SetMenu implementations of Shell Browser 
  2896.         // and Dochost to detect the second case, because the menu dispatch list
  2897.         // does not recognize this kind of menu merging (80734).
  2898.         DeleteMenu(mii.hSubMenu, FCIDM_PREVIOUSFOLDER, MF_BYCOMMAND);
  2899.         InsertMenuItem(hmenuShared, nMenuOffset++, TRUE, &mii);
  2900.         lpMenuWidths->width[4]++;
  2901.     }
  2902.     mii.cch = ARRAYSIZE(szSubMenu);
  2903.     if (EVAL(GetMenuItemInfo(_hmenuBrowser, FCIDM_MENU_FAVORITES, FALSE, &mii)))
  2904.     {
  2905.         InsertMenuItem(hmenuShared, nMenuOffset++, TRUE, &mii);
  2906.         lpMenuWidths->width[4]++;
  2907.     }
  2908.     if (_hmenuFrame)
  2909.     {
  2910.         // Micro-merge the help menu.
  2911.         mii.cch = ARRAYSIZE(szSubMenu);
  2912.         if (EVAL(GetMenuItemInfo(_hmenuFrame, FCIDM_MENU_HELP, FALSE, &mii)))
  2913.         {
  2914.             InsertMenuItem(hmenuShared, nMenuOffset++, TRUE, &mii);
  2915.             lpMenuWidths->width[5]++;
  2916.         }
  2917.     }
  2918.     DEBUG_CODE( _DumpMenus(TEXT("after InsertMenus"), TRUE); )
  2919.     return hres;
  2920. }
  2921. /*----------------------------------------------------------
  2922. Purpose: Different objects may add their own Help menu (like
  2923.          Word and Excel).  This function detects if the object
  2924.          added its own help menu, or if it added items to our
  2925.          help menu, or if it is just using our help menu.
  2926.          If they added their own help menu, we remove ours.
  2927. */
  2928. void CDocObjectHost::_CompleteHelpMenuMerge(HMENU hmenu)
  2929. {
  2930.     HMENU hmenuHelp;
  2931.     MENUITEMINFO mii;
  2932.     TCHAR szSubMenu[80];
  2933.     mii.cbSize = SIZEOF(mii);
  2934.     mii.fMask = MIIM_SUBMENU;
  2935.     // see if they added anything to our menu
  2936.     if (GetMenuItemInfo(_hmenuFrame, FCIDM_MENU_HELP, FALSE, &mii))
  2937.     {
  2938.         hmenuHelp = mii.hSubMenu;
  2939.         int iMenuCount = GetMenuItemCount(mii.hSubMenu);
  2940.         // Did the number of items in the help menu change?
  2941.         if (iMenuCount != HELP_ITEM_COUNT) {
  2942.             // Yes; that means they added something.  This has been micro-merged.
  2943.             _hmenuMergedHelp = mii.hSubMenu;
  2944.             _hmenuObjHelp = GetSubMenu(mii.hSubMenu, iMenuCount -1);
  2945.             goto Bail;
  2946.         }
  2947.         // Our menu didn't change.  Now find out if they added their own
  2948.         // help menu or if we ARE the help.  If they added their own, we need
  2949.         // to remove our help menu.
  2950.         _hmenuMergedHelp = NULL;
  2951.         _hmenuObjHelp = NULL;
  2952.         int iCount = GetMenuItemCount(hmenu) - 1;
  2953.         int i;
  2954.         for (i = iCount ; i >= 0 ; i--) {
  2955.             mii.fMask = MIIM_SUBMENU|MIIM_TYPE;
  2956.             mii.cch = ARRAYSIZE(szSubMenu);
  2957.             mii.dwTypeData = szSubMenu;
  2958.             if (GetMenuItemInfo(hmenu, i, TRUE, &mii)) {
  2959.                 if (mii.hSubMenu == hmenuHelp) {
  2960.                     BOOL bRemove = FALSE;
  2961.                     if (iCount != i) {
  2962.                         // if we're not the last one, then we're not it
  2963.                         bRemove = TRUE;
  2964.                     } else {
  2965.                         // if we are the last one see if the help menu was added
  2966.                         // right before us
  2967.                         TCHAR szMenuTitle[80];
  2968.                         mii.cch = ARRAYSIZE(szMenuTitle);
  2969.                         mii.dwTypeData = szMenuTitle;
  2970.                         if (GetMenuItemInfo(hmenu, i-1, TRUE, &mii)) {
  2971.                             if (!StrCmpI(szMenuTitle, szSubMenu)) {
  2972.                                 // same menu string yank ours
  2973.                                 bRemove = TRUE;
  2974.                             }
  2975.                         }
  2976.                     }
  2977.                     if (bRemove) {
  2978.                         RemoveMenu(hmenu, i, MF_BYPOSITION);
  2979.                     }
  2980.                 }
  2981.             }
  2982.         }
  2983.     }
  2984. Bail:;
  2985.     DEBUG_CODE( _DumpMenus(TEXT("after _CompleteHelpMenuMerge"), TRUE); )
  2986. }
  2987. //
  2988. // IOleInPlaceFrame::SetMenu equivalent
  2989. //
  2990. HRESULT CDocObjectHost::_SetMenu(
  2991.     /* [in] */ HMENU hmenuShared,           OPTIONAL
  2992.     /* [in] */ HOLEMENU holemenu,           OPTIONAL
  2993.     /* [in] */ HWND hwndActiveObject)
  2994. {
  2995.     TraceMsg(TF_SHDUIACTIVATE, "DOH::SetMenus(%x) called (this=%x)",
  2996.              hmenuShared, this);