📄 dsofdocobj.cpp
字号:
if (SUCCEEDED(hr = pipf->Load(pwszFile, dwBindFlgs)) &&
SUCCEEDED(hr = pipf->QueryInterface(IID_IPersistStorage, (void**)&pipstg)))
{
if (SUCCEEDED(hr = pipstg->Save(m_pstgfile, FALSE)))
hr = pipstg->SaveCompleted(NULL);
pipstg->Release();
}
pipf->Release();
}
}
else
{
// Other non-BIFF files that are associated with Office (like *.rtf/*.csv)
// we can open based on a moniker. This is a more traditional (i.e., OLE
// "Insert From File") way of binding, which uses an inproc handler...
if (SUCCEEDED(hr = CreateFileMoniker(pwszFile, &pmkfile)))
{
if (SUCCEEDED(hr = CreateBindCtx(0, &pbctx)))
{
// We ask for IPersistStorage and do a formal Save to our IStorage...
if (SUCCEEDED(hr = pmkfile->BindToObject(pbctx, NULL, IID_IPersistStorage, (void**)&pipstg)))
{
if (SUCCEEDED(hr = pipstg->Save(m_pstgfile, FALSE)))
hr = pipstg->SaveCompleted(NULL);
pipstg->Release();
}
else if (hr == E_NOINTERFACE) // Somehow we got a server that doesn't handle OLE embedding...
hr = STG_E_NOTFILEBASEDSTORAGE;
if (SUCCEEDED(hr) && (!fReadOnly))
{
// If we have our copy and user wants to keep a lock on original source,
// we'll try to get the lock by asking for the file's IStorage...
BIND_OPTS bopts = {sizeof(BIND_OPTS), 1, dwBindFlgs, 0};
pbctx->SetBindOptions(&bopts);
pmkfile->BindToStorage(pbctx, NULL, IID_IStorage, (void**)&pstg);
}
pbctx->Release();
}
pmkfile->Release();
}
}
// Assuming everything above worked...
if (SUCCEEDED(hr))
{
// We are read-only until told otherwise...
m_fOpenReadOnly = TRUE;
m_pwszSourceFile = DsoCopyString(pwszFile);
m_idxSourceName = CalcDocNameIndex(m_pwszSourceFile);
// Let's go ahead and create the object, and keep the lock pointers...
if (SUCCEEDED(hr = CreateDocObject(clsid)) && (fReadOnly == FALSE))
{
m_fOpenReadOnly = FALSE;
SAFE_SET_INTERFACE(m_pstgSourceFile, pstg);
}
}
// If we aren't locking, this will free the file...
if (pstg) pstg->Release();
return hr;
}
////////////////////////////////////////////////////////////////////////
// CDsoDocObject::LoadStorageFromURL
//
// Loads the internal IStorage from a URL (http: or https:).
//
// The idea here is we do a download from the URL and open the result
// as any other file using LoadStorageFromFile. This requires MSDAIPP
// which ships with MDAC 2.5, Office 2000/XP, or Windows 2000/XP.
//
STDMETHODIMP CDsoDocObject::LoadStorageFromURL(LPWSTR pwszURL, REFCLSID rclsid, BOOL fReadOnly, LPWSTR pwszUserName, LPWSTR pwszPassword)
{
HRESULT hr;
IStream *pstmWebResource = NULL;
LPWSTR pwszTempFile;
// We will need access to MSDAIPP unless it is read-only request...
if (!(m_punkRosebud) && !(m_punkRosebud = CreateRosebudIPP()) && (!fReadOnly))
return DSO_E_REQUIRESMSDAIPP;
// Get the temp path for download...
if (!GetTempPathForURLDownload(pwszURL, &pwszTempFile))
return E_INVALIDARG;
// Now get the resource from URLMON or MSDAIPP...
if (SUCCEEDED(hr = DownloadWebResource(pwszURL, pwszTempFile,
pwszUserName, pwszPassword, ((fReadOnly) ? NULL : &pstmWebResource))))
{
// If that worked, open from the downloaded resource...
if (SUCCEEDED(hr = LoadStorageFromFile(pwszTempFile, rclsid, fReadOnly)) &&
((pstmWebResource) && (!fReadOnly)))
{
m_fOpenReadOnly = FALSE;
m_pwszWebResource = DsoCopyString(pwszURL);
SAFE_SET_INTERFACE(m_pstmWebResource, pstmWebResource);
}
if (pstmWebResource)
pstmWebResource->Release();
}
DsoMemFree(pwszTempFile);
return hr;
}
////////////////////////////////////////////////////////////////////////
// CDsoDocObject::LoadFromAutomationObject
//
// Copies the storage of the current automation object and loads a new
// embedded object from the persisted state. This allows you to load
// a visible instance of a document previously open and edited by automation.
//
STDMETHODIMP CDsoDocObject::LoadFromAutomationObject(LPUNKNOWN punkObj, REFCLSID rclsid, BOOL fReadOnly)
{
HRESULT hr;
IPersistStorage *prststg;
IOleObject *pole;
CLSID clsid;
ODS("CDsoDocObject::LoadFromAutomationObject()\n");
CHECK_NULL_RETURN(punkObj, E_POINTER);
// First, ensure the object passed supports embedding (i.e., we expect
// something like a Word.Document or Excel.Sheet object, not a Word.Application
// object or something else that is not a document type)...
hr = punkObj->QueryInterface(IID_IOleObject, (void**)&pole);
if (FAILED(hr)) return hr;
// Ask the object to save its persistent state. We also collect its CLSID and
// validate that the object type supports DocObject embedding...
hr = pole->QueryInterface(IID_IPersistStorage, (void**)&prststg);
if (SUCCEEDED(hr))
{
hr = prststg->GetClassID(&clsid); // Validate the object type...
if (FAILED(hr) || ((clsid == GUID_NULL) && ((clsid = rclsid) == GUID_NULL)) ||
FAILED(ValidateDocObjectServer(clsid)))
{
hr = DSO_E_INVALIDSERVER;
}
else
{
// Create a matching storage for the object and save the current
// state of the file in our storage (this is our private copy)...
if (SUCCEEDED(hr = CreateObjectStorage(clsid)) &&
SUCCEEDED(hr = prststg->Save(m_pstgfile, FALSE)) &&
SUCCEEDED(hr = prststg->SaveCompleted(NULL)))
{
// At this point we have a read-only copy...
// prststg->HandsOffStorage();
m_fOpenReadOnly = TRUE;
// Create the embedding...
hr = CreateDocObject(clsid);
// If caller wants us to keep track of file for save (write access)
// we can do so with moniker. Keep in mind this is does not keep a
// lock on the resource and may fail the save if auto object is still
// open and has exclusive access at time of the save, but it is the
// best option we have when DocObject is loaded from an object already
// open and locked by another application or component.
if (SUCCEEDED(hr) && (!fReadOnly))
{
IPersistMoniker *prstmk = NULL;
IMoniker *pmk = NULL;
if (SUCCEEDED(pole->GetMoniker(OLEGETMONIKER_FORCEASSIGN, OLEWHICHMK_OBJFULL, &pmk)) ||
(SUCCEEDED(pole->QueryInterface(IID_IPersistMoniker, (void**)&prstmk)) &&
SUCCEEDED(prstmk->GetCurMoniker(&pmk))))
{
// Keep hold of the source moniker...
m_fOpenReadOnly = FALSE;
m_pmkSourceObject = pmk;
#ifdef _DEBUG // For debug trace, we output moniker name we will keep for write...
LPOLESTR postr = NULL; IBindCtx *pbc = NULL;
if (SUCCEEDED(CreateBindCtx(0, &pbc)))
{
if (SUCCEEDED(pmk->GetDisplayName(pbc, NULL, &postr)))
{
TRACE1(" >> Write Moniker = %S \n", postr);
CoTaskMemFree(postr);
}
pbc->Release();
}
#endif //_DEBUG
}
SAFE_RELEASE_INTERFACE(prstmk);
}
}
}
prststg->Release();
}
pole->Release();
return hr;
}
////////////////////////////////////////////////////////////////////////
// CDsoDocObject::EnsureOleServerRunning
//
// Verifies the DocObject server is running and is optionally locked
// while the embedding is taking place.
//
STDMETHODIMP CDsoDocObject::EnsureOleServerRunning(BOOL fLockRunning)
{
HRESULT hr = S_FALSE;
IBindCtx *pbc;
IRunnableObject *pro;
IOleContainer *pocnt;
BIND_OPTS bind;
TRACE1("CDsoDocObject::EnsureOleServerRunning(%d)\n", (DWORD)fLockRunning);
ASSERT(m_pole);
if (FAILED(CreateBindCtx(0, &pbc)))
return E_UNEXPECTED;
// Setup the bind options for the run operation...
bind.cbStruct = sizeof(BIND_OPTS);
bind.grfFlags = BIND_MAYBOTHERUSER;
bind.grfMode = STGM_READWRITE|STGM_SHARE_EXCLUSIVE;
bind.dwTickCountDeadline = 20000;
pbc->SetBindOptions(&bind);
// Assume we aren't locked running...
m_fLockedServerRunning = FALSE;
// Get IRunnableObject and set server to run as OLE object. We check the
// running state first since this is proper OLE, but note that this is not
// returned from out-of-proc server, but the in-proc handler. Also note, we
// specify a timeout in case the object never starts, and "check" the object
// runs without IMessageFilter errors...
if (SUCCEEDED(m_pole->QueryInterface(IID_IRunnableObject, (void**)&pro)))
{
// If the object is not currently running, let's run it...
if (!(pro->IsRunning()))
hr = pro->Run(pbc);
// Set the object server as a contained object (i.e., OLE object)...
pro->SetContainedObject(TRUE);
// Lock running if desired...
if (fLockRunning)
m_fLockedServerRunning = SUCCEEDED(pro->LockRunning(TRUE, TRUE));
pro->Release();
}
else if ((fLockRunning) &&
SUCCEEDED(m_pole->QueryInterface(IID_IOleContainer, (void**)&pocnt)))
{
m_fLockedServerRunning = SUCCEEDED(pocnt->LockContainer(TRUE));
pocnt->Release();
}
pbc->Release();
return hr;
}
////////////////////////////////////////////////////////////////////////
// CDsoDocObject::FreeRunningLock
//
// Free any previous lock made by EnsureOleServerRunning.
//
STDMETHODIMP_(void) CDsoDocObject::FreeRunningLock()
{
IRunnableObject *pro;
IOleContainer *pocnt;
ODS("CDsoDocObject::FreeRunningLock(%d)\n");
ASSERT(m_pole);
// Don't do anything if we didn't lock the server...
if (m_fLockedServerRunning == FALSE)
return;
// Get IRunnableObject and free lock...
if (SUCCEEDED(m_pole->QueryInterface(IID_IRunnableObject, (void**)&pro)))
{
pro->LockRunning(FALSE, TRUE);
pro->Release();
}
else if (SUCCEEDED(m_pole->QueryInterface(IID_IOleContainer, (void**)&pocnt)))
{
pocnt->LockContainer(FALSE);
pocnt->Release();
}
m_fLockedServerRunning = FALSE;
return;
}
////////////////////////////////////////////////////////////////////////
// CDsoDocObject::IPActivateView
//
// Activates the object for viewing. If we already have an IOleDocumentView
// we do this by calling Show, otherwise we'll do an IOleObject::DoVerb.
//
STDMETHODIMP CDsoDocObject::IPActivateView()
{
HRESULT hr = E_UNEXPECTED;
ODS("CDsoDocObject::IPActivateView()\n");
ASSERT(m_pole);
// Normal activation uses IOleObject::DoVerb with OLEIVERB_INPLACEACTIVATE
// (or OLEIVERB_SHOW), a view rect, and an IOleClientSite pointer...
if ((m_pole) && (!m_pdocv))
{
RECT rcView; GetClientRect(m_hwnd, &rcView);
hr = m_pole->DoVerb(OLEIVERB_INPLACEACTIVATE, NULL,
(IOleClientSite*)&m_xOleClientSite, (UINT)-1, m_hwnd, &rcView);
// If the DoVerb fails on the InPlaceActivate verb, do a Show...
if (FAILED(hr))
{
DWORD dwLoopCnt = 0;
do
{
Sleep((200 * dwLoopCnt++));
hr = m_pole->DoVerb(OLEIVERB_SHOW, NULL,
(IOleClientSite*)&m_xOleClientSite, (UINT)-1, m_hwnd, &rcView);
// There are issues with Visio 2002 rejecting DoVerb calls outright
// if it is still loading (instead of returning retry later as it should).
// So we might pop out of the message filter early and fail the call
// unexpectedly, so this little hack checks for the error and sleeps,
// then calls again in a recursive "loop"...
}
while ((hr == 0x80010001) && (dwLoopCnt < 10));
}
}
else if (m_pdocv)
{
// If we have an IOleDocument pointer, we can use the "new" method
// for inplace activation via Show/UIActivate...
if (SUCCEEDED(hr = m_pdocv->Show(TRUE)))
m_pdocv->UIActivate(TRUE);
}
// Forward focus as needed...
if (SUCCEEDED(hr) && (m_hwndIPObject))
SetFocus(m_hwndIPObject);
return hr;
}
////////////////////////////////////////////////////////////////////////
// CDsoDocObject::IPDeactivateView
//
// Deactivates the object.
//
STDMETHODIMP CDsoDocObject::IPDeactivateView()
{
HRESULT hr = S_OK;
ODS("CDsoDocObject::IPDeactivateView()\n");
// If we still have a UI active object, tell it to UI deactivate...
if (m_pipactive)
UIActivateView(FALSE);
// Next hide the active object...
if (m_pdocv)
m_pdocv->Show(FALSE);
// Notify object our intention to IP deactivate...
if (m_pipobj)
m_pipobj->InPlaceDeactivate();
// Close the object down and release pointers...
if (m_pdocv)
{
hr = m_pdocv->CloseView(0);
m_pdocv->SetInPlaceSite(NULL);
}
SAFE_RELEASE_INTERFACE(m_pcmdt);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -