// //************************************************************************** // // BOleCont.cpp -- Implements the server helper for documents by masquerading // as the container object. Provides plumbing for server // linking to documents and items // // Copyright (c) 1993,94 by Borland International, Inc. All rights reserved // //************************************************************************** #include "BOleCont.h" #include "BOleFact.h" #include "BOleCMan.h" #include "BOlePart.h" // for link or embed to embedding HRESULT _IFUNC BOleContainer::QueryInterfaceMain(REFIID iid, LPVOID FAR *ppv) { HRESULT hr = ResultFromScode(E_NOINTERFACE); *ppv = NULL; // interfaces SUCCEEDED(hr = IBRootLinkable_QueryInterface(this, iid, ppv)) || SUCCEEDED(hr = IPersistFile_QueryInterface(this, iid, ppv)) || SUCCEEDED(hr = IOleItemContainer_QueryInterface(this, iid, ppv)) // // base classes || SUCCEEDED(hr = BOleComponent::QueryInterfaceMain(iid, ppv)) // helpers ; return hr; }; BOleContainer::BOleContainer (BOleClassManager *pF, IBUnknownMain * pObj) : BOleComponent(pF, pObj) { pDoc = NULL; regId = 0L; pMoniker = NULL; pClassFact = NULLP; } BOleContainer::~BOleContainer () { if (pClassFact) { pClassFact->Release (); pClassFact = NULL; } } /**************************************************************************/ // IOleItemContainer /**************************************************************************/ HRESULT _IFUNC BOleContainer::GetClassID (LPCLSID lpClassID) { HRESULT hrErr = ResultFromScode (E_FAIL); // outer could have called IRootLinkable::Init. if (lpClassID && pClassFact) { hrErr = pClassFact->GetClassID(lpClassID); } else { // this is sometimes called for documents not attached to servers! *lpClassID = CLSID_NULL; } return hrErr; } HRESULT _IFUNC BOleContainer::IsDirty () { HRESULT hrErr = ResultFromScode (S_OK); // return hrErr; } #define OLE_MAXNAMESIZE (256) HRESULT _IFUNC BOleContainer::ParseDisplayName (IBindCtx *pbc, LPOLESTR pszDisplayName, ULONG FAR* pchEaten, IMoniker* FAR* ppmk) { *ppmk = NULL; OLECHAR szItemName[OLE_MAXNAMESIZE]; OLECHAR *pszDest = szItemName; LPCTSTR pszSrc = pszDisplayName; // skip leading delimiters int cEaten = 0; while (*pszSrc != '\0' && (*pszSrc == '\\' || *pszSrc == '/' || *pszSrc == '!' || *pszSrc == '[')) { ++pszSrc; ++cEaten; } // parse next token into szItemName while (*pszSrc != '\0' && *pszSrc != '\\' && *pszSrc != '/' && *pszSrc != '!' && *pszSrc != '[' && cEaten < OLE_MAXNAMESIZE-1) { *pszDest++ = *pszSrc++; ++cEaten; } *pchEaten = cEaten; *pszDest = 0; // attempt to get the object LPUNKNOWN pUnknown; HRESULT hr = GetObject(szItemName, BINDSPEED_INDEFINITE, pbc, IID_IUnknown, &(LPVOID)pUnknown); if (SUCCEEDED(hr)) { pUnknown->Release(); // item name found -- create item moniker for it return ::CreateItemMoniker(OLESTDDELIM, szItemName, ppmk); } else { return hr; } } HRESULT _IFUNC BOleContainer::EnumObjects (DWORD, IEnumUnknown* FAR* ppenumUnknown) { HRESULT hrErr = ResultFromScode(E_NOTIMPL); *ppenumUnknown = NULLP; return hrErr; } HRESULT _IFUNC BOleContainer::LockContainer (BOOL fLock) { // Keep app from closing // pFactory->ServerCount(fLock ? +1 : -1); // Lock external, but pass FALSE as last arg, so in-proc "self" linking // work (otherwise, Close gets called). // // // // // if (fLock) AddRef(); else Release(); return NOERROR; // } HRESULT _IFUNC BOleContainer::GetObject (LPOLESTR lpszItem, DWORD dwSpeedNeeded, IBindCtx* pbc, REFIID riid, LPVOID FAR* ppvObject) { HRESULT hrErr = ResultFromScode(MK_E_NOOBJECT); *ppvObject = NULL; PIBPart pPart; if (SUCCEEDED(pDoc->GetPart(& pPart, lpszItem))) { // bind speed always INDEFINITE? p.803 IUnknown *pUnk = pPart; BOleSite *pBOleSite; BOlePart *pBOlePart; if (SUCCEEDED(pUnk->QueryInterface(IID_BOlePart, &(LPVOID)pBOlePart))) { // Link to embedding case give the real IOleObject // if (pBOlePart->pOleObject) { pUnk = pBOlePart->pOleObject; } // Links to items need to maintain locks on their document // or the ProxyManager gets hosed. // When the BOlePart goes away it unlocks this. // if (!pBOlePart->pDocument) // only ONCE pBOlePart->pDocument = AsPIUnknown(pObjOuter); CoLockObjectExternal(AsPIUnknown(pObjOuter), TRUE, TRUE); pBOlePart->Release(); } else if (SUCCEEDED(pUnk->QueryInterface(IID_BOleSite, &(LPVOID)pBOleSite))) { // Links to items need maintain locks on their documents // or the ProxyManager gets hosed. // When the BOleSite goes away it unlocks this. // if (!pBOleSite->pDocument) // only ONCE pBOleSite->pDocument = AsPIUnknown(pObjOuter); pBOleSite->pDocument = AsPIUnknown(pObjOuter); CoLockObjectExternal(AsPIUnknown(pObjOuter), TRUE, TRUE); pBOleSite->Release(); } if (SUCCEEDED(hrErr=OleRun(pUnk))) { hrErr = pUnk->QueryInterface( riid, ppvObject); } pPart->Release(); pPart = NULL; } return hrErr; } HRESULT _IFUNC BOleContainer::GetObjectStorage (LPOLESTR lpszItem, IBindCtx* pbc, REFIID riid, LPVOID FAR* ppvStorage) { *ppvStorage = NULL; if (riid != IID_IStorage) return ResultFromScode(E_UNEXPECTED); // could get part and ask for BOlePart or BOleSite // and get the pStorage out of there // noone calls this return ResultFromScode(MK_E_NOSTORAGE); } HRESULT _IFUNC BOleContainer::IsRunning (LPOLESTR lpszItem) { HRESULT hrErr = ResultFromScode(MK_E_NOOBJECT); IOleObject *pOleObj = NULL; PIBPart pPart; if (SUCCEEDED(pDoc->GetPart(&pPart, lpszItem))) { IUnknown *pUnk = pPart; // check for link to embedding case! // if so, get the IOleObject out of the Bolero helper and use that! BOlePart *pBOlePart; if (SUCCEEDED(pUnk->QueryInterface(IID_BOlePart, &(LPVOID)pBOlePart))) { if (pBOlePart->pOleObject) { pUnk = pBOlePart->pOleObject; } pBOlePart->Release(); } if (SUCCEEDED(pUnk->QueryInterface(IID_IOleObject,&(LPVOID)pOleObj))) { hrErr = OleIsRunning(pOleObj) ? NOERROR : ResultFromScode(S_FALSE); pOleObj->Release(); pOleObj = NULL; } pPart->Release(); } return hrErr; } //************************************************************************** // // IPersistFile implementation // //************************************************************************** HRESULT _IFUNC BOleContainer::Load (LPCOLESTR lpszFileName, DWORD grfMode) { HRESULT hr = NOERROR; hr = pDoc->Init(lpszFileName); return hr; } HRESULT _IFUNC BOleContainer::Save (LPCOLESTR lpszFileName, BOOL fRemember) { return ResultFromScode (E_NOTIMPL); } HRESULT _IFUNC BOleContainer::SaveCompleted (LPCOLESTR lpszFileName) { return ResultFromScode (E_NOTIMPL); } HRESULT _IFUNC BOleContainer::GetCurFile (LPOLESTR FAR* lplpszFileName) { return ResultFromScode (E_NOTIMPL); } HRESULT _IFUNC BOleContainer::OnRename(PIBLinkable pContainer, LPCOLESTR pszName) { HRESULT hr; LPMONIKER pMon; if (pszName) { LPMONIKER pmkDoc = NULL; if (pContainer && SUCCEEDED(pContainer->GetMoniker(&pmkDoc))) { // intermediate moniker LPMONIKER pmkObj = NULL; if (SUCCEEDED(CreateItemMoniker(TEXT("!"), (LPOLESTR)pszName, &pmkObj))) { hr = CreateGenericComposite(pmkDoc, pmkObj, &pMon); pmkObj->Release(); } pmkDoc->Release(); } else { // root moniker hr = OLE::CreateFileMoniker ((LPOLESTR)pszName, &pMon); } } else pMon = NULL; hr = SetMoniker (pMon); if (pMon) pMon->Release(); return hr; } //************************************************************************** // // IBLinkable implementation // //************************************************************************** HRESULT _IFUNC BOleContainer::Init( PIBContains pC, LPCOLESTR pszProgId) { pDoc = pC; pFactory->GetService()->FindClassFactory( pszProgId, &pClassFact); return pClassFact ? NOERROR : ResultFromScode (E_FAIL); } HRESULT _IFUNC BOleContainer::SetMoniker(LPMONIKER pMon) { HRESULT hr; // 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 oldRegId = regId; if (pMoniker) { pMoniker->Release(); pMoniker = NULLP; } // Store the new moniker if any if (pMon) { pMoniker = pMon; pMoniker->AddRef(); // Register in the running object table // hr = pROT->Register (0, //ROTFLAGS_REGISTRATIONKEEPSALIVE, AsPIUnknown(pObjOuter), pMoniker, ®Id); } else regId = 0L; // release any old monikers and running object table registration if (oldRegId != 0L) { pROT->Revoke(oldRegId); oldRegId = 0L; } pROT->Release(); } return hr; } HRESULT _IFUNC BOleContainer::GetMoniker(LPMONIKER *ppMon) { HRESULT hrErr = ResultFromScode (E_FAIL); if (pMoniker) { pMoniker->AddRef(); *ppMon = pMoniker; hrErr = NOERROR; } else { // Must be a nested embedding. Ask the container for one. IOleObject *pOleObj; if (SUCCEEDED(QueryInterface(IID_IOleObject, &(LPVOID)pOleObj))) { hrErr = pOleObj->GetMoniker(OLEGETMONIKER_ONLYIFTHERE, OLEWHICHMK_OBJFULL, ppMon); pOleObj->Release(); } } return hrErr; } // // // // // // // // // // // // // // // // // // // // // //