/*++ Copyright (C) 1993-1999 Microsoft Corporation Module Name: ioleobj.cpp Abstract: Implementation of the IOleObject interface for Polyline. Some of these just pass through to the default handler which does default implementations. --*/ #include "polyline.h" #include "unkhlpr.h" #include "utils.h" #include "unihelpr.h" void RegisterAsRunning(IUnknown *pUnk, IMoniker *pmk, DWORD dwFlags, LPDWORD pdwReg); /* * CImpIOleObject interface implementation */ IMPLEMENT_CONTAINED_CONSTRUCTOR(CPolyline, CImpIOleObject) IMPLEMENT_CONTAINED_DESTRUCTOR(CImpIOleObject) IMPLEMENT_CONTAINED_QUERYINTERFACE(CImpIOleObject) IMPLEMENT_CONTAINED_ADDREF(CImpIOleObject) STDMETHODIMP_(ULONG) CImpIOleObject::Release( void ) { --m_cRef; #if 0 // Release cached site related interfaces if (m_cRef == 0) { ReleaseInterface(m_pObj->m_pIOleClientSite); ReleaseInterface(m_pObj->m_pIOleControlSite); ReleaseInterface(m_pObj->m_pIDispatchAmbients); } #endif return m_pUnkOuter->Release(); } /* * CImpIOleObject::SetClientSite * CImpIOleObject::GetClientSite * * Purpose: * Manages the IOleClientSite pointer of our container. */ STDMETHODIMP CImpIOleObject::SetClientSite (LPOLECLIENTSITE pIOleClientSite) { ReleaseInterface(m_pObj->m_pIOleClientSite); ReleaseInterface(m_pObj->m_pIOleControlSite); ReleaseInterface(m_pObj->m_pIDispatchAmbients); m_pObj->m_pIOleClientSite = pIOleClientSite; if (NULL != m_pObj->m_pIOleClientSite) { HRESULT hr; LPMONIKER pmk; LPOLECONTAINER pIOleCont; m_pObj->m_pIOleClientSite->AddRef(); /* * Within IRunnableObject::Run we're supposed to register * ourselves as running...however, the moniker has to come * from the container's IOleClientSite::GetMoniker. But * Run is called before SetClientSite here, so we have to * register now that we do have the client site as well * as lock the container. */ hr = m_pObj->m_pIOleClientSite->GetMoniker (OLEGETMONIKER_ONLYIFTHERE, OLEWHICHMK_OBJFULL, &pmk); if (SUCCEEDED(hr)) { RegisterAsRunning(m_pUnkOuter, pmk, 0, &m_pObj->m_dwRegROT); pmk->Release(); } hr = m_pObj->m_pIOleClientSite->GetContainer(&pIOleCont); if (SUCCEEDED(hr)) { m_pObj->m_fLockContainer=TRUE; pIOleCont->LockContainer(TRUE); pIOleCont->Release(); } /* * Go get the container's IDispatch for ambient * properties if it has one, and initilize ourself * with those properties. */ hr = m_pObj->m_pIOleClientSite->QueryInterface(IID_IDispatch , (void **)&m_pObj->m_pIDispatchAmbients); if (SUCCEEDED(hr)) m_pObj->AmbientsInitialize((ULONG)INITAMBIENT_ALL); /* * Get the control site */ hr = m_pObj->m_pIOleClientSite->QueryInterface(IID_IOleControlSite, (void **)&m_pObj->m_pIOleControlSite); } return NOERROR; } STDMETHODIMP CImpIOleObject::GetClientSite(LPOLECLIENTSITE *ppSite) { //Be sure to AddRef the new pointer you are giving away. *ppSite=m_pObj->m_pIOleClientSite; m_pObj->m_pIOleClientSite->AddRef(); return NOERROR; } /* * CImpIOleObject::SetHostNames * * Purpose: * Provides the object with names of the container application and * the object in the container to use in object user interface. * * Parameters: * pszApp LPCOLESTR of the container application. * pszObj LPCOLESTR of some name that is useful in window * titles. * * Return Value: * HRESULT NOERROR */ STDMETHODIMP CImpIOleObject::SetHostNames(LPCOLESTR /* pszApp */ , LPCOLESTR /* pszObj */) { return NOERROR; } /* * CImpIOleObject::Close * * Purpose: * Forces the object to close down its user interface and unload. * * Parameters: * dwSaveOption DWORD describing the circumstances under which * the object is being saved and closed. * * Return Value: * HRESULT NOERROR or a general error value. */ STDMETHODIMP CImpIOleObject::Close(DWORD dwSaveOption) { BOOL fSave=FALSE; //If object is dirty and we're asked to save, save it and close. if (OLECLOSE_SAVEIFDIRTY==dwSaveOption && m_pObj->m_fDirty) fSave=TRUE; /* * If asked to prompt, only do so if dirty, then if we get a * YES, save as usual and close. On NO, just close. On * CANCEL return OLE_E_PROMPTSAVECANCELLED. */ if (OLECLOSE_PROMPTSAVE==dwSaveOption && m_pObj->m_fDirty) { UINT uRet; uRet = MessageBox(NULL, ResourceString(IDS_CLOSEPROMPT), ResourceString(IDS_CLOSECAPTION), MB_YESNOCANCEL); if (IDCANCEL==uRet) return ResultFromScode(OLE_E_PROMPTSAVECANCELLED); if (IDYES==uRet) fSave=TRUE; } if (fSave) { m_pObj->SendAdvise(OBJECTCODE_SAVEOBJECT); m_pObj->SendAdvise(OBJECTCODE_SAVED); } //We get directly here on OLECLOSE_NOSAVE. if ( m_pObj->m_fLockContainer && ( NULL != m_pObj->m_pIOleClientSite ) ) { //Match LockContainer call from SetClientSite LPOLECONTAINER pIOleCont; if (SUCCEEDED(m_pObj->m_pIOleClientSite->GetContainer(&pIOleCont))) { pIOleCont->LockContainer(FALSE); pIOleCont->Release(); } } // Deactivate m_pObj->InPlaceDeactivate(); // Revoke registration in ROT if (m_pObj->m_dwRegROT != 0) { IRunningObjectTable *pROT; if (!FAILED(GetRunningObjectTable(0, &pROT))) { pROT->Revoke(m_pObj->m_dwRegROT); pROT->Release(); m_pObj->m_dwRegROT = 0; } } return NOERROR; } /* * CImpIOleObject::DoVerb * * Purpose: * Executes an object-defined action. * * Parameters: * iVerb LONG index of the verb to execute. * pMSG LPMSG describing the event causing the * activation. * pActiveSite LPOLECLIENTSITE to the site involved. * lIndex LONG the piece on which execution is happening. * hWndParent HWND of the window in which the object can play * in-place. * pRectPos LPRECT of the object in hWndParent where the * object can play in-place if desired. * * Return Value: * HRESULT NOERROR or a general error value. */ STDMETHODIMP CImpIOleObject::DoVerb(LONG iVerb, LPMSG /* pMSG */ , LPOLECLIENTSITE pActiveSite, LONG /* lIndex */, HWND /* hWndParent */ , LPCRECT /* pRectPos */) { HRESULT hr; CAUUID caGUID; USES_CONVERSION switch (iVerb) { case OLEIVERB_HIDE: if (NULL != m_pObj->m_pIOleIPSite) { m_pObj->UIDeactivate(); ShowWindow(m_pObj->m_pHW->Window(), SW_HIDE); } else { ShowWindow(m_pObj->m_pHW->Window(), SW_HIDE); m_pObj->SendAdvise(OBJECTCODE_HIDEWINDOW); } break; case OLEIVERB_PRIMARY: case OLEIVERB_SHOW: if (NULL != m_pObj->m_pIOleIPSite) { ShowWindow(m_pObj->m_pHW->Window(), SW_SHOW); return NOERROR; //Already active } if (m_pObj->m_fAllowInPlace) { return m_pObj->InPlaceActivate(pActiveSite ,TRUE); } return ResultFromScode(OLEOBJ_S_INVALIDVERB); break; case OLEIVERB_INPLACEACTIVATE: if (NULL != m_pObj->m_pHW) { HWND hWndHW=m_pObj->m_pHW->Window(); ShowWindow(hWndHW, SW_SHOW); SetFocus(hWndHW); return NOERROR; } /* * Only inside-out supporting containers will use * this verb. */ m_pObj->m_fContainerKnowsInsideOut=TRUE; m_pObj->InPlaceActivate(pActiveSite, FALSE); break; case OLEIVERB_UIACTIVATE: m_pObj->InPlaceActivate(pActiveSite, TRUE); break; case OLEIVERB_PROPERTIES: case POLYLINEVERB_PROPERTIES: /* * Let the container try first if there are * extended controls. Otherwise we'll display * our own pages. */ if (NULL!=m_pObj->m_pIOleControlSite) { hr=m_pObj->m_pIOleControlSite->ShowPropertyFrame(); if (NOERROR==hr) break; //All done } //Put up our property pages. hr=m_pObj->m_pImpISpecifyPP->GetPages(&caGUID); if (FAILED(hr)) return FALSE; hr=OleCreatePropertyFrame(m_pObj->m_pCtrl->Window(), 10, 10 , T2W(ResourceString(IDS_PROPFRM_TITLE)), 1, (IUnknown **)&m_pObj , caGUID.cElems, caGUID.pElems , LOCALE_USER_DEFAULT, 0L, NULL); //Free the GUIDs CoTaskMemFree((void *)caGUID.pElems); break; default: return ResultFromScode(OLEOBJ_S_INVALIDVERB); } return NOERROR; } /* * CImpIOleObject::GetUserClassID * * Purpose: * Used for linked objects, this returns the class ID of what end * users think they are editing. * * Parameters: * pClsID LPCLSID in which to store the CLSID. * * Return Value: * HRESULT NOERROR or a general error value. */ STDMETHODIMP CImpIOleObject::GetUserClassID(LPCLSID pClsID) { /* * If you are not registered to handle data other than yourself, * then you can just return your class ID here. If you are * registered as usable from Treat-As dialogs, then you need to * return the CLSID of what you are really editing. */ *pClsID=CLSID_SystemMonitor; return NOERROR; } /* * CImpIOleObject::SetExtent * * Purpose: * Sets the size of the object in HIMETRIC units. * * Parameters: * dwAspect DWORD of the aspect affected. * pszl LPSIZEL containing the new size. * * Return Value: * HRESULT NOERROR or a general error value. */ STDMETHODIMP CImpIOleObject::SetExtent( DWORD dwAspect, LPSIZEL pszl ) { RECT rectExt; if (dwAspect == DVASPECT_CONTENT) { // convert from HIMETRIC to device coord SetRect(&rectExt, 0, 0, pszl->cx, pszl->cy); m_pObj->RectConvertMappings(&rectExt,TRUE); // If changed and non-zero, store as new extent if ( !EqualRect ( &m_pObj->m_RectExt, &rectExt ) && !IsRectEmpty( &rectExt ) ) { m_pObj->m_RectExt = rectExt; m_pObj->m_pImpIPolyline->SizeSet(&rectExt, TRUE); // Notify container of change to force metafile update //m_pObj->SendAdvise(OBJECTCODE_DATACHANGED); } } return NOERROR; } /* * CImpIOleObject::GetExtent * * Purpose: * Retrieves the size of the object in HIMETRIC units. * * Parameters: * dwAspect DWORD of the aspect requested * pszl LPSIZEL into which to store the size. * * Return Value: * HRESULT NOERROR or a general error value. */ STDMETHODIMP CImpIOleObject::GetExtent(DWORD dwAspect, LPSIZEL pszl) { //Delegate directly to IViewObject2::GetExtent return m_pObj->m_pImpIViewObject->GetExtent(dwAspect, -1 , NULL, pszl); } /* * CImpIOleObject::Advise * CImpIOleObject::Unadvise * CImpIOleObject::EnumAdvise * * Purpose: * Advisory connection functions. */ STDMETHODIMP CImpIOleObject::Advise( LPADVISESINK pIAdviseSink, LPDWORD pdwConn ) { if (NULL==m_pObj->m_pIOleAdviseHolder) { HRESULT hr; hr=CreateOleAdviseHolder(&m_pObj->m_pIOleAdviseHolder); if (FAILED(hr)) return hr; } return m_pObj->m_pIOleAdviseHolder->Advise(pIAdviseSink, pdwConn); } STDMETHODIMP CImpIOleObject::Unadvise(DWORD dwConn) { if (NULL!=m_pObj->m_pIOleAdviseHolder) return m_pObj->m_pIOleAdviseHolder->Unadvise(dwConn); return ResultFromScode(E_FAIL); } STDMETHODIMP CImpIOleObject::EnumAdvise(LPENUMSTATDATA *ppEnum) { if (NULL!=m_pObj->m_pIOleAdviseHolder) return m_pObj->m_pIOleAdviseHolder->EnumAdvise(ppEnum); return ResultFromScode(E_FAIL); } /* * CImpIOleObject::SetMoniker * * Purpose: * Informs the object of its moniker or its container's moniker * depending on dwWhich. * * Parameters: * dwWhich DWORD describing whether the moniker is the * object's or the container's. * pmk LPMONIKER with the name. * * Return Value: * HRESULT NOERROR or a general error value. */ STDMETHODIMP CImpIOleObject::SetMoniker(DWORD /* dwWhich */ , LPMONIKER /* pmk */) { LPMONIKER pmkFull; HRESULT hr = ResultFromScode(E_FAIL); HRESULT hrTmp; LPBC pbc; if (NULL!=m_pObj->m_pIOleClientSite) { hr = m_pObj->m_pIOleClientSite->GetMoniker (OLEGETMONIKER_ONLYIFTHERE, OLEWHICHMK_OBJFULL , &pmkFull); if (SUCCEEDED(hr)) { hrTmp = CreateBindCtx(0,&pbc); if (SUCCEEDED(hrTmp)) { hrTmp = pmkFull->IsRunning(pbc, NULL, NULL); pbc->Release(); if (hrTmp == NOERROR) { pmkFull->Release(); return NOERROR; } } //This will revoke the old one if m_dwRegROT is nonzero. RegisterAsRunning(m_pUnkOuter, pmkFull, 0, &m_pObj->m_dwRegROT); //Inform clients of the new moniker if (NULL!=m_pObj->m_pIOleAdviseHolder) m_pObj->m_pIOleAdviseHolder->SendOnRename(pmkFull); pmkFull->Release(); } } return hr; } /* * CImpIOleObject::GetMoniker * * Purpose: * Asks the object for a moniker that can later be used to * reconnect to it. * * Parameters: * dwAssign DWORD determining how to assign the moniker to * to the object. * dwWhich DWORD describing which moniker the caller wants. * ppmk LPMONIKER * into which to store the moniker. * * Return Value: * HRESULT NOERROR or a general error value. */ STDMETHODIMP CImpIOleObject::GetMoniker(DWORD /* dwAssign */ , DWORD /* dwWhich */, LPMONIKER *ppmk) { HRESULT hr=ResultFromScode(E_FAIL); *ppmk=NULL; /* * Since we only support embedded objects, our moniker * is always the full moniker from the contianer. */ if (NULL!=m_pObj->m_pIOleClientSite) { hr=m_pObj->m_pIOleClientSite->GetMoniker (OLEGETMONIKER_ONLYIFTHERE, OLEWHICHMK_OBJFULL, ppmk); } return (NULL!=*ppmk) ? NOERROR : hr; } //Methods not implemented or trivial STDMETHODIMP CImpIOleObject::InitFromData( LPDATAOBJECT /* pIDataObject */ , BOOL /* fCreation */, DWORD /* dw */) { return ResultFromScode(E_NOTIMPL); } STDMETHODIMP CImpIOleObject::GetClipboardData(DWORD /* dwReserved */ , LPDATAOBJECT * /* ppIDataObj */) { return ResultFromScode(E_NOTIMPL); } STDMETHODIMP CImpIOleObject::Update(void) { return NOERROR; } STDMETHODIMP CImpIOleObject::IsUpToDate(void) { return NOERROR; } STDMETHODIMP CImpIOleObject::SetColorScheme(LPLOGPALETTE /* pLP */) { return ResultFromScode(E_NOTIMPL); } //Methods implemented using registry helper functions in OLE. STDMETHODIMP CImpIOleObject::EnumVerbs(LPENUMOLEVERB *ppEnum) { return OleRegEnumVerbs(m_pObj->m_clsID, ppEnum); } STDMETHODIMP CImpIOleObject::GetUserType( DWORD dwForm, LPOLESTR *ppszType ) { return OleRegGetUserType(m_pObj->m_clsID, dwForm, ppszType); } STDMETHODIMP CImpIOleObject::GetMiscStatus( DWORD dwAspect, LPDWORD pdwStatus ) { return OleRegGetMiscStatus(m_pObj->m_clsID, dwAspect, pdwStatus); } void RegisterAsRunning( IUnknown *pUnk, IMoniker *pmk, DWORD dwFlags, LPDWORD pdwReg ) { IRunningObjectTable *pROT; HRESULT hr; DWORD dwReg = *pdwReg; dwReg=*pdwReg; if (FAILED(GetRunningObjectTable(0, &pROT))) return; hr = pROT->Register(dwFlags, pUnk, pmk, pdwReg); if (MK_S_MONIKERALREADYREGISTERED == GetScode(hr)) { if (0 != dwReg) pROT->Revoke(dwReg); } pROT->Release(); return; }