/* * d o c h o s t . c p p * * Purpose: * basic implementation of a docobject host. Used by the body class to * host Trident and/or MSHTML * * History * August '96: brettm - created * * Copyright (C) Microsoft Corp. 1995, 1996. */ #include "pch.hxx" #include #include "globals.h" #include "dochost.h" /* * m a c r o s */ /* * c o n s t a n t s */ static CHAR c_szDocHostWndClass[] = "MEPAD_DocHost"; /* * t y p e d e f s */ /* * g l o b a l s */ /* * f u n c t i o n p r o t y p e s */ /* * f u n c t i o n s */ HRESULT HrInitNew(LPUNKNOWN pUnk) { LPPERSISTSTREAMINIT ppsi=0; HRESULT hr; if (!pUnk) return E_INVALIDARG; hr=pUnk->QueryInterface(IID_IPersistStreamInit, (LPVOID *)&ppsi); if (FAILED(hr)) goto error; hr = ppsi->InitNew(); error: ReleaseObj(ppsi); return hr; } CDocHost::CDocHost() { /* Not initialised Member: Initialised In: --------------------+--------------------------- */ m_cRef=1; m_hwnd=0; m_pDocView=0; m_lpOleObj=0; m_pCmdTarget=0; m_ulAdviseConnection=0; m_hwndDocObj=NULL; m_fUIActive=FALSE; m_fFocus=FALSE; m_fDownloading=FALSE; m_dhbBorder=dhbNone; m_fCycleFocus=FALSE; m_pInPlaceActiveObj = NULL; m_dwFrameWidth = 0; m_dwFrameHeight = 0; m_pInPlaceFrame =0; } CDocHost::~CDocHost() { SafeRelease(m_pInPlaceFrame); SafeRelease(m_pCmdTarget); SafeRelease(m_lpOleObj); SafeRelease(m_pDocView); SafeRelease(m_pInPlaceActiveObj); HrCloseDocObj(); } ULONG CDocHost::AddRef() { return ++m_cRef; } ULONG CDocHost::Release() { if (--m_cRef==0) { delete this; return 0; } return m_cRef; } HRESULT CDocHost::QueryInterface(REFIID riid, LPVOID *lplpObj) { if(!lplpObj) return E_INVALIDARG; *lplpObj = NULL; // set to NULL, in case we fail. if (IsEqualIID(riid, IID_IUnknown)) *lplpObj = (LPVOID)(LPUNKNOWN)(LPOLEINPLACEFRAME)this; else if (IsEqualIID(riid, IID_IOleInPlaceSite)) *lplpObj = (LPVOID)(LPOLEINPLACESITE)this; else if (IsEqualIID(riid, IID_IOleClientSite)) *lplpObj = (LPVOID)(LPOLECLIENTSITE)this; else if (IsEqualIID(riid, IID_IOleControlSite)) *lplpObj = (LPVOID)(IOleControlSite *)this; else if (IsEqualIID(riid, IID_IAdviseSink)) *lplpObj = (LPVOID)(LPADVISESINK)this; else if (IsEqualIID(riid, IID_IOleDocumentSite)) *lplpObj = (LPVOID)(LPOLEDOCUMENTSITE)this; // BUG BUGB // I don't think we need to provide this, here for debugging for now // brettm else if (IsEqualIID(riid, IID_IOleCommandTarget)) *lplpObj = (LPVOID)(LPOLECOMMANDTARGET)this; else if (IsEqualIID(riid, IID_IServiceProvider)) *lplpObj = (LPVOID)(LPSERVICEPROVIDER)this; else return E_NOINTERFACE; AddRef(); return NOERROR; } LRESULT CALLBACK CDocHost::ExtWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { LPDOCHOST pDocHost; if(msg==WM_CREATE) { pDocHost=(CDocHost *)((LPMDICREATESTRUCT)((LPCREATESTRUCT)lParam)->lpCreateParams)->lParam; if(!pDocHost) return -1; if(!pDocHost->WMCreate(hwnd)) return -1; } pDocHost = (LPDOCHOST)GetWndThisPtr(hwnd); if(pDocHost) return pDocHost->WndProc(hwnd, msg, wParam, lParam); else return DefMDIChildProc(hwnd, msg, wParam, lParam); } LRESULT CDocHost::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch(msg) { case WM_MDIACTIVATE: // if lParam is our HWND we're being activated, else deactivated if (m_pInPlaceActiveObj) m_pInPlaceActiveObj->OnDocWindowActivate((HWND)lParam == m_hwnd); break; case WM_DESTROY: HrCloseDocObj(); break; case WM_SETFOCUS: if(m_pDocView) m_pDocView->UIActivate(TRUE); break; case WM_SIZE: WMSize(LOWORD(lParam), HIWORD(lParam)); return 0; case WM_NCDESTROY: WMNCDestroy(); break; } return DefMDIChildProc(hwnd, msg, wParam, lParam); } void CDocHost::WMNCDestroy() { SetWindowLong(m_hwnd, GWL_USERDATA, NULL); m_hwnd = NULL; Release(); } BOOL CDocHost::WMCreate(HWND hwnd) { m_hwnd = hwnd; SetWindowLong(hwnd, GWL_USERDATA, (LPARAM)this); AddRef(); return SUCCEEDED(HrSubWMCreate())?TRUE:FALSE; } HRESULT CDocHost::HrCreateDocObj(LPCLSID pCLSID) { HRESULT hr=NOERROR; if(!pCLSID) return E_INVALIDARG; hr = CoCreateInstance(*pCLSID, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER, IID_IOleObject, (LPVOID *)&m_lpOleObj); if (FAILED(hr)) { MessageBox(m_hwnd, "MEPAD", "Failed to create DocObj", MB_OK); goto error; } hr = m_lpOleObj->SetClientSite((LPOLECLIENTSITE)this); if (FAILED(hr)) goto error; hr = m_lpOleObj->Advise((LPADVISESINK)this, &m_ulAdviseConnection); if (FAILED(hr)) goto error; hr = m_lpOleObj->QueryInterface(IID_IOleCommandTarget, (LPVOID *)&m_pCmdTarget); if (FAILED(hr)) goto error; hr = HrInitNew(m_lpOleObj); if (FAILED(hr)) goto error; error: return hr; } HRESULT CDocHost::HrShow() { RECT rc; HRESULT hr; GetClientRect(m_hwnd, &rc); HrGetDocObjSize(&rc); hr=m_lpOleObj->DoVerb(OLEIVERB_SHOW, NULL, (LPOLECLIENTSITE)this, 0, m_hwnd, &rc); if(FAILED(hr)) goto error; ShowWindow(m_hwnd, SW_SHOW); error: return hr; } HRESULT CDocHost::HrCloseDocObj() { LPOLEINPLACEOBJECT pInPlaceObj=0; SafeRelease(m_pInPlaceFrame); SafeRelease(m_pCmdTarget); SafeRelease(m_pInPlaceActiveObj); if(m_pDocView) { m_pDocView->UIActivate(FALSE); m_pDocView->CloseView(0); m_pDocView->SetInPlaceSite(NULL); SafeRelease(m_pDocView); } if (m_lpOleObj) { if (m_ulAdviseConnection) { m_lpOleObj->Unadvise(m_ulAdviseConnection); m_ulAdviseConnection=NULL; } // deactivate the docobj. mshtml seems more sensitive to this than Trident. if (!FAILED(m_lpOleObj->QueryInterface(IID_IOleInPlaceObject, (LPVOID*)&pInPlaceObj))) { pInPlaceObj->InPlaceDeactivate(); pInPlaceObj->Release(); } // close the ole object, but blow off changes as we have either extracted // them ourselves or don't care. m_lpOleObj->Close(OLECLOSE_NOSAVE); #ifdef DEBUG ULONG uRef; uRef= #endif m_lpOleObj->Release(); m_lpOleObj=NULL; } m_fDownloading=FALSE; m_fFocus=FALSE; m_fUIActive=FALSE; return NOERROR; } HRESULT CDocHost::HrInit(HWND hwndParent, int idDlgItem, DWORD dhbBorder) { HRESULT hr=S_OK; HWND hwnd; WNDCLASS wc={0}; if(!IsWindow(hwndParent)) return E_INVALIDARG; m_dhbBorder=dhbBorder; if (!GetClassInfo(g_hInst, c_szDocHostWndClass, &wc)) { wc.lpfnWndProc = CDocHost::ExtWndProc; wc.hInstance = g_hInst; wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.lpszClassName = c_szDocHostWndClass; wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wc.hIcon = LoadIcon(g_hInst, MAKEINTRESOURCE(idiApp)); wc.style = CS_DBLCLKS; if(!RegisterClass(&wc)) return E_OUTOFMEMORY; } hwnd = CreateMDIWindow( c_szDocHostWndClass, "MimeEdit Host", MDIS_ALLCHILDSTYLES| WS_CHILD|WS_CLIPCHILDREN|WS_CLIPSIBLINGS|WS_MAXIMIZEBOX|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, hwndParent, g_hInst, (LONG)this); if(!hwnd) { hr=E_OUTOFMEMORY; goto error; } error: return hr; } // *** IOleWindow methods *** HRESULT CDocHost::GetWindow(HWND *phwnd) { *phwnd=m_hwnd; return NOERROR; } HRESULT CDocHost::ContextSensitiveHelp(BOOL fEnterMode) { return E_NOTIMPL; } // *** IOleInPlaceUIWindow methods *** HRESULT CDocHost::GetBorder(LPRECT lprectBorder) { return E_NOTIMPL; } HRESULT CDocHost::RequestBorderSpace(LPCBORDERWIDTHS pborderwidths) { return NOERROR; } HRESULT CDocHost::SetBorderSpace(LPCBORDERWIDTHS lpborderwidths) { return NOERROR; } HRESULT CDocHost::SetActiveObject(IOleInPlaceActiveObject * pActiveObject, LPCOLESTR lpszObjName) { SafeRelease(m_pInPlaceActiveObj); m_pInPlaceActiveObj=pActiveObject; if(m_pInPlaceActiveObj) m_pInPlaceActiveObj->AddRef(); return NOERROR; } // **** IOleInPlaceSite methods **** HRESULT CDocHost::CanInPlaceActivate() { return NOERROR; } HRESULT CDocHost::OnInPlaceActivate() { LPOLEINPLACEACTIVEOBJECT pInPlaceActive=0; m_lpOleObj->QueryInterface(IID_IOleInPlaceActiveObject, (LPVOID *)&pInPlaceActive); if(pInPlaceActive) { pInPlaceActive->GetWindow(&m_hwndDocObj); ReleaseObj(pInPlaceActive); } return NOERROR; } HRESULT CDocHost::OnUIActivate() { m_fUIActive=TRUE; return NOERROR; } HRESULT CDocHost::GetWindowContext(IOleInPlaceFrame **ppFrame, IOleInPlaceUIWindow **ppDoc, LPRECT lprcPosRect, LPRECT lprcClipRect, LPOLEINPLACEFRAMEINFO lpFrameInfo) { *ppFrame = (LPOLEINPLACEFRAME)m_pInPlaceFrame; m_pInPlaceFrame->AddRef(); *ppDoc = (IOleInPlaceUIWindow *)this; AddRef(); GetClientRect(m_hwnd, lprcClipRect); GetClientRect(m_hwnd, lprcPosRect); HrGetDocObjSize(lprcClipRect); HrGetDocObjSize(lprcPosRect); lpFrameInfo->fMDIApp = FALSE; lpFrameInfo->hwndFrame=m_hwnd; lpFrameInfo->haccel = NULL; lpFrameInfo->cAccelEntries = 0; return NOERROR; } HRESULT CDocHost::Scroll(SIZE scrollExtent) { // the docobject consumes the entireview, so scroll requests // are meaningless. Return NOERROR to indicate that they're scolled // into view. return NOERROR; } HRESULT CDocHost::OnUIDeactivate(BOOL fUndoable) { m_fUIActive=FALSE; return S_OK; } HRESULT CDocHost::OnInPlaceDeactivate() { return S_OK; } HRESULT CDocHost::DiscardUndoState() { return E_NOTIMPL; } HRESULT CDocHost::DeactivateAndUndo() { return E_NOTIMPL; } HRESULT CDocHost::OnPosRectChange(LPCRECT lprcPosRect) { return E_NOTIMPL; } // IOleClientSite methods. HRESULT CDocHost::SaveObject() { return E_NOTIMPL; } HRESULT CDocHost::GetMoniker(DWORD dwAssign, DWORD dwWhichMoniker, LPMONIKER *ppmnk) { return E_NOTIMPL; } HRESULT CDocHost::GetContainer(LPOLECONTAINER *ppCont) { if(ppCont) *ppCont=NULL; return E_NOINTERFACE; } HRESULT CDocHost::ShowObject() { // always shown. // $TODO: do we need to restore the browser here if it is // minimised? return NOERROR; } HRESULT CDocHost::OnShowWindow(BOOL fShow) { return E_NOTIMPL; } HRESULT CDocHost::RequestNewObjectLayout() { return E_NOTIMPL; } // IAdviseSink methods void CDocHost::OnDataChange(FORMATETC *pfetc, STGMEDIUM *pstgmed) { } void CDocHost::OnViewChange(DWORD dwAspect, LONG lIndex) { } void CDocHost::OnRename(LPMONIKER pmk) { } void CDocHost::OnSave() { } void CDocHost::OnClose() { } // IOleDocumentSite HRESULT CDocHost::ActivateMe(LPOLEDOCUMENTVIEW pViewToActivate) { return HrCreateDocView(); } HRESULT CDocHost::HrCreateDocView() { HRESULT hr; LPOLEDOCUMENT pOleDoc=NULL; hr=OleRun(m_lpOleObj); if(FAILED(hr)) goto error; hr=m_lpOleObj->QueryInterface(IID_IOleDocument, (LPVOID*)&pOleDoc); if(FAILED(hr)) goto error; hr=pOleDoc->CreateView(this, NULL,0,&m_pDocView); if(FAILED(hr)) goto error; hr=m_pDocView->SetInPlaceSite(this); if(FAILED(hr)) goto error; hr=m_pDocView->Show(TRUE); if(FAILED(hr)) goto error; error: ReleaseObj(pOleDoc); return hr; } HRESULT CDocHost::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD rgCmds[], OLECMDTEXT *pCmdText) { ULONG ul; // BUGBUG: Check IsEqualGUID(*pguidCmdGroup, CGID_ShellDocView) as well if (!rgCmds) return E_INVALIDARG; if (pguidCmdGroup == NULL) { for (ul=0;ulcmdtextf & OLECMDTEXTF_STATUS)) { pCmdText->cmdtextf = OLECMDTEXTF_NONE;// is this needed? pCmdText->cwActual = 0; return NOERROR; } } return NOERROR; } return OLECMDERR_E_UNKNOWNGROUP; } HRESULT CDocHost::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdExecOpt, VARIANTARG *pvaIn, VARIANTARG *pvaOut) { if (pguidCmdGroup == NULL) { switch(nCmdID) { case OLECMDID_SETDOWNLOADSTATE: if(pvaIn->vt==VT_I4) { m_fDownloading=pvaIn->lVal; return S_OK; } break; case OLECMDID_UPDATECOMMANDS: OnUpdateCommands(); break; case OLECMDID_SETPROGRESSPOS: // when done downloading trident now hits us with a // setprogresspos == -1 to indicate we should remove the "Done" if (pvaIn->lVal == -1) m_pInPlaceFrame->SetStatusText(NULL); return S_OK; case OLECMDID_SETPROGRESSTEXT: if(pvaIn->vt == (VT_BSTR)) m_pInPlaceFrame->SetStatusText((LPCOLESTR)pvaIn->bstrVal); return S_OK; } } return OLECMDERR_E_UNKNOWNGROUP; } void CDocHost::WMSize(int cxBody, int cyBody) { RECT rc={0}; if(m_pDocView) { rc.bottom=cyBody; rc.right=cxBody; // give the subclass a chance to override the size of the // docobj HrGetDocObjSize(&rc); m_pDocView->SetRect(&rc); } // notify the subclass of a wmsize OnWMSize(&rc); } HRESULT CDocHost::QueryService(REFGUID guidService, REFIID riid, LPVOID *ppvObject) { return E_UNEXPECTED; } HRESULT CDocHost::HrSubWMCreate() { return NOERROR; } HRESULT CDocHost::OnControlInfoChanged() { return E_NOTIMPL; } HRESULT CDocHost::LockInPlaceActive(BOOL fLock) { return E_NOTIMPL; } HRESULT CDocHost::GetExtendedControl(LPDISPATCH *ppDisp) { if (ppDisp) *ppDisp=NULL; return E_NOTIMPL; } HRESULT CDocHost::TransformCoords(POINTL *pPtlHimetric, POINTF *pPtfContainer,DWORD dwFlags) { return E_NOTIMPL; } /* * this is a little trippy, so bear with me. When we get a tab, and trident is UIActive we always pass it off to them * if it tabs off the end of its internal tab order (a list of urls for instance) then we get hit with a VK_TAB in our * IOleControlSite::TranslateAccel. If so then we set m_fCycleFocus to TRUE and return S_OK to indicate we took the tab * tridents IOIPAO::TranslateAccel returns S_OK to indicate it snagged the TAB, we then detect if we set cyclefocus to true * there and if so, we return S_FALSE from CBody::HrTranslateAccel to indicate to the browser that we didn't take it and it * move the focus on * */ HRESULT CDocHost::TranslateAccelerator(LPMSG lpMsg, DWORD grfModifiers) { if (lpMsg->message == WM_KEYDOWN && lpMsg->wParam == VK_TAB) { m_fCycleFocus=TRUE; return S_OK; } return E_NOTIMPL; } HRESULT CDocHost::OnFocus(BOOL fGotFocus) { m_fFocus = fGotFocus; return S_OK; } HRESULT CDocHost::ShowPropertyFrame(void) { return E_NOTIMPL; }