#include "shellprv.h" #include #include "ole2dup.h" #include "defview.h" #include "bookmk.h" #include #include "defviewp.h" #include "ids.h" #include #include #include "mshtml.h" #include #include // get the CLSID definitions, the bits are built into shguidp.lib #include "basefvcb.h" #include "clsobj.h" #define TF_FOCUS TF_ALLOC CSFVFrame::~CSFVFrame() { ATOMICRELEASE(_pvoActive); ATOMICRELEASE(_pActive); ATOMICRELEASE(_pDocView); ATOMICRELEASE(_pOleObj); if (_dwConnectionCookie) _RemoveReadyStateNotifyCapability(); ATOMICRELEASE(_pOleObjNew); } // Default implementation of SFVM_GETVIEWDATA is to grab the info // from SFVM_GETVIEWS. We no longer provide a default implementation // of that message, so if SFVM_GETVIEWS fails, we manually look in: // shellex\ExtShellFolderViews\{VID_WebView}\PersistMoniker // HRESULT CCallback::OnGetWebViewTemplate(DWORD pv, UINT uViewMode, SFVM_WEBVIEW_TEMPLATE_DATA* pvit) { CDefView* pView = IToClass(CDefView, _cCallback, this); // try the old message pvit->szWebView[0] = 0; // For now, use the old one - clean up soon... SFVM_VIEWINFO_DATA data; data.bWantWebview = TRUE; HRESULT hr = pView->CallCB(SFVM_GETVIEWINFO, (WPARAM)uViewMode, (LPARAM)&data); if (SUCCEEDED(hr)) { hr = StringCchCopy(pvit->szWebView, ARRAYSIZE(pvit->szWebView), data.szWebView); } else { if (FAILED(hr)) hr = TryLegacyGetViews(pvit); } return hr; } void CleanUpDocView(IOleDocumentView* pDocView, IOleObject* pOleObj) { pDocView->UIActivate(FALSE); IOleInPlaceObject* pipo; if (SUCCEEDED(pOleObj->QueryInterface(IID_PPV_ARG(IOleInPlaceObject, &pipo)))) { pipo->InPlaceDeactivate(); pipo->Release(); } pDocView->CloseView(0); pDocView->SetInPlaceSite(NULL); pDocView->Release(); } void CSFVFrame::_CleanupOldDocObject( ) { //See if we have already switched to the new Ole Obj if (_pDocView) { //Save the current values first! IOleObject *pOleObjOld = _pOleObj; IOleDocumentView *pDocViewOld = _pDocView; _pDocView = NULL; _pOleObj = NULL; CleanUpDocView(pDocViewOld, pOleObjOld); _CleanUpOleObjAndDt(pOleObjOld); SetActiveObject(NULL, NULL); } if (_dwConnectionCookie) _RemoveReadyStateNotifyCapability(); _CleanupNewOleObj(); } void CSFVFrame::_CleanUpOleObj(IOleObject* pOleObj) { pOleObj->Close(OLECLOSE_NOSAVE); pOleObj->SetClientSite(NULL); pOleObj->Release(); } void CSFVFrame::_CleanUpOleObjAndDt(IOleObject* pOleObj) { _CleanUpOleObj(pOleObj); // If we have a wrapping droptarget, release it now. IDropTarget* pdtTemp = _cSite._dt._pdtFrame; if (pdtTemp) { _cSite._dt._pdtFrame = NULL; pdtTemp->Release(); } } void CSFVFrame::_CleanupNewOleObj() { IOleObject *pOleObj = _pOleObjNew; if (pOleObj) { _pOleObjNew = NULL; _CleanUpOleObj(pOleObj); } } void DisableActiveDesktop() { SHELLSTATE ss; // Disable this settings in the registry! ss.fDesktopHTML = FALSE; SHGetSetSettings(&ss, SSF_DESKTOPHTML, TRUE); // Write back the new // Tell the user that we have just disabled the active desktop! ShellMessageBox(HINST_THISDLL, NULL, MAKEINTRESOURCE(IDS_HTMLFILE_NOTFOUND), MAKEINTRESOURCE(IDS_DESKTOP), MB_OK | MB_ICONEXCLAMATION | MB_SETFOREGROUND); } HRESULT CSFVFrame::_GetCurrentZone(IOleObject *pOleObj, VARIANT *pvar) { HRESULT hr = S_OK; CDefView* pView = IToClass(CDefView, _cFrame, this); VariantInit(pvar); V_VT(pvar) = VT_EMPTY; IOleCommandTarget* pct; if (pOleObj && SUCCEEDED(GetCommandTarget(&pct))) { hr = pct->Exec(&CGID_Explorer, SBCMDID_MIXEDZONE, 0, 0, pvar); pct->Release(); } else { V_VT(pvar) = VT_UI4; V_UI4(pvar) = URLZONE_LOCAL_MACHINE; // Default is "My Computer" pView->CallCB(SFVM_GETZONE, 0, (LPARAM)&V_UI4(pvar)); } if (V_VT(pvar) == VT_UI4) // We were able to figure out what zone we are in { } // the zone is just fine else if (V_VT(pvar) == VT_NULL) // MSHTML has figured us to be in a mixed zone V_UI4(pvar) = ZONE_MIXED; else // We don't have zone info V_UI4(pvar) = ZONE_UNKNOWN; V_VT(pvar) = VT_UI4; return hr; } HRESULT CSFVFrame::_UpdateZonesStatusPane(IOleObject *pOleObj) { CDefView* pView = IToClass(CDefView, _cFrame, this); VARIANT var; HRESULT hr = _GetCurrentZone(pOleObj, &var); // Tell CShellbrowser to show the zone stuff in the second pane ASSERT(V_VT(&var) == VT_UI4); // The "2" means "second pane" V_UI4(&var) = MAKELONG(2, V_UI4(&var)); IUnknown_Exec(pView->_psb, &CGID_Explorer, SBCMDID_MIXEDZONE, 0, &var, NULL); ASSERT((V_VT(&var) == VT_I4) || (V_VT(&var) == VT_UI4) || (V_VT(&var) == VT_EMPTY) || (V_VT(&var) == VT_NULL)); return hr; } HRESULT CSFVFrame::_GetHTMLBackgroundColor(COLORREF *pclr) { HRESULT hr = E_FAIL; if (_bgColor == CLR_INVALID) hr = IUnknown_HTMLBackgroundColor(_pOleObj, &_bgColor); else hr = S_OK; // cached if (SUCCEEDED(hr)) *pclr = _bgColor; return hr; } #ifdef DEBUG BOOL_PTR CALLBACK s_WVDlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_INITDIALOG: { RECT rc; if (GetWindowRect(hWnd, &rc)) { HWND hEdit = CreateWindow(TEXT("edit"), NULL, WS_CHILD|WS_VISIBLE|ES_MULTILINE|ES_AUTOVSCROLL, 10, 10, (rc.right-rc.left)-20, (rc.bottom-rc.top)-20, hWnd, NULL, NULL, 0); if (hEdit) { SetWindowTextA(hEdit, (LPCSTR)lParam); } } SetWindowText(hWnd, TEXT("WebView Content (DEBUG)")); break; } case WM_COMMAND: switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDCANCEL: EndDialog(hWnd, 0); break; } break; } return FALSE; } void CSFVFrame::_ShowWebViewContent() { CDefView* pView = IToClass(CDefView, _cCallback, this); HRESULT hr = E_FAIL; LPSTR pszFree = NULL; if (_pOleObj) { IStream* pstm = SHCreateMemStream(NULL, 0); if (pstm) { VARIANTARG vt; vt.vt = VT_UNKNOWN; vt.punkVal = pstm; #define IDM_DEBUG_GETTREETEXT 7102 // stolen from mshtml\src\include\privcid.h if (SUCCEEDED(IUnknown_Exec(_pOleObj, &CGID_MSHTML, IDM_DEBUG_GETTREETEXT, 0, &vt, NULL))) { STATSTG stg; if (SUCCEEDED(pstm->Stat(&stg, 0))) { pszFree = (LPSTR)LocalAlloc(LPTR, stg.cbSize.LowPart+2); // stream doesn't include NULL... if (pszFree) { pstm->Seek(g_li0, STREAM_SEEK_SET, NULL); pstm->Read(pszFree, stg.cbSize.LowPart, NULL); } } } pstm->Release(); } } // I'm not sure if the output from Trident is always ANSI, but right now that seems to be the case. LPSTR pszMessage = pszFree ? pszFree : "Error collecting WebView content"; DialogBoxParam(HINST_THISDLL, MAKEINTRESOURCE(DLG_DRV_HWTAB), pView->_hwndView, s_WVDlgProc, (LPARAM)pszFree); if (pszFree) LocalFree(pszFree); } #endif // ready state complete has occured, ready to do the switch thing. HRESULT CSFVFrame::_SwitchToNewOleObj() { HRESULT hr = S_OK; if (!_fSwitchedToNewOleObj && _pOleObjNew) { _fSwitchedToNewOleObj = TRUE; CDefView* pView = IToClass(CDefView, _cFrame, this); //Save the current values first! IOleObject *pOleObjOld = _pOleObj; IOleDocumentView *pDocViewOld = _pDocView; IOleObject *pOleObjNew = _pOleObjNew; _pDocView = NULL; _pOleObj = NULL; _pOleObjNew = NULL; //If we already have one, destroy it! if (pDocViewOld) { //To prevent flashing, set the flag that avoids the painting SendMessage(pView->_hwndView, WM_SETREDRAW, 0, 0); CleanUpDocView(pDocViewOld, pOleObjOld); _CleanUpOleObjAndDt(pOleObjOld); SetActiveObject(NULL, NULL); //Is the ViewWindow still around? if (IsWindow(pView->_hwndView)) { SendMessage(pView->_hwndView, WM_SETREDRAW, TRUE, 0); if (pView->_hwndListview) InvalidateRect(pView->_hwndListview, NULL, TRUE); } } // HACK: We need to set the host names for Word to force embedding mode pOleObjNew->SetHostNames(L"1", L"2"); OleRun(pOleObjNew); IOleDocumentView* pDocView = NULL; IOleDocument* pDocObj; hr = pOleObjNew->QueryInterface(IID_PPV_ARG(IOleDocument, &pDocObj)); if (SUCCEEDED(hr)) { hr = pDocObj->CreateView(&_cSite, NULL, 0, &pDocView); if (SUCCEEDED(hr)) { RECT rcView; pDocView->SetInPlaceSite(&_cSite); GetClientRect(pView->_hwndView, &rcView); hr = pOleObjNew->DoVerb(OLEIVERB_INPLACEACTIVATE, NULL, &_cSite, (UINT)-1, pView->_hwndView, &rcView); if (FAILED(hr)) CleanUpDocView(pDocView, pOleObjNew); } pDocObj->Release(); } if (SUCCEEDED(hr)) { hr = S_OK; // S_FALSE -> S_OK, needed? ASSERT(_pOleObj == NULL); ASSERT(_pDocView == NULL); _pDocView = pDocView; pDocView->AddRef(); // copy hold the ref for our copy _pOleObj = pOleObjNew; _pOleObjNew = NULL; RECT rcClient; // Make sure the new view is the correct size GetClientRect(pView->_hwndView, &rcClient); SetRect(&rcClient); // If this is desktop, then we need to see the listview's background color if (pView->_IsDesktop()) { _bgColor = CLR_INVALID; pView->_SetFolderColors(); //Tell the listview about color change! } } else { if (pView->_IsDesktop()) PostMessage(pView->_hwndView, WM_DSV_DISABLEACTIVEDESKTOP, 0, 0); // Clean up if necessary _CleanupNewOleObj(); } ATOMICRELEASE(pDocView); } return hr; } // IBindStatusCallback impl HRESULT CSFVFrame::CBindStatusCallback::QueryInterface(REFIID riid, void **ppv) { static const QITAB qit[] = { QITABENT(CSFVFrame::CBindStatusCallback, IBindStatusCallback), // IID_IBindStatusCallback QITABENT(CSFVFrame::CBindStatusCallback, IServiceProvider), // IID_IServiceProvider { 0 } }; return QISearch(this, qit, riid, ppv); } ULONG CSFVFrame::CBindStatusCallback::AddRef(void) { CSFVFrame* pFrame = IToClass(CSFVFrame, _bsc, this); return pFrame->AddRef(); } ULONG CSFVFrame::CBindStatusCallback::Release(void) { CSFVFrame* pFrame = IToClass(CSFVFrame, _bsc, this); return pFrame->Release(); } HRESULT CSFVFrame::CBindStatusCallback::OnStartBinding(DWORD grfBSCOption, IBinding *pib) { return S_OK; } HRESULT CSFVFrame::CBindStatusCallback::GetPriority(LONG *pnPriority) { *pnPriority = NORMAL_PRIORITY_CLASS; return S_OK; } HRESULT CSFVFrame::CBindStatusCallback::OnLowResource(DWORD reserved) { return S_OK; } HRESULT CSFVFrame::CBindStatusCallback::OnProgress(ULONG ulProgress, ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR szStatusText) { return S_OK; } HRESULT CSFVFrame::CBindStatusCallback::OnStopBinding(HRESULT hr, LPCWSTR pszError) { return S_OK; } HRESULT CSFVFrame::CBindStatusCallback::GetBindInfo(DWORD *grfBINDINFOF, BINDINFO *pbindinfo) { return S_OK; } HRESULT CSFVFrame::CBindStatusCallback::OnDataAvailable(DWORD grfBSCF, DWORD dwSize, FORMATETC *pformatetc, STGMEDIUM *pstgmed) { return S_OK; } HRESULT CSFVFrame::CBindStatusCallback::OnObjectAvailable(REFIID riid, IUnknown *punk) { return S_OK; } HRESULT CSFVFrame::CBindStatusCallback::QueryService(REFGUID guidService, REFIID riid, void **ppv) { CSFVFrame* pFrame = IToClass(CSFVFrame, _bsc, this); if (IsEqualGUID(guidService, SID_DefView)) { // QueryService from a pluggable protocol/mime filter winds up // here during the Bind, but Trident re-binds during F5 processing // so the QueryService winds up directly at _cSite. Handle all // SID_DefView processing there so there's no discrepencies. // return pFrame->_cSite.QueryService(guidService, riid, ppv); } *ppv = NULL; return E_FAIL; } HRESULT CSFVFrame::_CreateNewOleObjFromMoniker(LPCWSTR wszMoniker, IOleObject **ppOleObj) { CDefView* pView = IToClass(CDefView, _cFrame, this); HRESULT hr = E_FAIL; IOleObject* pOleObj = NULL; if (wszMoniker[0]) { LPWSTR pwszExtension = PathFindExtensionW(wszMoniker); // Only htt's are allowed if (StrCmpIW(pwszExtension, L".htt") == 0) { IMoniker * pMoniker; hr = CreateURLMoniker(NULL, wszMoniker, &pMoniker); if (SUCCEEDED(hr)) { IBindCtx * pbc; hr = CreateBindCtx(0, &pbc); if (SUCCEEDED(hr)) { // NOTE: We only support synchronous bind here! // // // Associate the client site as an object parameter to this // bind context so that Trident can pick it up while processing // IPersistMoniker::Load(). // pbc->RegisterObjectParam(WSZGUID_OPID_DocObjClientSite, SAFECAST((&_cSite), IOleClientSite*)); RegisterBindStatusCallback(pbc, SAFECAST(&_bsc, IBindStatusCallback*), 0, 0); hr = pMoniker->BindToObject(pbc, NULL, IID_PPV_ARG(IOleObject, &pOleObj)); if (FAILED(hr)) { if (pView->_IsDesktop()) PostMessage(pView->_hwndView, WM_DSV_DISABLEACTIVEDESKTOP, 0, 0); } RevokeBindStatusCallback(pbc, SAFECAST(&_bsc, IBindStatusCallback*)); pbc->Release(); } pMoniker->Release(); } } } *ppOleObj = pOleObj; return hr; } HRESULT CSFVFrame::_GetCurrentWebViewMoniker(LPWSTR pszCurrentMoniker, DWORD cchCurrentMoniker) { HRESULT hr = StringCchCopy(pszCurrentMoniker, cchCurrentMoniker, _szCurrentWebViewMoniker); if (SUCCEEDED(hr)) { if (pszCurrentMoniker[0] == TEXT('\0')) { hr = E_FAIL; } } return hr; } // Show Web View content for the specified template/moniker // HRESULT CSFVFrame::ShowWebView(LPCWSTR pszMoniker) { if (GetSystemMetrics(SM_CLEANBOOT)) return E_FAIL; // kill previous readystatenotify and cleanup old pending hoster. // // TODO: move into _CleanupNewOleObj if (_dwConnectionCookie) _RemoveReadyStateNotifyCapability(); // Clean up if a new Ole object is already awaiting ready state if (_pOleObjNew) _CleanupNewOleObj(); // TODO: rename to _CleanupPendingView ASSERT(_dwConnectionCookie == NULL); ASSERT(_pOleObjNew == NULL); // Create and initialize the new old object! IOleObject *pOleObj; HRESULT hr = _CreateNewOleObjFromMoniker(pszMoniker, &pOleObj); if (SUCCEEDED(hr) && pOleObj) { if (!_pOleObjNew) { CDefView* pView = IToClass(CDefView, _cFrame, this); hr = StringCchCopy(_szCurrentWebViewMoniker, ARRAYSIZE(_szCurrentWebViewMoniker), pszMoniker); if (SUCCEEDED(hr)) { hr = _ShowExtView_Helper(pOleObj); // takes ownership of pOleObj (yuck) pOleObj->SetClientSite(&_cSite); pView->ShowHideListView(); // we just changed IsWebView } else { pOleObj->Release(); } } else { // Yikes! We got reentered during the creation of the OleObj, blow away the object // and just return. pOleObj->Release(); } } return hr; } HRESULT CSFVFrame::HideWebView() { CDefView* pView = IToClass(CDefView, _cFrame, this); _szCurrentWebViewMoniker[0] = 0; _CleanupOldDocObject(); pView->ShowHideListView(); // we just changed IsWebView return S_OK; } HRESULT CSFVFrame::_ShowExtView_Helper(IOleObject* pOleObj) { HRESULT hr; // Don't leak the old object, it must be NULL at this point ASSERT(_pOleObjNew == NULL); // Save the new ole object _pOleObjNew = pOleObj; _fSwitchedToNewOleObj = FALSE; // Establish to connection point to receive the READYSTATE notification. if (!_SetupReadyStateNotifyCapability()) { _SwitchToNewOleObj(); _UpdateZonesStatusPane(_pOleObj); // If the object doesn't support readystate (or it's already interactive) // then we return S_OK to indicate synchronous switch. hr = S_OK; } else { // We're waiting on the docobj, we'll call _SwitchToNewOleObj // when it goes interactive... hr = S_FALSE; } return hr; } BOOL CSFVFrame::_SetupReadyStateNotifyCapability() { // By default we don't have gray-flash communication BOOL fSupportsReadystate = FALSE; // Sanity Check if (!_pOleObjNew) return fSupportsReadystate; // Check for proper readystate support BOOL fReadyStateOK = FALSE; IDispatch *pdisp; if (SUCCEEDED(_pOleObjNew->QueryInterface(IID_PPV_ARG(IDispatch, &pdisp)))) { EXCEPINFO exInfo; VARIANTARG va = {0}; DISPPARAMS dp = {0}; if (SUCCEEDED(pdisp->Invoke(DISPID_READYSTATE, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET, &dp, &va, &exInfo, NULL))) { if ((va.vt == VT_I4) && (va.lVal < READYSTATE_COMPLETE)) { fReadyStateOK = TRUE; } } pdisp->Release(); } if (fReadyStateOK) { // Check and Set-Up IPropertyNotifySink if (SUCCEEDED(ConnectToConnectionPoint(SAFECAST(this, IPropertyNotifySink*), IID_IPropertyNotifySink, TRUE, _pOleObjNew, &_dwConnectionCookie, NULL))) { fSupportsReadystate = TRUE; _fReadyStateInteractiveProcessed = FALSE; _fReadyStateComplete = FALSE; _pOleObjReadyState = _pOleObjNew; _pOleObjReadyState->AddRef(); } } return fSupportsReadystate; } BOOL CSFVFrame::_RemoveReadyStateNotifyCapability() { BOOL fRet = FALSE; if (_dwConnectionCookie) { ASSERT(_pOleObjReadyState); ConnectToConnectionPoint(NULL, IID_IPropertyNotifySink, FALSE, _pOleObjReadyState, &_dwConnectionCookie, NULL); ATOMICRELEASE(_pOleObjReadyState); fRet = TRUE; _dwConnectionCookie = 0; } return fRet; } HWND CSFVFrame::GetExtendedViewWindow() { HWND hwnd; if (SUCCEEDED(IUnknown_GetWindow(_pDocView, &hwnd))) return hwnd; if (_pActive && SUCCEEDED(_pActive->GetWindow(&hwnd))) return hwnd; return NULL; } STDMETHODIMP CSFVSite::QueryInterface(REFIID riid, void **ppv) { static const QITAB qit[] = { QITABENT(CSFVSite, IOleInPlaceSite), QITABENTMULTI(CSFVSite, IOleWindow, IOleInPlaceSite), QITABENT(CSFVSite, IOleClientSite), QITABENT(CSFVSite, IOleDocumentSite), QITABENT(CSFVSite, IServiceProvider), QITABENT(CSFVSite, IOleCommandTarget), QITABENT(CSFVSite, IDocHostUIHandler), QITABENT(CSFVSite, IOleControlSite), QITABENT(CSFVSite, IDispatch), QITABENT(CSFVSite, IInternetSecurityManager), { 0 } }; return QISearch(this, qit, riid, ppv); } STDMETHODIMP_(ULONG) CSFVSite::AddRef() { return IToClass(CSFVFrame, _cSite, this)->AddRef(); } STDMETHODIMP_(ULONG) CSFVSite::Release() { return IToClass(CSFVFrame, _cSite, this)->Release(); } // IOleWindow STDMETHODIMP CSFVSite::GetWindow(HWND *phwnd) { CSFVFrame* pFrame = IToClass(CSFVFrame, _cSite, this); return pFrame->GetWindow(phwnd); } STDMETHODIMP CSFVSite::ContextSensitiveHelp(BOOL fEnterMode) { CSFVFrame* pFrame = IToClass(CSFVFrame, _cSite, this); return pFrame->ContextSensitiveHelp(fEnterMode); } // IInternetSecurityManager HRESULT CSFVSite::ProcessUrlAction(LPCWSTR pwszUrl, DWORD dwAction, BYTE * pPolicy, DWORD cbPolicy, BYTE * pContext, DWORD cbContext, DWORD dwFlags, DWORD dwReserved) { HRESULT hr = INET_E_DEFAULT_ACTION; if ((((URLACTION_ACTIVEX_MIN <= dwAction) && (URLACTION_ACTIVEX_MAX >= dwAction)) || ((URLACTION_SCRIPT_MIN <= dwAction) && (URLACTION_SCRIPT_MAX >= dwAction))) && pContext && (sizeof(CLSID) == cbContext) && (IsEqualIID(*(CLSID *) pContext, CLSID_WebViewFolderContents) || (IsEqualIID(*(CLSID *) pContext, CLSID_ThumbCtl)))) { if (EVAL(pPolicy) && EVAL(sizeof(DWORD) == cbPolicy)) { *pPolicy = (DWORD) URLPOLICY_ALLOW; hr = S_OK; } else { hr = E_INVALIDARG; } } return hr; } // IOleInPlaceSite STDMETHODIMP CSFVSite::CanInPlaceActivate(void) { return S_OK; } STDMETHODIMP CSFVSite::OnInPlaceActivate(void) { TraceMsg(TF_FOCUS, "sfvf.oipa: _pAct=%x", IToClass(CSFVFrame, _cSite, this)->_pActive); IToClass(CSFVFrame, _cSite, this)->_uState = SVUIA_ACTIVATE_NOFOCUS; return S_OK; } STDMETHODIMP CSFVSite::OnUIActivate(void) { CSFVFrame* pFrame = IToClass(CSFVFrame, _cSite, this); CDefView* pView = IToClass(CDefView, _cFrame._cSite, this); HRESULT hr = pView->_OnViewWindowActive(); pFrame->_uState = SVUIA_ACTIVATE_FOCUS; TraceMsg(TF_FOCUS, "sfvf.ouia: _pAct'=%x", IToClass(CSFVFrame, _cSite, this)->_pActive); return hr; } STDMETHODIMP CSFVSite::GetWindowContext( /* [out] */ IOleInPlaceFrame **ppFrame, /* [out] */ IOleInPlaceUIWindow **ppDoc, /* [out] */ LPRECT lprcPosRect, /* [out] */ LPRECT lprcClipRect, /* [out][in] */ LPOLEINPLACEFRAMEINFO lpFrameInfo) { CSFVFrame* pFrame = IToClass(CSFVFrame, _cSite, this); CDefView* pView = IToClass(CDefView, _cFrame, pFrame); *ppFrame = pFrame; pFrame->AddRef(); *ppDoc = NULL; // indicating that doc window == frame window GetClientRect(pView->_hwndView, lprcPosRect); *lprcClipRect = *lprcPosRect; lpFrameInfo->fMDIApp = FALSE; lpFrameInfo->hwndFrame = pView->_hwndView; // Yes, should be view window lpFrameInfo->haccel = NULL; lpFrameInfo->cAccelEntries = 0; return S_OK; } STDMETHODIMP CSFVSite::Scroll(SIZE scrollExtant) { return S_OK; } STDMETHODIMP CSFVSite::OnUIDeactivate(BOOL fUndoable) { return S_OK; } STDMETHODIMP CSFVSite::OnInPlaceDeactivate(void) { return S_OK; } STDMETHODIMP CSFVSite::DiscardUndoState(void) { return S_OK; } STDMETHODIMP CSFVSite::DeactivateAndUndo(void) { return S_OK; } STDMETHODIMP CSFVSite::OnPosRectChange(LPCRECT lprcPosRect) { return S_OK; } // IOleClientSite STDMETHODIMP CSFVSite::SaveObject(void) { return S_OK; } STDMETHODIMP CSFVSite::GetMoniker(DWORD dwAssign, DWORD dwWhichMoniker, IMoniker **ppmk) { return E_FAIL; } STDMETHODIMP CSFVSite::GetContainer(IOleContainer **ppContainer) { *ppContainer = NULL; return E_NOTIMPL; } STDMETHODIMP CSFVSite::ShowObject(void) { return S_OK; } STDMETHODIMP CSFVSite::OnShowWindow(BOOL fShow) { return S_OK; } STDMETHODIMP CSFVSite::RequestNewObjectLayout(void) { return S_OK; } // IOleDocumentSite STDMETHODIMP CSFVSite::ActivateMe(IOleDocumentView *pviewToActivate) { CSFVFrame* pFrame = IToClass(CSFVFrame, _cSite, this); CDefView* pView = IToClass(CDefView, _cFrame, pFrame); if (pView->_uState == SVUIA_ACTIVATE_FOCUS) pviewToActivate->UIActivate(TRUE); pviewToActivate->Show(TRUE); return S_OK; } // // IOleCommandTarget stuff - just forward to _psb // STDMETHODIMP CSFVSite::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD rgCmds[], OLECMDTEXT *pcmdtext) { CSFVFrame* pFrame = IToClass(CSFVFrame, _cSite, this); CDefView* pView = IToClass(CDefView, _cFrame, pFrame); IOleCommandTarget* pct; HRESULT hr = OLECMDERR_E_UNKNOWNGROUP; if (SUCCEEDED(pView->_psb->QueryInterface(IID_PPV_ARG(IOleCommandTarget, &pct)))) { hr = pct->QueryStatus(pguidCmdGroup, cCmds, rgCmds, pcmdtext); pct->Release(); } return hr; } STDMETHODIMP CSFVSite::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANTARG *pvarargIn, VARIANTARG *pvarargOut) { CSFVFrame* pFrame = IToClass(CSFVFrame, _cSite, this); CDefView* pView = IToClass(CDefView, _cFrame, pFrame); HRESULT hr = OLECMDERR_E_UNKNOWNGROUP; if (pguidCmdGroup) { if (IsEqualIID(*pguidCmdGroup, CGID_DefView)) { hr = E_INVALIDARG; if (pvarargOut) { VariantClear(pvarargOut); TCHAR szPath[MAX_PATH]; switch (nCmdID) { case DVCMDID_GETTHISDIRPATH: case DVCMDID_GETTHISDIRNAME: hr = pView->_GetNameAndFlags(nCmdID == DVCMDID_GETTHISDIRPATH ? SHGDN_FORPARSING : SHGDN_INFOLDER, szPath, ARRAYSIZE(szPath), NULL); if (SUCCEEDED(hr)) { hr = InitVariantFromStr(pvarargOut, szPath); } break; case DVCMDID_GETTEMPLATEDIRNAME: if (pFrame->IsWebView()) { WCHAR wszMoniker[MAX_PATH]; if (SUCCEEDED(pFrame->_GetCurrentWebViewMoniker(wszMoniker, ARRAYSIZE(wszMoniker))) || SUCCEEDED(pView->_GetWebViewMoniker(wszMoniker, ARRAYSIZE(wszMoniker)))) { hr = InitVariantFromStr(pvarargOut, wszMoniker); } } break; } } return hr; } else if (IsEqualIID(*pguidCmdGroup, CGID_Explorer)) { if ((SBCMDID_UPDATETRAVELLOG == nCmdID) && !pView->_fCanActivateNow) { // // We get a spurious UPDATETRAVELLOG command because we have enabled // CDefviewPersistHistory to call the MSHTML IPersistHistory in webview // mode. // This seems to be the best place to fix this as the call stack // below this call is trident, and the call stack above this call is // browser code. // // The travellog is subsequently updated correctly when // CBaseBrowser2::ActivatePendingView is called. // return S_OK; } } // fall through on other cmd groups... } else if ((OLECMDID_SETTITLE == nCmdID) && !pView->_fCanActivateNow) { // NT #282632: Don't forward this message if we aren't the active view. return S_OK; } IOleCommandTarget* pct; if (SUCCEEDED(pView->_psb->QueryInterface(IID_PPV_ARG(IOleCommandTarget, &pct)))) { hr = pct->Exec(pguidCmdGroup, nCmdID, nCmdexecopt, pvarargIn, pvarargOut); pct->Release(); } return hr; } //*** IOleControlSite { //*** IsVK_TABCycler -- is key a TAB-equivalent // ENTRY/EXIT // dir 0 if not a TAB, non-0 if a TAB // NOTES // NYI: -1 for shift+tab, 1 for tab // int IsVK_TABCycler(MSG *pMsg) { int nDir = 0; if (!pMsg) return nDir; if (pMsg->message != WM_KEYDOWN) return nDir; if (! (pMsg->wParam == VK_TAB || pMsg->wParam == VK_F6)) return nDir; nDir = (GetKeyState(VK_SHIFT) < 0) ? -1 : 1; #ifdef KEYBOARDCUES SendMessage(GetParent(pMsg->hwnd), WM_CHANGEUISTATE, MAKEWPARAM(UIS_CLEAR, UISF_HIDEFOCUS), 0); #endif return nDir; } //*** CSFVSite::TranslateAccelerator (IOCS::TranslateAccelerator) // NOTES // (following comment/logic stolen from shdocvw/dochost.cpp) // trident (or any other DO that uses IOCS::TA) calls us back when TABing // off the last link. to handle it, we flag it for our original caller // (IOIPAO::TA), and then pretend we handled it by telling trident S_OK. // trident returns S_OK to IOIPAO::TA, which checks the flag and says // 'trident did *not* handle it' by returning S_FALSE. that propagates // way up to the top where it sees it was a TAB so it does a CycleFocus. // // that's how we do it when we're top-level. when we're a frameset, we // need to do it the 'real' way, sending it up to our parent IOCS. HRESULT CSFVSite::TranslateAccelerator(MSG *pMsg, DWORD grfModifiers) { if (IsVK_TABCycler(pMsg)) { CSFVFrame* pFrame = IToClass(CSFVFrame, _cSite, this); CDefView* pView = IToClass(CDefView, _cFrame, pFrame); TraceMsg(TF_FOCUS, "csfvs::IOCS::TA(wParam=VK_TAB) ret _fCycleFocus=TRUE hr=S_OK (lie)"); // defer it, set flag for cdv::IOIPAO::TA, and pretend we handled it ASSERT(!pView->_fCycleFocus); pView->_fCycleFocus = TRUE; return S_OK; } //ASSERT(!pView->_fCycleFocus); return S_FALSE; } // } // IServiceProvider HRESULT CSFVSite::QueryService(REFGUID guidService, REFIID riid, void ** ppv) { CSFVFrame* pFrame = IToClass(CSFVFrame, _cSite, this); CDefView* pView = IToClass(CDefView, _cFrame, pFrame); *ppv = NULL; HRESULT hr = E_FAIL; if (guidService == SID_DefView) { if (riid == IID_IDefViewFrame && pView->_IsDesktop()) { return E_FAIL; } // Try site QI hr = QueryInterface(riid, ppv); } if (FAILED(hr)) { // Delegate to defview QS hr = pView->QueryService(guidService, riid, ppv); if (FAILED(hr)) { // Look for IID_IInternetSecurityManager if (guidService == IID_IInternetSecurityManager) { ASSERT(riid == IID_IInternetSecurityManager); hr = QueryInterface(riid, ppv); } } } return hr; } HRESULT CSFVSite::Invoke(DISPID dispidMember, REFIID iid, LCID lcid, WORD wFlags, DISPPARAMS *pdispparams, VARIANT *pVarResult, EXCEPINFO *pexcepinfo, UINT *puArgErr) { if (!pVarResult) return E_INVALIDARG; //Get pointer to the defview CSFVFrame* pFrame = IToClass(CSFVFrame, _cSite, this); CDefView* pView = IToClass(CDefView, _cFrame, pFrame); // We handle the query of whether we want to show images, ourselves. if (wFlags == DISPATCH_PROPERTYGET) { switch (dispidMember) { case DISPID_AMBIENT_DLCONTROL: { // Do the following only if this is NOT the desktop. // (Because Desktop is in offline mode, it should // return DLCTL_OFFLINEIFNOTCONNECTED flag). The following code // should be executed only for NON-desktop folders. if (!(pView->_IsDesktop())) { pVarResult->vt = VT_I4; pVarResult->lVal = DLCTL_DLIMAGES | DLCTL_VIDEOS; return S_OK; } } } } // We delegate all other queries to shdocvw. if (!_peds) { IUnknown_QueryService(pView->_psb, IID_IExpDispSupport, IID_PPV_ARG(IExpDispSupport, &_peds)); } if (!_peds) return E_NOTIMPL; return _peds->OnInvoke(dispidMember, iid, lcid, wFlags, pdispparams, pVarResult, pexcepinfo, puArgErr); } HRESULT CHostDropTarget::QueryInterface(REFIID riid, void **ppv) { static const QITAB qit[] = { QITABENT(CHostDropTarget, IDropTarget), // IID_IDropTarget { 0 } }; return QISearch(this, qit, riid, ppv); } ULONG CHostDropTarget::AddRef(void) { CSFVSite* pcsfvs = IToClass(CSFVSite, _dt, this); return pcsfvs->AddRef(); } ULONG CHostDropTarget::Release(void) { CSFVSite* pcsfvs = IToClass(CSFVSite, _dt, this); return pcsfvs->Release(); } HRESULT CHostDropTarget::DragEnter(IDataObject *pdtobj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) { return _pdtFrame->DragEnter(pdtobj, grfKeyState, pt, pdwEffect); } HRESULT CHostDropTarget::DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) { return _pdtFrame->DragOver(grfKeyState, pt, pdwEffect); } HRESULT CHostDropTarget::DragLeave(void) { return _pdtFrame->DragLeave(); } HRESULT CHostDropTarget::Drop(IDataObject *pdtobj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) { return _pdtFrame->Drop(pdtobj, grfKeyState, pt, pdwEffect); } STDMETHODIMP CSFVFrame::QueryInterface(REFIID riid, void **ppv) { static const QITAB qit[] = { QITABENTMULTI(CSFVFrame, IOleWindow, IOleInPlaceFrame), // IID_IOleWindow QITABENTMULTI(CSFVFrame, IOleInPlaceUIWindow, IOleInPlaceFrame), // IID_IOleInPlaceUIWindow QITABENT(CSFVFrame, IOleInPlaceFrame), // IID_IOleInPlaceFrame QITABENT(CSFVFrame, IAdviseSink), // IID_IAdviseSink QITABENT(CSFVFrame, IPropertyNotifySink), // IID_IPropertyNotifySink { 0 } }; return QISearch(this, qit, riid, ppv); } STDMETHODIMP_(ULONG) CSFVFrame::AddRef() { CDefView* pView = IToClass(CDefView, _cFrame, this); return pView->AddRef(); } STDMETHODIMP_(ULONG) CSFVFrame::Release() { CDefView* pView = IToClass(CDefView, _cFrame, this); return pView->Release(); } // IOleWindow STDMETHODIMP CSFVFrame::GetWindow(HWND *phwnd) { CDefView* pView = IToClass(CDefView, _cFrame, this); return pView->GetWindow(phwnd); } STDMETHODIMP CSFVFrame::ContextSensitiveHelp(BOOL fEnterMode) { CDefView* pView = IToClass(CDefView, _cFrame, this); return pView->ContextSensitiveHelp(fEnterMode); } // IOleInPlaceUIWindow STDMETHODIMP CSFVFrame::GetBorder(LPRECT lprectBorder) { CDefView* pView = IToClass(CDefView, _cFrame, this); GetClientRect(pView->_hwndView, lprectBorder); return S_OK; } STDMETHODIMP CSFVFrame::RequestBorderSpace(LPCBORDERWIDTHS pborderwidths) { return INPLACE_E_NOTOOLSPACE; } STDMETHODIMP CSFVFrame::SetBorderSpace(LPCBORDERWIDTHS pborderwidths) { return INPLACE_E_NOTOOLSPACE; } STDMETHODIMP CSFVFrame::SetActiveObject(IOleInPlaceActiveObject *pActiveObject, LPCOLESTR pszObjName) { TraceMsg(TF_FOCUS, "sfvf.sao(pAct'=%x): _pAct=%x", pActiveObject, _pActive); if (pActiveObject != _pActive) { IAdviseSink* pOurSink = SAFECAST(this, IAdviseSink*); #ifdef DEBUG QueryInterface(IID_PPV_ARG(IAdviseSink, &pOurSink)); #endif if (_pActive) { // // if we had an OLE view object then disconnect our advise sink and // release the view object. // if (_pvoActive) { IAdviseSink *pSink; if (SUCCEEDED(_pvoActive->GetAdvise(NULL, NULL, &pSink))) { // Be polite, only blow away the advise if we're the // one who's listening if (pSink == pOurSink) { _pvoActive->SetAdvise(0, 0, NULL); } // If there was no sink, GetAdvise succeeds but sets // pSink to NULL, so need to check pSink here. if (pSink) pSink->Release(); } ATOMICRELEASE(_pvoActive); } ATOMICRELEASE(_pActive); } _pActive = pActiveObject; if (_pActive) { _pActive->AddRef(); // // try to get an OLE view object and set up an advisory connection. // if (SUCCEEDED(_pActive->QueryInterface(IID_PPV_ARG(IViewObject, &_pvoActive)))) { ASSERT(_pvoActive); _pvoActive->SetAdvise(DVASPECT_CONTENT, 0, pOurSink); } } // // since we changed the active view, tell our owner that the content // may have changed... // OnViewChange(DVASPECT_CONTENT, -1); #ifdef DEBUG ATOMICRELEASE(pOurSink); #endif } return S_OK; } // IOleInPlaceFrame STDMETHODIMP CSFVFrame::InsertMenus(HMENU hmenuShared, LPOLEMENUGROUPWIDTHS lpMenuWidths) { if (hmenuShared) { // No menu merging // or fill lpMenuWidths with 0 and return success lpMenuWidths->width[0] = 0; lpMenuWidths->width[2] = 0; lpMenuWidths->width[4] = 0; } return S_OK; } STDMETHODIMP CSFVFrame::SetMenu(HMENU hmenuShared, HOLEMENU holemenu, HWND hwndActiveObject) { return S_OK; // No menu merging } STDMETHODIMP CSFVFrame::RemoveMenus(HMENU hmenuShared) { return E_FAIL; // No menu merging } // // This one is a bit tricky. If the client wants to clear the status // area, then restore it to the original defview status area text. // // For example, in webview, MSHTML will keep clearing the status area // whenever you are not over a link, which would otherwise keep erasing // the "n object(s) selected" message from defview. // // To really clear the status area, set the text to " " instead of "". // STDMETHODIMP CSFVFrame::SetStatusText(LPCOLESTR pszStatusText) { CDefView* pView = IToClass(CDefView, _cFrame, this); if (pszStatusText && pszStatusText[0]) return pView->_psb->SetStatusTextSB(pszStatusText); pView->_UpdateStatusBar(FALSE); return S_OK; } STDMETHODIMP CSFVFrame::EnableModeless(BOOL fEnable) { CDefView* pView = IToClass(CDefView, _cFrame, this); if (pView->_IsDesktop()) { if (fEnable) { pView->_fDesktopModal = FALSE; if (pView->_fDesktopRefreshPending) //Was a refresh pending? { pView->_fDesktopRefreshPending = FALSE; //Let's do a refresh asynchronously. PostMessage(pView->_hwndView, WM_KEYDOWN, (WPARAM)VK_F5, 0); } TraceMsg(TF_DEFVIEW, "A Modal dlg is going away!"); } else { pView->_fDesktopModal = TRUE; TraceMsg(TF_DEFVIEW, "A Modal dlg is coming up for Desktop!"); } } return pView->_psb->EnableModelessSB(fEnable); } STDMETHODIMP CSFVFrame::TranslateAccelerator(LPMSG lpmsg,WORD wID) { CDefView* pView = IToClass(CDefView, _cFrame, this); return pView->_psb->TranslateAcceleratorSB(lpmsg, wID); } // IAdviseSink void CSFVFrame::OnDataChange(FORMATETC *, STGMEDIUM *) { } void CSFVFrame::OnViewChange(DWORD dwAspect, LONG lindex) { if (IsWebView() && _pvoActive) { CDefView *pView = IToClass(CDefView, _cFrame, this); pView->PropagateOnViewChange(dwAspect, lindex); } } void CSFVFrame::OnRename(IMoniker *) { } void CSFVFrame::OnSave() { } void CSFVFrame::OnClose() { if (IsWebView() && _pvoActive) { CDefView *pView = IToClass(CDefView, _cFrame, this); pView->PropagateOnClose(); } } HRESULT CSFVFrame::OnChanged(DISPID dispid) { if (DISPID_READYSTATE == dispid || DISPID_UNKNOWN == dispid) { ASSERT(_pOleObjReadyState); if (!_pOleObjReadyState) return S_OK; //Documentation says we need to return this all the time IDispatch *pdisp; if (SUCCEEDED(_pOleObjReadyState->QueryInterface(IID_PPV_ARG(IDispatch, &pdisp)))) { CDefView* pView = IToClass(CDefView, _cFrame, this); EXCEPINFO exInfo; VARIANTARG va = {0}; DISPPARAMS dp = {0}; if (EVAL(SUCCEEDED(pdisp->Invoke(DISPID_READYSTATE, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET, &dp, &va, &exInfo, NULL)) && va.vt == VT_I4)) { if (va.lVal >= READYSTATE_INTERACTIVE) { if (!_fReadyStateInteractiveProcessed) { _fReadyStateInteractiveProcessed = TRUE; // First time through this function we need to request // activation. After that, we can switch immediately. // // Switch the bit early since SHDVID_ACTIVATEMENOW calls // SHDVID_CANACTIVATENOW which checks it. // BOOL fTmp = !pView->_fCanActivateNow; pView->_fCanActivateNow = TRUE; if (fTmp) { // If we did an async CreateViewWindow2, then we // need to notify the browser that we're ready // to be activated - it will uiactivate us which // will cause us to switch. //Don't Make the View Visible, if it is in //DEACTIVATE State. The View would be made visible //during uiactivate call. - KishoreP if (pView->_uState != SVUIA_DEACTIVATE) { SetWindowPos(pView->_hwndView, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_SHOWWINDOW); } IUnknown_Exec(pView->_psb, &CGID_ShellDocView, SHDVID_ACTIVATEMENOW, NULL, NULL, NULL); } else { // Technically we only want to do this iff our view is currently // the active visible view. !fCanActivateNow => we are definitely not visible, // but _fCanActivateNow does NOT imply visible, it implies we are ready to be // made the active visible guy, and that we've requested to be made the active // visible view, but not necessarily that we *are* the active visible view. If // the previous view wasn't ready to go away, then we are in limbo. But if that's // the case, then our menus aren't merged, so there's no way the user could // switch views on us... Verify this. #ifdef DEBUG CDefView* pView = IToClass(CDefView, _cFrame, this); IShellView* psvCurrent; if (EVAL(SUCCEEDED(pView->_psb->QueryActiveShellView(&psvCurrent)))) { ASSERT(SHIsSameObject(SAFECAST(pView, IShellView2*), psvCurrent)); psvCurrent->Release(); } ASSERT(pView->_uState != SVUIA_DEACTIVATE) #endif // If we're simply switching views, go ahead // and do it. _SwitchToNewOleObj(); } if (g_dwProfileCAP & 0x00010000) StopCAP(); } } } if (va.lVal == READYSTATE_COMPLETE) { _UpdateZonesStatusPane(_pOleObjReadyState); _RemoveReadyStateNotifyCapability(); _fReadyStateComplete = TRUE; } pdisp->Release(); } } return S_OK; } HRESULT CSFVFrame::OnRequestEdit(DISPID dispid) { return E_NOTIMPL; } // randum stuff HRESULT CSFVFrame::GetCommandTarget(IOleCommandTarget** ppct) { if (_pDocView) { return _pDocView->QueryInterface(IID_PPV_ARG(IOleCommandTarget, ppct)); } *ppct = NULL; return E_FAIL; } HRESULT CSFVFrame::SetRect(LPRECT prc) { if (IsWebView() && _pDocView) return _pDocView->SetRect(prc); return E_FAIL; } HRESULT CSFVFrame::OnTranslateAccelerator(LPMSG pmsg, BOOL* pbTabOffLastTridentStop) { HRESULT hr = E_FAIL; *pbTabOffLastTridentStop = FALSE; if (IsWebView()) { if (_pActive) { hr = _pActive->TranslateAccelerator(pmsg); } else if (_pOleObj) { IOleInPlaceActiveObject* pIAO; if (SUCCEEDED(_pOleObj->QueryInterface(IID_PPV_ARG(IOleInPlaceActiveObject, &pIAO)))) { hr = pIAO->TranslateAccelerator(pmsg); pIAO->Release(); } } if (hr == S_OK) { CDefView* pView = IToClass(CDefView, _cFrame, this); if (pView->_fCycleFocus) { // we got called back by trident (IOCS::TA), but deferred it. // time to pay the piper. *pbTabOffLastTridentStop = TRUE; TraceMsg(TF_FOCUS, "sfvf::IOIPAO::OnTA piao->TA==S_OK ret _fCycleFocus=FALSE hr=S_FALSE (piper)"); pView->_fCycleFocus = FALSE; // _UIActivateIO(FALSE, NULL); hr = S_FALSE; // time to pay the piper } } ASSERT(! IToClass(CDefView, _cFrame, this)->_fCycleFocus); } return hr; } HRESULT CSFVFrame::_HasFocusIO() { TraceMsg(TF_FOCUS, "sfvf._hfio: uState=%x hr=%x", _uState, (_uState == SVUIA_ACTIVATE_FOCUS) ? S_OK : S_FALSE); if (IsWebView()) { return (_uState == SVUIA_ACTIVATE_FOCUS) ? S_OK : S_FALSE; } return S_FALSE; } HRESULT CSFVFrame::_UIActivateIO(BOOL fActivate, MSG *pMsg) { HRESULT hr; if (IsWebView() && _pOleObj) { CSFVFrame* pFrame = IToClass(CSFVFrame, _cSite, this); CDefView* pView = IToClass(CDefView, _cFrame, pFrame); LONG iVerb; RECT rcView; if (fActivate) { iVerb = OLEIVERB_UIACTIVATE; _uState = SVUIA_ACTIVATE_FOCUS; } else { iVerb = OLEIVERB_INPLACEACTIVATE; _uState = SVUIA_ACTIVATE_NOFOCUS; } if (fActivate) { GetClientRect(pView->_hwndView, &rcView); hr = _pOleObj->DoVerb(iVerb, pMsg, &_cSite, (UINT)-1, pView->_hwndView, &rcView); } else { IOleInPlaceObject *pipo; hr = _pOleObj->QueryInterface(IID_PPV_ARG(IOleInPlaceObject, &pipo)); if (SUCCEEDED(hr)) { hr = pipo->UIDeactivate(); pipo->Release(); } } ASSERT(SUCCEEDED(hr)); ASSERT(_uState == (UINT)(fActivate ? SVUIA_ACTIVATE_FOCUS : SVUIA_ACTIVATE_NOFOCUS)); TraceMsg(TF_FOCUS, "sfvf._uiaio(fAct=%d) ExtView DoVerb S_OK", fActivate); hr = S_OK; } else { TraceMsg(TF_FOCUS, "sfvf._uiaio(fAct=%d) else S_FALSE", fActivate); hr = S_FALSE; } return hr; }