// //************************************************************************** // // BOleSite.cpp -- Implements the Bolero half of the OLE2 server object. // BOleSite objects impersonate the client application // from the point of view of the Bolero customer who's // writing a server object (IPart) // // Copyright (c) 1993,94 by Borland International, Inc. All rights reserved // //************************************************************************** // Bolero headers // #include "BOle.h" #include "BOleSite.h" #include "BOleDoc.h" #include "BOleCMan.h" extern "C" { #include "ole2ui.h" } // System/RTL headers // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // #define NOT_IMPLEMENTED OLERET(E_NOTIMPL); HRESULT _IFUNC BOleSite::QueryInterfaceMain(REFIID iid, LPVOID FAR *ppv) { HRESULT hr = ResultFromScode(E_NOINTERFACE); *ppv = NULL; // Self // if (IID_BOleSite == iid) { (BOleSite *)*ppv = this; AddRef(); return NOERROR; } // nested interface class if (IID_IBApplication == iid) { ((IBApplication *)*ppv) = &iApplication; AddRef(); return NOERROR; } // interfaces if (SUCCEEDED(hr = IBContainer_QueryInterface(this, iid, ppv))) { } else if (SUCCEEDED(hr = IBLinkable_QueryInterface(this, iid, ppv))) { } else if (SUCCEEDED(hr = IPersistStorage_QueryInterface(this, iid, ppv))) { } else if (SUCCEEDED(hr = IDataObject_QueryInterface(this, iid, ppv))) { } else if (SUCCEEDED(hr = IDropSource_QueryInterface(this, iid, ppv))) { } else if (SUCCEEDED(hr = IOleObject_QueryInterface(this, iid, ppv))) { } else if (SUCCEEDED(hr = IOleInPlaceObject_QueryInterface(this, iid, ppv))) { } else if (SUCCEEDED(hr = IOleInPlaceActiveObject_QueryInterface(this, iid, ppv))) { } else if (SUCCEEDED(hr = IBSite_QueryInterface(this, iid, ppv))) { } else if (SUCCEEDED(hr = IEnumFORMATETC_QueryInterface(this, iid, ppv))) { } // base classes else if (SUCCEEDED(hr = BOleComponent::QueryInterfaceMain(iid, ppv))) { } return hr; }; // // BOleSite implementation -- These functions aren't part of an inherited // interface, but are part of the private // implementation of BOleSite // BOleSite::BOleSite(BOleClassManager * pFact, IBUnknownMain *pOuter, BOleService *pSvc) : BOleComponent (pFact, pOuter) , iApplication(this, pOuter), cid (CLSID_NULL) { pService = pSvc; #ifdef OLEDBG DebugMode = 0; #endif pClientSite = NULL; pStg = NULL; pDAdvHolder = NULL; pAdvHolder = NULL; pPart = NULL; // (IPart *) pOuter->InterfaceGet(IID(IPart)); pProvider = NULL; pIPSite = 0; pIPFrame = 0; pIPDoc = 0; fShown = FALSE; fInPlaceActive = FALSE; fInPlaceVisible = FALSE; fInsideOut = FALSE; fUIActive = FALSE; fInHelpMode = FALSE; fInClose = FALSE; hWndParent = 0; pHatchWnd = NULLP; hWndInPlace = 0; hOleMenu = 0; hMenuShared = 0; pszProgID = NULLP; pmkDoc = NULLP; hatchOffset.x = hatchOffset.y = 0; pFactory->ServerCount(+1L); regLink = 0L; pszInstName = NULL; pWindowTitle = NULL; pAppName = NULL; fHandsOff = FALSE; fIsDirty = TRUE; formatList = NULL; formatCount = 0; formatLink = TRUE; // default pending moniker existence formatEmbed = TRUE; pInPlaceName = NULL; pDocument = NULL; } HRESULT _IFUNC BOleSite::Init (PIBDataProvider pProv, PIBPart ppart, LPCOLESTR psz, BOOL fHatchWnd) { // If the provider also supports IBPart, then it's a full-fledged // server object capable of inplace activation. If it doesn't, this // BOleSite will only be used for data transfer. // pProvider = pProv; pPart = ppart; // Bind to BOleFact so we can get the CLSID // if (pszProgID != NULLP) delete pszProgID; pszProgID = new OLECHAR [lstrlen(psz) + 1]; if (!pszProgID) return ResultFromScode (E_OUTOFMEMORY); lstrcpy (pszProgID, psz); CLSIDFromProgID(pszProgID, &cid); // Cache the available formats because OLE2 will ask for formats // during link/embed from file, even though no Clip or Drag // happened. // // // // // // // pService->FormatHelper (&formatList, &formatCount, formatLink, formatEmbed, pProvider); // Create a hatched window which is visible during visual editing // if (pPart && fHatchWnd) { //pHatchWnd = BOleHatchWindow::Create (NULL, boleInst, this); pHatchWnd = new BOleHatchWindow(NULL, boleInst, this); if (!pHatchWnd || !(HANDLE)pHatchWnd) return ResultFromScode (E_OUTOFMEMORY); } // Catenate the APPNAME and the SHORTUSERTYPENAME together. This seems // to be the convention for SetActiveObject // LPOLESTR appname = NULL, shortname = NULL; int c = 0; OleRegGetUserType (cid, USERCLASSTYPE_APPNAME, &appname); if (appname) c += lstrlen (appname) + lstrlen ( TEXT(" - ") ); OleRegGetUserType (cid, USERCLASSTYPE_SHORT, &shortname); if (shortname) c += lstrlen (shortname); pInPlaceName = new OLECHAR [c + 1]; // +1 for null term if (!pInPlaceName) return ResultFromScode (E_OUTOFMEMORY); pInPlaceName[0] = 0; if (appname) { strcat (pInPlaceName, appname); strcat (pInPlaceName, TEXT(" - ") ); } if (shortname) strcat (pInPlaceName, shortname); IMalloc *pMalloc; if (SUCCEEDED(CoGetMalloc(MEMCTX_TASK, &pMalloc))) { pMalloc->Free(appname); pMalloc->Free(shortname); pMalloc->Release(); } return NOERROR; } BOleSite::~BOleSite () { // Don't translate any more accelerators through this helper // if (pService->pFocusedSite == this) OnSetFocus (NULL); DoClose(); // Release the client site here (not in DoClose) so that we can in place // activate after an open-edit session (Dll server case). // if (pClientSite) { pClientSite->Release (); pClientSite = NULL; } if (pWindowTitle) { delete [] pWindowTitle; pWindowTitle = NULL; } if (pAppName) { delete [] pAppName; pAppName = NULL; } if (pszProgID) { delete pszProgID; pszProgID = NULL; } if (pHatchWnd) { delete pHatchWnd; pHatchWnd = NULL; } if (pDocument) { // Set in BOleContainer::GetObject CoLockObjectExternal(pDocument, FALSE, FALSE); pDocument = NULL; } if (pmkDoc) { pmkDoc->Release(); pmkDoc = NULL; } if (pszInstName) { delete [] pszInstName; pszInstName = NULL; } if (pInPlaceName) { delete [] pInPlaceName; pInPlaceName = NULL; } if (formatList) { delete [] formatList; } pFactory->ServerCount(-1L); } // // Accessor functions for format lists // void _IFUNC BOleSite::GetFormatFlags(BOOL *pfEmbed, BOOL *pfLink) { if (pService->dropCount || (pService->clipCount && pService->IsOnClipboard(this))) { *pfLink = pService->fUseDropList ? pService->dropOkToLink : pService->clipOkToLink; *pfEmbed = pService->fUseDropList ? pService->dropOkToEmbed : pService->clipOkToEmbed; } else { if (!formatList) { // Cache the available formats because OLE2 will ask for formats // during link/embed from file, even though no Clip or Drag // happened. pService->FormatHelper (&formatList, &formatCount, formatLink, formatEmbed, pProvider); } *pfLink = formatLink; *pfEmbed = formatEmbed; } } void _IFUNC BOleSite::GetFormatList(LPFORMATETC *ppList, UINT *pCount) { if (pService->dropCount || (pService->clipCount && pService->IsOnClipboard(this))) { *ppList = pService->fUseDropList ? pService->dropList : pService->clipList; *pCount = pService->fUseDropList ? pService->dropCount : pService->clipCount; } else { if (!formatList) { // Cache the available formats because OLE2 will ask for formats // during link/embed from file, even though no Clip or Drag // happened. pService->FormatHelper (&formatList, &formatCount, formatLink, formatEmbed, pProvider); } *ppList = formatList; *pCount = formatCount; } } void _IFUNC BOleSite::GetFormatCount(UINT *pCount) { if (pService->dropCount || (pService->clipCount && pService->IsOnClipboard(this))) { *pCount = pService->fUseDropList ? pService->dropCount : pService->clipCount; } else { if (!formatList) { // Cache the available formats because OLE2 will ask for formats // during link/embed from file, even though no Clip or Drag // happened. pService->FormatHelper (&formatList, &formatCount, formatLink, formatEmbed, pProvider); } *pCount = formatCount; } } void _IFUNC BOleSite::GetFormatInfo(BOOL *pfEmbed, BOOL *pfLink, LPFORMATETC *ppList, UINT *pCount) { if (pService->dropCount || (pService->clipCount && pService->IsOnClipboard(this))) { *pfLink = pService->fUseDropList ? pService->dropOkToLink : pService->clipOkToLink; *pfEmbed = pService->fUseDropList ? pService->dropOkToEmbed : pService->clipOkToEmbed; *ppList = pService->fUseDropList ? pService->dropList : pService->clipList; *pCount = pService->fUseDropList ? pService->dropCount : pService->clipCount; } else { if (!formatList) { // Cache the available formats because OLE2 will ask for formats // during link/embed from file, even though no Clip or Drag // happened. pService->FormatHelper (&formatList, &formatCount, formatLink, formatEmbed, pProvider); } *pfLink = formatLink; *pfEmbed = formatEmbed; *ppList = formatList; *pCount = formatCount; } } // Render this server object onto a storage medium. // HRESULT _IFUNC BOleSite::GetEmbeddedObjectData (LPFORMATETC pFmt, LPSTGMEDIUM pMed) { LPSTORAGE lpstg = NULL; SCODE sc = S_OK; HRESULT hrErr; pMed->pUnkForRelease = NULL; if (pMed->tymed == TYMED_NULL) { // If the tymed passed in is NULL, we will create a temporary storage // in memory in order to render the object // if (pFmt->tymed & TYMED_ISTORAGE) { lpstg = CreateStorageInMemory (STGM_READWRITE | STGM_TRANSACTED | STGM_SHARE_EXCLUSIVE /*| STGM_DELETEONRELEASE??*/); if (!lpstg) return ResultFromScode(E_OUTOFMEMORY); pMed->pstg = lpstg; pMed->tymed = TYMED_ISTORAGE; pMed->pUnkForRelease = NULL; } else return ResultFromScode(DATA_E_FORMATETC); } // If the tymed passed in is non-NULL, we will use the storage they // gave us. If it's not a storage, return failure. // else if (pMed->tymed & TYMED_ISTORAGE) { pMed->tymed = TYMED_ISTORAGE; // The online dox say that OleSave does this, but there's no // CompObj stream without WriteFmtUseTypeStg and no CLSID in the // stream without WriteClassStg // CLSID clsid = CLSID_NULL; CLSIDFromProgID (pszProgID, &clsid); if ((hrErr = WriteClassStg (pMed->pstg, clsid)) != NOERROR) return hrErr; LPOLESTR lpLongType = NULL; OleRegGetUserType (clsid, USERCLASSTYPE_FULL, &lpLongType); hrErr = WriteFmtUserTypeStg (pMed->pstg, pFmt->cfFormat, lpLongType); } else return ResultFromScode(DATA_E_FORMATETC); // We don't really expect anyone to respond to this call, but WPWin // is going to try to decide whether a new object is linked or embedded // based on this notification. // BOleFormat f; f.fmtId = BOleDocument::oleEmbSrcClipFmt; f.fmtMedium = BOLE_MED_STORAGE; f.fmtName[0] = 0; f.fmtResultName[0] = 0; f.fmtIsLinkable = FALSE; pProvider->GetFormatData (&f); hrErr = OleSave(this, pMed->pstg, FALSE /* fSameAsLoad */); if (hrErr != NOERROR) sc = GetScode(hrErr); // Always call SaveCompleted, but don't stomp the error code if // OleSave failed // hrErr = SaveCompleted (NULL); if (hrErr != NOERROR && sc == S_OK) sc = GetScode(hrErr); return ResultFromScode(sc); } // Render the data for a link source into a stream medium // HRESULT _IFUNC BOleSite::GetLinkSourceData(LPMONIKER lpmk, REFCLSID cid, LPFORMATETC lpformatetc, LPSTGMEDIUM lpMedium) { LPSTREAM lpstm = NULL; HRESULT hrErr; // We don't really expect anyone to respond to this call, but WPWin // is going to try to decide whether a new object is linked or embedded // based on this notification. // BOleFormat f; f.fmtId = BOleDocument::oleLinkSrcClipFmt; f.fmtMedium = BOLE_MED_STREAM; f.fmtName[0] = 0; f.fmtResultName[0] = 0; f.fmtIsLinkable = TRUE; pProvider->GetFormatData (&f); if (lpMedium->tymed == TYMED_NULL) { if (lpformatetc->tymed & TYMED_ISTREAM) { hrErr = CreateStreamOnHGlobal( NULL, // auto allocate TRUE, // delete on release (LPSTREAM FAR*)&lpstm ); if (hrErr != NOERROR) { lpMedium->pUnkForRelease = NULL; return ResultFromScode (E_OUTOFMEMORY); } lpMedium->pstm = lpstm; lpMedium->tymed = TYMED_ISTREAM; lpMedium->pUnkForRelease = NULL; } else { lpMedium->pUnkForRelease = NULL; return ResultFromScode (DATA_E_FORMATETC); } } else { if (lpMedium->tymed & TYMED_ISTREAM) { lpMedium->tymed = TYMED_ISTREAM; lpMedium->pstm = lpMedium->pstm; lpMedium->pUnkForRelease = NULL; } else { lpMedium->pUnkForRelease = NULL; return ResultFromScode (DATA_E_FORMATETC); } } hrErr = OleSaveToStream((LPPERSISTSTREAM)lpmk, lpMedium->pstm); if (hrErr != NOERROR) return hrErr; return WriteClassStm (lpMedium->pstm, cid); } // Creates an LPSTORAGE with the specified flags on a memory lockbytes // LPSTORAGE _IFUNC BOleSite::CreateStorageInMemory (DWORD grfMode) { DWORD grfCreateMode =grfMode | STGM_CREATE; HRESULT hrErr; LPLOCKBYTES lpLockBytes = NULL; DWORD reserved = 0; LPSTORAGE lpStg = NULL; hrErr = CreateILockBytesOnHGlobal(NULL, TRUE /*delete on release*/, &lpLockBytes); if (hrErr != NOERROR) return NULL; hrErr = StgCreateDocfileOnILockBytes(lpLockBytes, grfCreateMode, reserved, &lpStg); if (hrErr != NOERROR) { lpLockBytes->Release(); return NULL; } lpLockBytes->Release(); return lpStg; } //************************************************************************** // // IDataObject implementation // //************************************************************************** HRESULT _IFUNC BOleSite::GetData (LPFORMATETC pFormatEtcIn, LPSTGMEDIUM pMedium) { #ifdef ANSI char name[32]; GetClipboardFormatNameA(pFormatEtcIn->cfFormat, name, sizeof(name)); #else OLECHAR name[32]; GetClipboardFormatName(pFormatEtcIn->cfFormat, name, sizeof(name)); #endif HRESULT hrErr = ResultFromScode (DATA_E_FORMATETC); BOOL fLink = TRUE; BOOL fEmbed = TRUE; GetFormatFlags(&fEmbed, &fLink); if (pFormatEtcIn->dwAspect & (DVASPECT_CONTENT | DVASPECT_DOCPRINT)) { pMedium->tymed = 0L; pMedium->pUnkForRelease = NULL; pMedium->hGlobal = NULL; if (pFormatEtcIn->cfFormat == BOleDocument::oleEmbSrcClipFmt) { if( fEmbed ) hrErr = GetEmbeddedObjectData (pFormatEtcIn, pMedium); } else if (pFormatEtcIn->cfFormat == BOleDocument::oleObjectDescFmt) { if( fEmbed ) goto _getobjdesc; } else if (pFormatEtcIn->cfFormat == BOleDocument::oleLinkSrcClipFmt) { if( fLink ) { LPMONIKER pMon; hrErr = GetMoniker(OLEGETMONIKER_ONLYIFTHERE,OLEWHICHMK_OBJFULL, &pMon); if (SUCCEEDED(hrErr)) { CLSID id; hrErr = GetUserClassID(&id); pMedium->tymed = TYMED_NULL; // for GetLinkSourceData pFormatEtcIn->cfFormat = BOleDocument::oleLinkSrcClipFmt; // per Brockshmit's suggestion pFormatEtcIn->tymed = TYMED_ISTREAM; // pg. 773 if (SUCCEEDED(hrErr)) { hrErr = GetLinkSourceData(pMon, id, pFormatEtcIn, pMedium); } pMon->Release(); } } } else if (pFormatEtcIn->cfFormat == BOleDocument::oleLinkSrcDescFmt) { if( fLink ) { _getobjdesc:; // Object descriptors *must* be returned in a memory handle // if (pFormatEtcIn->tymed & TYMED_HGLOBAL) { pMedium->hGlobal = GetObjDescData (); if (pMedium->hGlobal) { pMedium->tymed = TYMED_HGLOBAL; hrErr = ResultFromScode (S_OK); } else hrErr = ResultFromScode (E_OUTOFMEMORY); } } } else if (pFormatEtcIn->cfFormat == CF_METAFILEPICT && (pFormatEtcIn->tymed & TYMED_MFPICT)) { hrErr = GetMetaFileData (pMedium->hGlobal); if (hrErr == NOERROR) pMedium->tymed = TYMED_MFPICT; } // It's not an OLE2 format, maybe it's a regular clipboard format // the client would know. // else { BOleFormat boleFmt; _fmemset(&boleFmt, 0, sizeof(boleFmt)); boleFmt.fmtId = pFormatEtcIn->cfFormat; boleFmt.fmtMedium = (BOleMedium) pFormatEtcIn->tymed; //PHP It would be more efficient to use our list of formats //from enumFormatEtc to check before calling GetFormatData if (pMedium) { pMedium->hGlobal = pProvider->GetFormatData (&boleFmt); if (pMedium->hGlobal) { pMedium->tymed = boleFmt.fmtMedium & ~BOLE_MED_STATIC; } } if (pMedium->hGlobal) hrErr = ResultFromScode (S_OK); } } return hrErr; } #ifdef TESTMETAFILE extern HINSTANCE boleInst; void RenderMetaFile(HGLOBAL hMFPict) { LPMETAFILEPICT pMFPict = (LPMETAFILEPICT) GlobalLock (hMFPict); int xPix = MAP_LOGHIM_TO_PIX (pMFPict->xExt, BOleService::pixPerIn.x); int yPix = MAP_LOGHIM_TO_PIX (pMFPict->yExt, BOleService::pixPerIn.y); HWND w = GetDesktopWindow(); if (w) { HDC dc = GetDC (w); UINT oldMapMode = SetMapMode(dc, MM_ANISOTROPIC); SetWindowExt (dc, 1000, 1000); SetViewportExt (dc, xPix, yPix); PlayMetaFile (dc, pMFPict->hMF); SetMapMode (dc, oldMapMode); ReleaseDC(w, dc); GlobalUnlock (hMFPict); } } #endif HRESULT _IFUNC BOleSite::GetMetaFileData (HGLOBAL& hMem) { HRESULT hrErr = NOERROR; #ifdef ANSI HDC hDC = CreateMetaFileA(NULL); #else HDC hDC = CreateMetaFile(NULL); #endif if (hDC) { // Get server size in pixels SIZE s; pProvider->GetPartSize (&s); // Convert server size to himetric, and set up dc for drawing // SIZEL sl; sl.cx = MAP_PIX_TO_LOGHIM (s.cx, BOleService::pixPerIn.x); sl.cy = MAP_PIX_TO_LOGHIM (s.cy, BOleService::pixPerIn.y); SetMapMode(hDC, MM_ANISOTROPIC); SetWindowOrg(hDC, 0, 0); SetWindowExt(hDC, sl.cx, sl.cy); RECTL rPos = {0L, 0L, sl.cx, sl.cy}, rExt = {0L, 0L, sl.cx, sl.cy}; pProvider->Draw (hDC, &rPos, &rExt, BOLE_CONTENT); HMETAFILE hMF = CloseMetaFile (hDC); if (hMF) { HGLOBAL hMFPict = ::GlobalAlloc (GMEM_SHARE|GMEM_ZEROINIT, sizeof (METAFILEPICT)); if (hMFPict) { LPMETAFILEPICT pPict = (LPMETAFILEPICT) ::GlobalLock (hMFPict); if (pPict) { pPict->mm = MM_ANISOTROPIC; pPict->hMF = hMF; pPict->xExt = sl.cx; pPict->yExt = sl.cy; // add minus sign to make it +ve GlobalUnlock (hMFPict); hMem = hMFPict; } else { GlobalFree (hMFPict); DeleteMetaFile (hMF); hrErr = ResultFromScode (E_OUTOFMEMORY); } } else { DeleteMetaFile (hMF); hrErr = ResultFromScode (E_OUTOFMEMORY); } } else hrErr = ResultFromScode (E_OUTOFMEMORY); } #ifdef TESTMETAFILE if (SUCCEEDED(hrErr)) RenderMetaFile(hMem); #endif return hrErr; } HRESULT _IFUNC BOleSite::GetDataHere (LPFORMATETC pFormatEtc, LPSTGMEDIUM pMedium) { #ifdef ANSI char name[32]; GetClipboardFormatNameA(pFormatEtc->cfFormat, name, sizeof(name)); #else OLECHAR name[32]; GetClipboardFormatName(pFormatEtc->cfFormat, name, sizeof(name)); #endif BOOL fLink = TRUE; BOOL fEmbed = TRUE; GetFormatFlags(&fEmbed, &fLink); HRESULT hr = ResultFromScode(DATA_E_FORMATETC); if (pFormatEtc->cfFormat == BOleDocument::oleEmbSrcClipFmt) { if( fEmbed ) hr = GetEmbeddedObjectData (pFormatEtc, pMedium); } else if (pFormatEtc->cfFormat == BOleDocument::oleLinkSrcClipFmt) { if (fLink) { LPMONIKER pMon; hr = GetMoniker(OLEGETMONIKER_ONLYIFTHERE,OLEWHICHMK_OBJFULL, &pMon); if (SUCCEEDED(hr)) { CLSID id; hr = GetUserClassID (&id); pMedium->tymed = TYMED_NULL; // for GetLinkSourceData pFormatEtc->cfFormat = BOleDocument::oleLinkSrcClipFmt; // per Brockshmit's suggestion pFormatEtc->tymed = TYMED_ISTREAM; // pg. 773 if (SUCCEEDED(hr)) hr = GetLinkSourceData(pMon, id, pFormatEtc, pMedium); pMon->Release(); } } } return hr; } HRESULT _IFUNC BOleSite::QueryGetData (LPFORMATETC pFormatEtc) { #ifdef ANSI char name[32]; GetClipboardFormatNameA(pFormatEtc->cfFormat, name, sizeof(name)); #else OLECHAR name[32]; GetClipboardFormatName(pFormatEtc->cfFormat, name, sizeof(name)); #endif BOOL fLink = TRUE; BOOL fEmbed = TRUE; LPFORMATETC pList; UINT count; GetFormatInfo(&fEmbed, &fLink, &pList, &count); HRESULT hrErr = ResultFromScode (DV_E_FORMATETC); if (pFormatEtc->cfFormat == BOleDocument::oleObjectDescFmt) { if (fEmbed) { // Object Descriptors must be offered in global handles // if (pFormatEtc->tymed & TYMED_HGLOBAL) hrErr = NOERROR; else hrErr = ResultFromScode (DV_E_FORMATETC); } } else if (pFormatEtc->cfFormat == BOleDocument::oleLinkSrcDescFmt) { if (fLink) { // Link Src Desc, like Obj Desc, must be offered in a global handle // if (pFormatEtc->tymed & TYMED_HGLOBAL) hrErr = NOERROR; else hrErr = ResultFromScode (DV_E_FORMATETC); } } for (UINT i = 0; i < count; i++) { if ((pList[i].cfFormat == pFormatEtc->cfFormat) && (pList[i].tymed & pFormatEtc->tymed)) { return ResultFromScode(S_OK); } } return hrErr; } HRESULT _IFUNC BOleSite::GetCanonicalFormatEtc (LPFORMATETC pFormatetc, LPFORMATETC pFormatetcOut) { if (!pFormatetcOut) return ResultFromScode( E_INVALIDARG ); pFormatetcOut->ptd = NULL; if (!pFormatetc) return ResultFromScode (E_INVALIDARG); HRESULT hrErr; hrErr = QueryGetData (pFormatetc); if (hrErr != NOERROR) return hrErr; *pFormatetcOut = *pFormatetc; if (!pFormatetc->ptd) return ResultFromScode (DATA_S_SAMEFORMATETC); pFormatetcOut->ptd = NULL; return NOERROR; } // Set data into the server // HRESULT _IFUNC BOleSite::SetData (LPFORMATETC pFormatEtc, STGMEDIUM FAR* pMedium, BOOL fRelease) { PIBDataProvider2 pProvider2 = NULL; // Does client implement IBDataProvider2? // if (!SUCCEEDED(pObjOuter->QueryInterfaceMain (IID_IBDataProvider2,&(LPVOID)pProvider2))) NOT_IMPLEMENTED HRESULT hr = ResultFromScode (DATA_E_FORMATETC); if ((BOleMedium) pFormatEtc->tymed == BOLE_MED_HGLOBAL) { BOleFormat boleFmt; _fmemset(&boleFmt, 0, sizeof(boleFmt)); boleFmt.fmtId = pFormatEtc->cfFormat; boleFmt.fmtMedium = (BOleMedium) pFormatEtc->tymed; if (pMedium) { hr = pProvider2->SetFormatData(&boleFmt, pMedium->hGlobal, FALSE); // Always do release here instead of in SetFormatData // if (fRelease) ReleaseStgMedium(pMedium); } } pProvider2->Release(); return hr; } HRESULT _IFUNC BOleSite::EnumFormatEtc (DWORD dwDirection, LPENUMFORMATETC FAR* ppenumFormatEtc) { if (dwDirection == DATADIR_GET) { *ppenumFormatEtc = this; enumFmtIndex = 0L; AddRef(); // caller must release return ResultFromScode(S_OK); } // I'm not sure what it would mean to call IDataObject::SetData // on the BOleSite so it's blank until I can do more research // return ResultFromScode (E_FAIL); } HRESULT _IFUNC BOleSite::DAdvise (FORMATETC FAR* pFormatetc, DWORD advf, IAdviseSink* pAdvSink, DWORD FAR* pdwConnection) { HRESULT hrErr; *pdwConnection = 0; if (pDAdvHolder == 0) hrErr = CreateDataAdviseHolder (&pDAdvHolder); if (pDAdvHolder) hrErr = pDAdvHolder->Advise (this, pFormatetc, advf, pAdvSink, pdwConnection); else hrErr = ResultFromScode (E_OUTOFMEMORY); return hrErr; } HRESULT _IFUNC BOleSite::DUnadvise (DWORD dwConnection) { HRESULT hrErr = ResultFromScode(E_FAIL); if (pDAdvHolder) hrErr = pDAdvHolder->Unadvise (dwConnection); return hrErr; } HRESULT _IFUNC BOleSite::EnumDAdvise (IEnumSTATDATA* FAR* ppenumAdvise) { HRESULT hrErr = ResultFromScode(E_FAIL); if (pDAdvHolder) hrErr = pDAdvHolder->EnumAdvise (ppenumAdvise); return hrErr; } //************************************************************************** // // IEnumFORMATETC implementation // //************************************************************************** HRESULT _IFUNC BOleSite::Next (ULONG celt, FORMATETC FAR * pFE, ULONG FAR* pceltFetched) { LPFORMATETC pList; UINT count; GetFormatList(&pList, &count); if (pceltFetched) *pceltFetched = 0; if( !celt ) return ResultFromScode (E_INVALIDARG); short nCopied = 0; while ( (enumFmtIndex < count) && (nCopied < celt) ) { pFE[nCopied] = pList[enumFmtIndex]; enumFmtIndex++; nCopied++; if (pceltFetched) (*pceltFetched)++; } return ResultFromScode( nCopied != celt ? S_FALSE : S_OK); } HRESULT _IFUNC BOleSite::Skip (ULONG celt) { UINT count; GetFormatCount(&count); if( celt > count ) return ResultFromScode (E_INVALIDARG); if( enumFmtIndex < count ) { int diff = count - enumFmtIndex; enumFmtIndex += celt; return ResultFromScode (diff < celt ? S_OK : S_FALSE); } return ResultFromScode (S_FALSE); } HRESULT _IFUNC BOleSite::Reset () { enumFmtIndex = 0L; return ResultFromScode(S_OK); } HRESULT _IFUNC BOleSite::Clone (IEnumFORMATETC FAR* FAR* ppenum) { return ResultFromScode (E_NOTIMPL); } //************************************************************************** // // IOleObject implementation // //************************************************************************** HRESULT _IFUNC BOleSite::SetClientSite (IOleClientSite* pCS) { if (pClientSite) pClientSite->Release (); pClientSite = pCS; if (pClientSite) pClientSite->AddRef (); return ResultFromScode(S_OK); } HRESULT _IFUNC BOleSite::GetClientSite (IOleClientSite* FAR* ppClientSite) { if (pClientSite) { pClientSite->AddRef (); *ppClientSite = pClientSite; return ResultFromScode(S_OK); } else { *ppClientSite = NULL; return ResultFromScode(E_FAIL); } } HRESULT _IFUNC BOleSite::SetHostNames (LPCOLESTR szContainerApp, LPCOLESTR szContainerObj) { // Delete the old ones if any // if (pAppName) { delete [] pAppName; pAppName = NULL; } if (pWindowTitle) { delete [] pWindowTitle; pWindowTitle = NULL; } // Copy the new ones into member data so they're around in case // the part object asks for them (through IBContainer or IBApplication) // short c = strlen (szContainerApp) + 1; //+1 for \0 terminator pAppName = new OLECHAR[c]; if (!pAppName) return ResultFromScode (E_OUTOFMEMORY); lstrcpyn( pAppName, szContainerApp, c ); if (szContainerObj) { // docs say this could be NULL c = strlen (szContainerObj) + 1; //+1 for \0 terminator pWindowTitle = new OLECHAR[c]; if (!pWindowTitle) return ResultFromScode (E_OUTOFMEMORY); lstrcpyn ( pWindowTitle, szContainerObj, c); } return NOERROR; } HRESULT _IFUNC BOleSite::DoClose () { // If closed while open in place, exit in-place mode // if (fInPlaceActive) { DoInPlaceDeactivate (); } // If closed while open editing, exit open edit mode // if (fShown) { // pass FALSE here to not allow Lock(FALSE) to cause ::Close to be // called recursively in in-proc server case. // Unlocking is done at the end of ::Close (see comments below). // HideWindow(FALSE); } // If this object is on the clipboard, render all formats // if (pService->IsOnClipboard(this)) pService->FlushClipboardData(FALSE); // Unregister for linking // if (regLink != 0L) { LPRUNNINGOBJECTTABLE pROT = NULL; HRESULT hr = OLE::GetRunningObjectTable (0, &pROT); if (SUCCEEDED(hr)) { pROT->Revoke(regLink); regLink = 0L; pROT->Release(); } } // Notify containers of exit from "running state" // if (pDAdvHolder) { pDAdvHolder->SendOnDataChange (this, 0, ADVF_DATAONSTOP); pDAdvHolder->Release (); pDAdvHolder = NULL; } if (pAdvHolder) { BOOL tmp = fInClose; fInClose = TRUE; pAdvHolder->SendOnClose (); // SendOnClose recursively calls Close! pAdvHolder->Release (); fInClose = tmp; pAdvHolder = NULL; } // Release some remaining references to others // if (pIPSite) { pIPSite->Release(); pIPSite = NULL; } if (pIPFrame) { pIPFrame->Release(); pIPFrame = NULL; } if (pIPDoc) { pIPDoc->Release(); pIPDoc = NULL; } if (pStg) { pStg->Release (); pStg = NULL; } return NOERROR; } HRESULT _IFUNC BOleSite::Close (DWORD dwSaveOption) { HRESULT hrErr = NOERROR; if (fInClose) return NOERROR; AddRef(); fInClose = TRUE; if (fIsDirty) { if (dwSaveOption == OLECLOSE_PROMPTSAVE) { if (pAppName) { UINT nResponse = MessageBox(NULL, TEXT("Save Object before closing?"), pAppName, MB_ICONQUESTION | MB_YESNOCANCEL ); switch (nResponse) { case IDNO: dwSaveOption = OLECLOSE_NOSAVE; break; case IDCANCEL: hrErr = ResultFromScode(OLE_E_PROMPTSAVECANCELLED); // don't close fInClose = FALSE; return hrErr; case IDYES: dwSaveOption = OLECLOSE_SAVEIFDIRTY; break; } } } switch (dwSaveOption) { case OLECLOSE_SAVEIFDIRTY: if (pClientSite) { pClientSite->SaveObject(); fIsDirty = FALSE; } break; case OLECLOSE_NOSAVE: break; } } DoClose(); // Might not have a pPart if this helper object was only used by a // pProvider for data transfer // if (pPart) { pPart->Close(); } // This allows self embedded apps to in place activate and still shutdown // properly. In self embed in place activation, default handler aggregator // seems to have interfaces that don't go away until a last unlock releases. // // Unfortunately, the default handler also calls IOleObject::Close // recursively. Wish it would just drop those references without // calling Close! or Release those references before calling close... // // // // // // CoDisconnectObject(AsPIUnknown(pObjOuter), 0); fInClose = FALSE; Release(); return hrErr; } HRESULT _IFUNC BOleSite::SetMoniker (DWORD dwWhichMoniker, IMoniker* pmk) { HRESULT hr= ResultFromScode(E_FAIL); LPMONIKER pmkFull; // To play "link to embedding", we need to register this object // under the full moniker given by the client site. // get the running object table LPRUNNINGOBJECTTABLE pROT = NULL; hr = OLE::GetRunningObjectTable (0, &pROT); if (SUCCEEDED(hr)) { // Register the new moniker BEFORE revoking the old moniker. // Otherwise the object's "StubManager" gets hosed. // DWORD oldRegLink = regLink; hr = GetMoniker(OLEGETMONIKER_ONLYIFTHERE, OLEWHICHMK_OBJFULL, &pmkFull); if (SUCCEEDED(hr)) { hr = pROT->Register (0, //ROTFLAGS_REGISTRATIONKEEPSALIVE, AsPIUnknown(pObjOuter), pmkFull, ®Link); if (pAdvHolder) { pAdvHolder->SendOnRename (pmkFull); } pmkFull->Release(); } else regLink = 0L; // release any old running object table registration if (oldRegLink != 0L) { pROT->Revoke(oldRegLink); oldRegLink = 0L; } pROT->Release(); } return hr; } HRESULT _IFUNC BOleSite::GetMoniker (DWORD dwAssign, DWORD dwWhichMoniker, IMoniker* FAR* ppmk) { // If we're open in a server doc its relative to the one in pmkDoc // If we're an embedding, its relative to the container's doc HRESULT hr = ResultFromScode(E_FAIL); *ppmk = NULL; if (pClientSite) { hr = pClientSite->GetMoniker(OLEGETMONIKER_ONLYIFTHERE, OLEWHICHMK_OBJFULL, ppmk); } else if (pmkDoc && pszInstName) { LPMONIKER pmkObj = NULL; if (SUCCEEDED(CreateItemMoniker(TEXT("!"), pszInstName, &pmkObj))) { hr = CreateGenericComposite(pmkDoc, pmkObj, ppmk); pmkObj->Release(); } } else if (pmkDoc && !pszInstName) { *ppmk = pmkDoc; pmkDoc->AddRef(); hr = NOERROR; } return hr; } HRESULT _IFUNC BOleSite::InitFromData (IDataObject* pDataObject, BOOL fCreation, DWORD dwReserved) { return ResultFromScode (E_NOTIMPL); } HRESULT _IFUNC BOleSite::GetClipboardData (DWORD dwReserved, IDataObject* FAR* ppDataObject) { return ResultFromScode (E_NOTIMPL); } // Put external lock on document HRESULT _IFUNC BOleSite::Lock (BOOL fLock, BOOL fLastUnlockReleases) { return CoLockObjectExternal (AsPIUnknown(pObjOuter), fLock, fLastUnlockReleases); } HRESULT _IFUNC BOleSite::ShowWindow () { HRESULT hrErr = NOERROR; if (fShown) hrErr = pPart->Open(TRUE); // show window and set focus anyway else { // If there's no pClientSite, this is a linked object // if (!pClientSite) { hrErr = pPart->Open(TRUE); fShown = SUCCEEDED(hrErr); } else { // This is an embedded object. ask container to show itself and object // pClientSite->ShowObject(); if (!fInPlaceActive) { hrErr = pPart->Open(TRUE); // show app main window fShown = SUCCEEDED(hrErr); if (fShown) // show open edit hatching pClientSite->OnShowWindow (TRUE); } else fShown = TRUE; } if (fShown) Lock (TRUE, FALSE); // lock document till window is hidden } return hrErr; } HRESULT _IFUNC BOleSite::HideWindow (BOOL fShutdown) { HRESULT hrErr = NOERROR; if (fShown) { fShown = FALSE; // If there's no pClientSite, this is a linked object // if (!pClientSite) hrErr = pPart->Open(FALSE); else { // This is an embedded object. // inform container that our window is hiding // if (!fInPlaceVisible) { pClientSite->OnShowWindow (FALSE); // hide open edit hatching hrErr = pPart->Open(FALSE); } } // Must unlock at the bottom in case object gets deleted // Lock (FALSE, fShutdown); } return hrErr; } HRESULT _IFUNC BOleSite::AssembleMenus () { HRESULT hrErr = NOERROR; hMenuShared = CreateMenu (); if (hMenuShared) { hrErr = pIPFrame->InsertMenus (hMenuShared, &menuGroupWidths); if (hrErr == NOERROR) { hrErr = pPart->InsertMenus (hMenuShared, (BOleMenuWidths *)&menuGroupWidths); } else { // Even when the in-place container does not allow menu merging // the server must still call OleCreateMenuDescriptor(NULL) // DestroyMenu (hMenuShared); hMenuShared = NULL; } } hOleMenu = OleCreateMenuDescriptor (hMenuShared, &menuGroupWidths); if (!hOleMenu) hrErr = ResultFromScode (E_OUTOFMEMORY); return hrErr; } void _IFUNC BOleSite::DisassembleMenus () { if (hOleMenu) { OleDestroyMenuDescriptor (hOleMenu); hOleMenu = 0; } if (hMenuShared) { UINT uDeleteAt = 0; for (UINT uGroup = 0; uGroup < 6; uGroup++) { uDeleteAt += menuGroupWidths.width [uGroup++]; for (UINT uCount = 0; uCount < menuGroupWidths.width [uGroup]; uCount++) DeleteMenu (hMenuShared, uDeleteAt, MF_BYPOSITION); } if (pIPFrame) pIPFrame->RemoveMenus (hMenuShared); DestroyMenu (hMenuShared); hMenuShared = 0; } } HRESULT _IFUNC BOleSite::DoInPlaceActivate (BOOL fActivateOnly) { HRESULT hrErr = NOERROR; if (pClientSite && !fInPlaceActive /*&& !fShown*/) { hrErr = pClientSite->QueryInterface(IID_IOleInPlaceSite,&(void *)pIPSite); if (SUCCEEDED(hrErr)) { hrErr = pIPSite->CanInPlaceActivate (); if (GetScode(hrErr) == S_OK) { //returns S_FALSE instead of E_FAIL hrErr = pIPSite->OnInPlaceActivate (); if (SUCCEEDED(hrErr)) { fInPlaceActive = TRUE; hrErr = DoInPlaceShow (fActivateOnly); if (SUCCEEDED(hrErr)) hrErr = DoUIActivate (); } else { pIPSite->Release(); pIPSite = 0; } } else { pIPSite->Release(); pIPSite = 0; } } } return hrErr; } HRESULT _IFUNC BOleSite::CalcZoom( LPCRECT rcPosRect ) { SIZE sCurrent; HRESULT hr = pProvider->GetPartSize (&sCurrent); if (SUCCEEDED(hr)) { if (sCurrent.cx == 0) { scale.xN = 1; scale.xD = 1; } else { scale.xN = rcPosRect->right - rcPosRect->left; scale.xD = sCurrent.cx; } if (sCurrent.cy == 0) { scale.yN = 1; scale.yD = 1; } else { scale.yN = rcPosRect->bottom - rcPosRect->top; scale.yD = sCurrent.cy; } } return hr; } HRESULT _IFUNC BOleSite::DoInPlaceShow (BOOL fActivateOnly) { HRESULT hrErr = NOERROR; if (!fInPlaceVisible) { fInPlaceVisible = TRUE; hrErr = pIPSite->GetWindow (&hWndParent); if (SUCCEEDED(hrErr)) { frameInfo.cb = sizeof (frameInfo); hrErr = pIPSite->GetWindowContext ( &pIPFrame, &pIPDoc, &rcPosRect, &rcClipRect, &frameInfo); CalcZoom( &rcPosRect ); if (SUCCEEDED(hrErr) && pIPFrame) { // set message filter (ICS) hWndInPlace = pPart->OpenInPlace (hWndParent); AssembleMenus (); if (fInsideOut && fActivateOnly) { // show object without adornments and border pPart->SetPartPos (&rcPosRect); } } else { DoInPlaceDeactivate (); } } else { DoInPlaceDeactivate (); } } return hrErr; } HRESULT _IFUNC BOleSite::DoUIActivate () { HRESULT hrErr = NOERROR; if (!fUIActive) { fUIActive = TRUE; // // // // // // hrErr = pIPSite->OnUIActivate (); if (SUCCEEDED(hrErr)) { if (pHatchWnd) { // Put the hatch window around the inplace window. The offset // is necessary because we're reparenting the inplace window // behind the scenes, so the border of the hatch window would // throw rcPosRect off. // ::SetParent (hWndInPlace, *pHatchWnd); ::SetParent (*pHatchWnd, hWndParent); pHatchWnd->SetSize (&rcPosRect, &rcClipRect, &hatchOffset); pHatchWnd->Show (TRUE, pIPSite); ::OffsetRect (&rcPosRect, hatchOffset.x, hatchOffset.y); } pPart->SetPartPos (&rcPosRect); pPart->Show(TRUE); // Show after SetPos to prevent flashing // window position of part may need to move but the extent // should be the same pPart->Activate (TRUE); pIPFrame->SetActiveObject (this, pInPlaceName); if (pIPDoc) pIPDoc->SetActiveObject (this, pInPlaceName); pIPFrame->SetMenu (hMenuShared, hOleMenu, hWndInPlace); pPart->ShowTools (TRUE); } else { fUIActive = FALSE; } } return hrErr; } HRESULT _IFUNC BOleSite::DoInPlaceDeactivate () { HRESULT hrErr = NOERROR; if (fInPlaceActive) { hrErr = DoUIDeactivate (); if (SUCCEEDED(hrErr) && fInPlaceActive) { fInPlaceActive = FALSE; pIPSite->OnInPlaceDeactivate (); pIPSite->Release(); pIPSite = 0; } } return hrErr; } HRESULT _IFUNC BOleSite::DoUIDeactivate () { if (!SUCCEEDED(pPart->Show (FALSE))) return ResultFromScode (E_FAIL); // Hide here to match Show which prevents flashing HRESULT hrErr = NOERROR; if (fUIActive) { fUIActive = FALSE; // // // // // // // remove shading and adornments if (pIPDoc) pIPDoc->SetActiveObject (NULL, NULL); if (pIPFrame) pIPFrame->SetActiveObject (NULL, NULL); pPart->ShowTools (FALSE); pIPSite->OnUIDeactivate (FALSE); // deactivate contained objects if any if (!fInsideOut) { DoInPlaceHide (); if (pIPFrame) { pIPFrame->Release(); pIPFrame = 0; } if (pIPDoc) { pIPDoc->Release(); pIPDoc = 0; } } } return hrErr; } HRESULT _IFUNC BOleSite::DoInPlaceHide () { HRESULT hrErr = NOERROR; if (fInPlaceVisible) { // deactivate contained objects (ICS) // remove shading and adornments (ICS) hrErr = pPart->OpenInPlace (0) == NULL ? ResultFromScode (E_FAIL) : NOERROR; if (pHatchWnd) // Hide the hatch window // pHatchWnd->Show (FALSE); // set filter ? (ICS) DisassembleMenus (); HideWindow (FALSE); fInPlaceVisible = FALSE; } return hrErr; } HRESULT _IFUNC BOleSite::DoVerb (LONG lVerb, LPMSG lpmsg, IOleClientSite* pActiveSite, LONG lindex, HWND hwndParent, LPCRECT lprcPosRect) { HRESULT hrErr = NOERROR; switch (lVerb) { default: // First ask the server app if it knows this verb // hrErr = pPart->DoVerb ((UINT)lVerb); if (SUCCEEDED(hrErr)) return hrErr; // If the server app doesn't know it, and it's a predefined (<0) // verb, return an error // hrErr = ResultFromScode (OLEOBJ_S_INVALIDVERB); if (lVerb < 0) OLERES(hrErr); // If it's not a predefined verb and we don't know it, deliberately // fall through to Primary Verb case OLEIVERB_PRIMARY: case OLEIVERB_SHOW: // If the window is already open (primary verb has already been // run, just bring the window to the front // if (pClientSite && !fShown && !fInPlaceActive && (S_OK == GetScode(pPart->CanOpenInPlace()))) hrErr = DoInPlaceActivate (FALSE); else if (fInPlaceActive && !fInPlaceVisible) { if (SUCCEEDED(DoInPlaceShow (FALSE))) { hrErr = DoUIActivate (); } } hrErr = ShowWindow (); break; case 1: case OLEIVERB_OPEN: if (pClientSite && fInPlaceActive) hrErr = DoInPlaceDeactivate (); hrErr = ShowWindow (); break; case OLEIVERB_HIDE: if (pClientSite && fInPlaceActive) hrErr = DoInPlaceHide (); else hrErr = HideWindow (TRUE /*fShutdown*/); break; case OLEIVERB_UIACTIVATE: case OLEIVERB_INPLACEACTIVATE: // If our window is already open-editing we can't activate in-place. // if (pClientSite && !fShown && !fInPlaceActive && (S_OK == GetScode(pPart->CanOpenInPlace()))) hrErr = DoInPlaceActivate (lVerb == OLEIVERB_INPLACEACTIVATE); else hrErr = ResultFromScode (OLE_E_NOT_INPLACEACTIVE); break; } return hrErr; } HRESULT _IFUNC BOleSite::EnumVerbs (IEnumOLEVERB* FAR* ppenumOleVerb) { return OleRegEnumVerbs(cid, ppenumOleVerb); // // } HRESULT _IFUNC BOleSite::Update () { return ResultFromScode(S_OK); } HRESULT _IFUNC BOleSite::IsUpToDate () { return ResultFromScode(MK_E_UNAVAILABLE); } HRESULT _IFUNC BOleSite::GetUserClassID (CLSID FAR* pClsid) { *pClsid = cid; return NOERROR; } HRESULT _IFUNC BOleSite::GetUserType (DWORD dwFormOfType, LPOLESTR FAR* pszUserType) { return ResultFromScode (OLE_S_USEREG); } HRESULT _IFUNC BOleSite::SetExtent (DWORD dwDrawAspect, LPSIZEL lpsizel) { RECT pos; pos.left = pos.top = 0; pos.right = MAP_LOGHIM_TO_PIX (lpsizel->cx, BOleService::pixPerIn.x); pos.bottom = MAP_LOGHIM_TO_PIX (lpsizel->cy, BOleService::pixPerIn.y); SIZE size; size.cx = pos.right; size.cy = pos.bottom; HRESULT hr = pPart->SetPartSize(&size); if (SUCCEEDED(hr)) { Invalidate(BOLE_INVAL_VIEW); pPart->SetPartPos (&pos); } // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // return hr; } HRESULT _IFUNC BOleSite::GetExtent (DWORD dwDrawAspect, LPSIZEL lpsizel) { if (dwDrawAspect != DVASPECT_CONTENT) //PHP for now. return ResultFromScode (E_FAIL); if (!lpsizel) return ResultFromScode (E_INVALIDARG); SIZE s; HRESULT hr = pProvider->GetPartSize (&s); //PHP do we need aspect here? lpsizel->cx = MAP_PIX_TO_LOGHIM (s.cx, BOleService::pixPerIn.x); lpsizel->cy = MAP_PIX_TO_LOGHIM (s.cy, BOleService::pixPerIn.y); return hr; } HRESULT _IFUNC BOleSite::Advise (IAdviseSink* pAdvSink, DWORD FAR* pdwConnection) { HRESULT hrErr; *pdwConnection = 0; if (pAdvHolder == 0) hrErr = CreateOleAdviseHolder (&pAdvHolder); if (pAdvHolder) hrErr = pAdvHolder->Advise (pAdvSink, pdwConnection); else hrErr = ResultFromScode (E_OUTOFMEMORY); return hrErr; } HRESULT _IFUNC BOleSite::Unadvise (DWORD dwConnection) { HRESULT hrErr = ResultFromScode (E_FAIL); if (pAdvHolder) hrErr = pAdvHolder->Unadvise (dwConnection); return hrErr; } HRESULT _IFUNC BOleSite::EnumAdvise (IEnumSTATDATA* FAR* ppenumAdvise) { HRESULT hrErr = ResultFromScode (E_FAIL); if (pAdvHolder) hrErr = pAdvHolder->EnumAdvise (ppenumAdvise); return hrErr; } HRESULT _IFUNC BOleSite::GetMiscStatus (DWORD dwAspect, DWORD FAR* pdwStatus) { return ResultFromScode (OLE_S_USEREG); } HRESULT _IFUNC BOleSite::SetColorScheme (LPLOGPALETTE lpLogpal) { return ResultFromScode (E_NOTIMPL); } //************************************************************************** // // IPersist implementation // //************************************************************************** HRESULT _IFUNC BOleSite::GetClassID (LPCLSID lpClassID) { *lpClassID = cid; return NOERROR; } HRESULT _IFUNC BOleSite::IsDirty () { return ResultFromScode((fIsDirty) ? S_OK : S_FALSE); } //************************************************************************** // // IPersistStorage implementation // //************************************************************************** HRESULT _IFUNC BOleSite::InitNew (IStorage* pStgNew) { if (pStg) { pStg->Release (); pStg = NULL; } pStg = pStgNew; if (pStg) { pStg->AddRef(); } BOleInitInfo bi; bi.pContainer = NULL; bi.Where = BOLE_NEW; bi.How = BOLE_EMBED; bi.pStorage = pStgNew; HRESULT hr = pPart->Init(this, &bi); if (!SUCCEEDED(hr)) return hr; Invalidate(BOLE_INVAL_DATA); return ResultFromScode(S_OK); } HRESULT _IFUNC BOleSite::Load (IStorage* pStgFrom) { HRESULT hresult = NOERROR; fIsDirty = FALSE; // data will be the same as what was saved if (pStg) { pStg->Release (); pStg= NULL; } pStg = pStgFrom; pStg->AddRef(); BOleInitInfo bi; bi.pContainer = NULL; bi.Where = BOLE_STORAGE; bi.How = BOLE_EMBED; bi.pStorage = pStg; hresult = pPart->Init (this, &bi); return hresult; } HRESULT _IFUNC BOleSite::Save (IStorage* pStgSave, BOOL fSameAsLoad) { // if (fSameAsLoad && !fIsDirty) // don't bother, its up to date // return NOERROR; HRESULT hresult = ResultFromScode(S_OK); if (!pStgSave && fSameAsLoad) pStgSave = pStg; // The online dox say that OleSave does this, but there's no // CompObj stream without WriteFmtUseTypeStg and no CLSID in the // stream without WriteClassStg // CLSID clsid = CLSID_NULL; CLSIDFromProgID (pszProgID, &clsid); if ((hresult = WriteClassStg (pStgSave, clsid)) != NOERROR) return hresult; LPOLESTR lpLongType = NULL; OleRegGetUserType (clsid, USERCLASSTYPE_FULL, &lpLongType); hresult = WriteFmtUserTypeStg (pStgSave, BOleDocument::oleEmbSrcClipFmt, lpLongType); // We pass along the fHandsOff flag here to "fRemember" // If HandsOffStorage was called before it means SaveAs is happening // and objects need to remember their new substorages as they create them. // We use the fRemember flag to do what what HandsOffStorage and // SaveCompleted do (we can't scribble to storages between saves anyway) if (SUCCEEDED(pProvider->Save( pStgSave, fSameAsLoad, fHandsOff))) { // since we don't scribble, do the SaveCompleted stuff here // where we know fSameAsLoad if (fHandsOff || fSameAsLoad) { // ! save copy as situation fIsDirty = FALSE; if (pAdvHolder) hresult = pAdvHolder->SendOnSave(); if (fHandsOff) { fHandsOff = FALSE; pStg = pStgSave; // pStg was Released in HandsOffStorage if (pStg) pStg->AddRef(); } } } else hresult = ResultFromScode(STG_E_CANTSAVE); return hresult; } HRESULT _IFUNC BOleSite::SaveCompleted (IStorage* pStgNew) { if (fHandsOff) { // HandsOffStorage, SaveCompleted without Save Save(pStgNew, FALSE); } return ResultFromScode(S_OK); } HRESULT _IFUNC BOleSite::HandsOffStorage () { fHandsOff = TRUE; if (pStg) { pStg->Release(); pStg = NULL; } return ResultFromScode(S_OK); } //************************************************************************** // // IDropSource implementation // //************************************************************************** HRESULT _IFUNC BOleSite::QueryContinueDrag (BOOL fEscapePressed, DWORD grfKeyState) { if (fEscapePressed) { OLERET (DRAGDROP_S_CANCEL); } if (!(grfKeyState & (MK_LBUTTON))) { OLERET (DRAGDROP_S_DROP); } return ResultFromScode(S_OK); } HRESULT _IFUNC BOleSite::GiveFeedback (DWORD dwEffect) { POINT p = {0,0}; BOOL fNearScroll = FALSE; // // of IBDataProvider so we can do drag/drop with only a provider // if (!pPart) return ResultFromScode (DRAGDROP_S_USEDEFAULTCURSORS); if (S_OK == GetScode(pPart->DragFeedback (&p, fNearScroll))) { return ResultFromScode (DRAGDROP_S_USEDEFAULTCURSORS); } else { return ResultFromScode (S_OK); } } //************************************************************************** // // IOleWindow implementation // //************************************************************************** HRESULT _IFUNC BOleSite::GetWindow (HWND FAR* lphwnd) { if (lphwnd) { *lphwnd = hWndInPlace; return NOERROR; } return ResultFromScode (E_INVALIDARG); } HRESULT _IFUNC BOleSite::ContextSensitiveHelp (BOOL fEnterMode) { return pService->ContextSensitiveHelp (fEnterMode); } //************************************************************************** // // IOleInPlaceObject implementation // //************************************************************************** HRESULT _IFUNC BOleSite::InPlaceDeactivate () { return DoInPlaceDeactivate (); } HRESULT _IFUNC BOleSite::UIDeactivate () { return DoUIDeactivate (); } HRESULT _IFUNC BOleSite::SetObjectRects (LPCRECT lprcPosRect, LPCRECT lprcClipRect) { rcPosRect = *lprcPosRect; rcClipRect = *lprcClipRect; RECT r; if (pHatchWnd) { // if (! fUIActive) // hatch and adornments should not be drawn // lprcClipRect = lprcPosRect; pHatchWnd->SetSize (&rcPosRect, &rcClipRect, &hatchOffset); r = rcPosRect; // offset hatch border ::OffsetRect (&r, hatchOffset.x, hatchOffset.y); } else r = rcPosRect; CalcZoom (lprcPosRect); pPart->SetPartPos (&r); return NOERROR; } HRESULT _IFUNC BOleSite::GetZoom( BOleScaleFactor *pScale) { if (fInPlaceActive) { *pScale = scale; } else { pScale->xN = 1; pScale->yN = 1; pScale->xD = 1; pScale->yD = 1; } return NOERROR; } HRESULT _IFUNC BOleSite::ReactivateAndUndo () { HRESULT hrErr; if (pClientSite && !fShown && !fInPlaceActive && (S_OK == GetScode(pPart->CanOpenInPlace()))) hrErr = DoInPlaceActivate (OLEIVERB_INPLACEACTIVATE); else hrErr = ResultFromScode (OLE_E_NOT_INPLACEACTIVE); // do undo? return hrErr; } //************************************************************************** // // IOleInPlaceActiveObject implementation // //************************************************************************** HRESULT _IFUNC BOleSite::TranslateAccelerator (LPMSG lpmsg) { return ResultFromScode (E_NOTIMPL); } HRESULT _IFUNC BOleSite::OnFrameWindowActivate (BOOL fActivate) { // post message to server app ? (ICS) return NOERROR; } HRESULT _IFUNC BOleSite::OnDocWindowActivate (BOOL fActivate) { if (fActivate) { pIPFrame->SetActiveObject ((IOleInPlaceActiveObject *)this, pInPlaceName); pIPFrame->SetMenu (hMenuShared, hOleMenu, hWndInPlace); pPart->ShowTools (TRUE); } else { pIPFrame->SetActiveObject (NULL, NULL); pPart->ShowTools (FALSE); // deactivate contained objects if any (ICS) } return NOERROR; } HRESULT _IFUNC BOleSite::ResizeBorder (LPCRECT lprectBorder, LPOLEINPLACEUIWINDOW lpUIWindow, BOOL fFrameWindow) { pPart->FrameResized(lprectBorder, fFrameWindow); return ResultFromScode(S_OK); } HRESULT _IFUNC BOleSite::EnableModeless (BOOL fEnable) { return pService->GetApplication()->OnModalDialog (!fEnable); } //************************************************************************** // // IContainer implementation // //************************************************************************** HRESULT _IFUNC BOleSite::AllowInPlace() { // anything we can use this for on server side?? return ResultFromScode (E_NOTIMPL); } HRESULT _IFUNC BOleSite::BringToFront() { // anything we can use this for on server side?? return ResultFromScode (E_NOTIMPL); } HRESULT _IFUNC BOleSite::FindDropDest (LPPOINT, PIBDropDest FAR*) { // anything we can use this for on server side?? return ResultFromScode (E_NOTIMPL); } HWND _IFUNC BOleSite::GetWindow() { HWND hWnd; return (pIPSite && pIPSite->GetWindow (&hWnd) == NOERROR) ? hWnd : 0; } HRESULT _IFUNC BOleSite::GetWindowRect(LPRECT pR) { if (pIPDoc) return pIPDoc->GetBorder (pR); return ResultFromScode (E_FAIL); } HRESULT _IFUNC BOleSite::RequestBorderSpace(LPCRECT pR) { BORDERWIDTHS r; if (pR) { r = *pR; // Word bums modify our LPCRECT contents pR = &r; } if (pIPDoc) return pIPDoc->RequestBorderSpace (pR); return ResultFromScode (E_FAIL); } HRESULT _IFUNC BOleSite::SetBorderSpace(LPCRECT pR) { BORDERWIDTHS r; if (pR) { r = *pR; // Word bums modify our LPCRECT contents pR = &r; } if (pIPDoc) return pIPDoc->SetBorderSpace (pR); return ResultFromScode (E_FAIL); } LPCOLESTR _IFUNC BOleSite::GetWindowTitle() { return pWindowTitle; } void _IFUNC BOleSite::AppendWindowTitle(LPCOLESTR) { //PHP Do we need to call SetActiveObject??? } //************************************************************************** // // ISite implementation // //************************************************************************** HRESULT _IFUNC BOleSite::SiteShow(BOOL) { return ResultFromScode (E_NOTIMPL); } HRESULT _IFUNC BOleSite::DiscardUndo() { return ResultFromScode (E_NOTIMPL); } HRESULT _IFUNC BOleSite::GetSiteRect(LPRECT prcPos,LPRECT prcClip) { if( prcPos ) *prcPos = rcPosRect; if( prcClip ) *prcClip = rcClipRect; return NOERROR; } HRESULT _IFUNC BOleSite::SetSiteRect(LPCRECT pR) { // Can be useful for hatch window implementations or resizing // the server when in-place active HRESULT hr; SIZE s; s.cx = pR->right - pR->left; s.cy = pR->bottom - pR->top; if (SUCCEEDED(hr = SetSiteExtent(&s))) { // Ask the client to resize to the new size of the window if (pIPSite) { hr = pIPSite->OnPosRectChange (pR); } } return hr; } HRESULT _IFUNC BOleSite::SetSiteExtent (LPCSIZE pS) { SIZE s = *pS; // Servers call this to update their own scaled size // and notify the container of the change BOleScaleFactor scale; GetZoom(&scale); s.cx = s.cx * scale.xD / scale.xN; // unscale s.cy = s.cy * scale.yD / scale.yN; HRESULT hr = pPart->SetPartSize(&s); if (SUCCEEDED(hr)) { // Invalidate the metafile since it's size has changed Invalidate(BOLE_INVAL_VIEW); } return hr; } void _IFUNC BOleSite::Invalidate(BOleInvalidate inval) { // The PERSISTENT flag is used for servers "Update" menu. // if (inval & BOLE_INVAL_PERSISTENT && pClientSite) { pClientSite->SaveObject (); fIsDirty = FALSE; } // We're not distinguishing between the other two flags on the // server side // if (inval & BOLE_INVAL_VIEW || inval & BOLE_INVAL_DATA) { fIsDirty = TRUE; if (pDAdvHolder) pDAdvHolder->SendOnDataChange (this, 0, 0); } } void _IFUNC BOleSite::OnSetFocus(BOOL bSet) { pService->SetFocusedSite( bSet ? this : NULL ); } void _IFUNC BOleSite::Disconnect () { // // // Close(OLECLOSE_SAVEIFDIRTY); } //************************************************************************** // // IApplication implementation // //************************************************************************** LPCOLESTR _IFUNC BOleSite::IBApplicationImpl::GetAppName() { return pThis->pAppName; } // This is called when an inplace active object receives a Shift-F1 // keystroke. We need to call our container so that other objects can // be prepared to give context-sensitive help if clicked. // BOleHelp _IFUNC BOleSite::IBApplicationImpl::HelpMode (BOleHelp newMode) { BOleHelp oldMode = (BOleHelp) pThis->fInHelpMode; if (newMode != BOLE_HELP_GET) if (pThis->pIPSite) { pThis->fInHelpMode = newMode == BOLE_HELP_ENTER; pThis->pIPSite->ContextSensitiveHelp (pThis->fInHelpMode); } return oldMode; } HRESULT _IFUNC BOleSite::IBApplicationImpl::InsertContainerMenus(HMENU hMenu,BOleMenuWidths FAR* pMW) { return pThis->InsertContainerMenus(hMenu, pMW); } HRESULT _IFUNC BOleSite::IBApplicationImpl::SetFrameMenu (HMENU h) { return pThis->SetFrameMenu(h); } HRESULT _IFUNC BOleSite::IBApplicationImpl::Accelerator(MSG FAR*pMsg) { return pThis->Accelerator(pMsg); } HRESULT _IFUNC BOleSite::IBApplicationImpl::GetAccelerators (HACCEL FAR*, int FAR*) { return ResultFromScode (E_NOTIMPL); } HRESULT _IFUNC BOleSite::IBApplicationImpl::CanLink() { return ResultFromScode (E_NOTIMPL); } HRESULT _IFUNC BOleSite::IBApplicationImpl::CanEmbed() { return ResultFromScode (E_NOTIMPL); } HWND _IFUNC BOleSite::IBApplicationImpl::GetWindow () { HWND hWnd; return (pThis->pIPFrame && pThis->pIPFrame->GetWindow (&hWnd) == NOERROR) ? hWnd : 0; } HRESULT _IFUNC BOleSite::IBApplicationImpl::RequestBorderSpace (LPCRECT pR) { BORDERWIDTHS r; if (pR) { r = *pR; // Word modifies our LPCRECT contents pR = &r; } if (pThis->pIPFrame) return pThis->pIPFrame->RequestBorderSpace (pR); return ResultFromScode (E_FAIL); } HRESULT _IFUNC BOleSite::IBApplicationImpl::SetBorderSpace (LPCRECT pR) { BORDERWIDTHS r; if (pR) { r = *pR; // Word bums modify our LPCRECT contents pR = &r; } if (pThis->pIPFrame) return pThis->pIPFrame->SetBorderSpace (pR); return ResultFromScode (E_FAIL); } void _IFUNC BOleSite::IBApplicationImpl::AppendWindowTitle (LPCOLESTR s) { if (pThis->pIPFrame) pThis->pIPFrame->SetActiveObject(pThis, s); } HRESULT _IFUNC BOleSite::IBApplicationImpl::SetStatusText (LPCOLESTR s) { if (pThis->pIPFrame) return pThis->pIPFrame->SetStatusText(s); return ResultFromScode(E_FAIL); } HRESULT _IFUNC BOleSite::IBApplicationImpl::IsMDI () { if (pThis->pIPDoc) return ResultFromScode (S_OK); else return ResultFromScode (S_FALSE); } HRESULT _IFUNC BOleSite::IBApplicationImpl::OnModalDialog (BOOL fDialogComingActive) { return (pThis->pIPFrame) ? pThis->pIPFrame->EnableModeless (!fDialogComingActive) : NOERROR; } void _IFUNC BOleSite::IBApplicationImpl::RestoreUI () { //PHP Server object should use this instead of SetBorderSpace(NULL) // and AppendWindowTitle(NULL). Semantics are much cleaner. } void _IFUNC BOleSite::IBApplicationImpl::DialogHelpNotify (BOleDialogHelp helpCode) { // unimplemented in server side helper } void _IFUNC BOleSite::IBApplicationImpl::ShutdownMaybe () { // unimplemented in server side helper } // // ILinkable // HRESULT _IFUNC BOleSite::GetMoniker(IMoniker FAR* FAR* ppMon) { return GetMoniker(OLEGETMONIKER_ONLYIFTHERE, OLEWHICHMK_OBJFULL, ppMon); } HRESULT _IFUNC BOleSite::OnRename(PIBLinkable pCont, LPCOLESTR szName) { HRESULT ret = NOERROR; if (pCont) pCont->GetMoniker(&pmkDoc); else if (pmkDoc) { // Reset cached format list to cause it to be updated next time // (now that link format is enabled/disabled). // // if (formatList) { delete [] formatList; formatLink = FALSE; formatEmbed = FALSE; formatList = NULL; formatCount = 0; } if (pService->IsOnClipboard(this)) { // remove the linking capability from this object if one calls // OnRename(NULL, NULL) before Close rather during Close // // AddRef(); pService->Clip(NULL, FALSE, FALSE, FALSE); pService->Clip(pProvider, FALSE, pService->clipOkToEmbed, FALSE); Release(); } if (pmkDoc) { pmkDoc->Release(); pmkDoc = NULL; } } if (pszInstName) { delete [] pszInstName; pszInstName = NULL; } if (szName) { pszInstName = new OLECHAR[strlen (szName) +1]; lstrcpy(pszInstName, szName); } // Don't register if this is a clone (pPart is NULL) // otherwise we would link to what's on the clipboard... // // Also don't bother if it is only a document (no item name) // (pszInstName may be NULL and pmkDoc valid, in that case // we shouldn't register here. BOleContainer already registered it. // // if (pPart && pmkDoc && pszInstName) SetMoniker(OLEWHICHMK_OBJFULL, NULLP); // register if (!pmkDoc && (regLink != 0L)) { // Unregister for linking if pmkDoc is NULL LPRUNNINGOBJECTTABLE pROT = NULL; HRESULT hr = OLE::GetRunningObjectTable (0, &pROT); if (SUCCEEDED(hr)) { pROT->Revoke(regLink); regLink = 0L; pROT->Release(); } } return ret; } HRESULT _IFUNC BOleSite::SetStatusText (LPCOLESTR s) { if (pIPFrame) return pIPFrame->SetStatusText(s); return ResultFromScode(E_FAIL); } LPCOLESTR _IFUNC BOleSite::IBApplicationImpl::GetWindowTitle() { return pThis->pWindowTitle; } HRESULT _IFUNC BOleSite::IBApplicationImpl::GetWindowRect(LPRECT pR) { if (pThis->pIPFrame) return pThis->pIPFrame->GetBorder (pR); return ResultFromScode(CO_E_OBJNOTCONNECTED); } HRESULT _IFUNC BOleSite::GetAccelerators( HACCEL FAR *,int far*) { return ResultFromScode (E_NOTIMPL); } HRESULT _IFUNC BOleSite::Accelerator(MSG FAR*pMsg) { // Give the container a chance to handle its accelerators. // Returns S_OK if processed or S_FALSE if no accelerator was met. if (pIPFrame) return OleTranslateAccelerator( pIPFrame, &frameInfo, pMsg ); return ResultFromScode(S_FALSE); } void _IFUNC BOleSite::RestoreUI() { } // This little trick allows Bolero servers to dynamically renegotiate // the menu bar in case some state changes while they're inplace active // HRESULT _IFUNC BOleSite::SetFrameMenu(HMENU) { // First get the client to let go of the menus so we can put new ones up // if (pIPFrame) pIPFrame->SetMenu (NULL, hOleMenu, hWndInPlace); DisassembleMenus (); // Tear down the old shared menu HRESULT hr = AssembleMenus (); // Put together a new shared menu if (!SUCCEEDED(hr)) return hr; // Tell the client to install it return pIPFrame->SetMenu (hMenuShared, hOleMenu, hWndInPlace); } HRESULT _IFUNC BOleSite::InsertContainerMenus(HMENU hMenu,BOleMenuWidths far*) { if (pIPFrame) return pIPFrame->InsertMenus (hMenu, &menuGroupWidths); return ResultFromScode (CO_E_OBJNOTCONNECTED); }