📄 olelink.cpp
字号:
// This is a part of the Microsoft Foundation Classes C++ library.
// Copyright (C) 1992-1998 Microsoft Corporation
// All rights reserved.
//
// This source code is only intended as a supplement to the
// Microsoft Foundation Classes Reference and related
// electronic documentation provided with the library.
// See these sources for detailed information regarding the
// Microsoft Foundation Classes product.
#include "stdafx.h"
#ifdef AFX_OLE3_SEG
#pragma code_seg(AFX_OLE3_SEG)
#endif
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#define new DEBUG_NEW
#define OLE_MAXNAMESIZE (256)
/////////////////////////////////////////////////////////////////////////////
// COleLinkingDoc - enables linking to embeddings (basis for server)
COleLinkingDoc::COleLinkingDoc()
{
m_dwRegister = 0;
m_pFactory = NULL;
m_bVisibleLock = FALSE;
m_bDeferErrors = FALSE;
m_pLastException = NULL;
m_lpMonikerROT = NULL;
ASSERT_VALID(this);
}
COleLinkingDoc::~COleLinkingDoc()
{
ASSERT_VALID(this);
ASSERT(!m_bVisibleLock);
DisconnectViews();
ASSERT(m_viewList.IsEmpty());
Revoke(); // cleanup naming support
ExternalDisconnect();
}
/////////////////////////////////////////////////////////////////////////////
// COleLinkingDoc moniker handling
LPMONIKER COleLinkingDoc::GetMoniker(OLEGETMONIKER nAssign)
{
USES_CONVERSION;
ASSERT_VALID(this);
// use base class implementation if no registered moniker
if (m_strMoniker.IsEmpty())
return COleDocument::GetMoniker(nAssign);
// return file moniker based on current path name
LPMONIKER lpMoniker;
CreateFileMoniker(T2COLE(m_strMoniker), &lpMoniker);
return lpMoniker;
}
BOOL COleLinkingDoc::Register(COleObjectFactory* pFactory, LPCTSTR lpszPathName)
{
USES_CONVERSION;
ASSERT_VALID(this);
ASSERT(pFactory == NULL ||
AfxIsValidAddress(pFactory, sizeof(COleObjectFactory)));
ASSERT(lpszPathName == NULL || AfxIsValidString(lpszPathName));
ASSERT(m_dwRegister == 0);
// attach the document to the server
ASSERT(m_pFactory == NULL || m_pFactory == pFactory);
m_pFactory = pFactory;
BOOL bResult = TRUE;
// create file moniker based on path name
RELEASE(m_lpMonikerROT);
m_strMoniker.Empty();
if (lpszPathName != NULL)
{
if (CreateFileMoniker(T2COLE(lpszPathName), &m_lpMonikerROT) != S_OK)
bResult = FALSE;
}
// register file moniker as running
if (m_lpMonikerROT != NULL)
{
// see if the object is already running in the ROT
LPRUNNINGOBJECTTABLE lpROT = NULL;
VERIFY(GetRunningObjectTable(0, &lpROT) == S_OK);
ASSERT(lpROT != NULL);
LPUNKNOWN lpUnk;
if (lpROT->GetObject(m_lpMonikerROT, &lpUnk) == S_OK)
{
// fatal error -- can't register same moniker twice!
lpUnk->Release();
RELEASE(m_lpMonikerROT);
return FALSE;
}
// not already running -- so ok to attempt registration
SCODE sc = lpROT->Register(NULL, (LPUNKNOWN)
GetInterface(&IID_IUnknown), m_lpMonikerROT, &m_dwRegister);
lpROT->Release();
m_strMoniker = lpszPathName;
if (sc != S_OK)
bResult = FALSE;
}
// update all objects with new moniker
POSITION pos = GetStartPosition();
COleClientItem* pItem;
while ((pItem = GetNextClientItem(pos)) != NULL)
{
if (pItem->m_bMoniker)
{
ASSERT(pItem->m_lpObject != NULL);
pItem->m_lpObject->SetMoniker(OLEWHICHMK_CONTAINER,
m_lpMonikerROT);
}
}
return bResult;
}
void COleLinkingDoc::Revoke()
{
ASSERT_VALID(this);
// revoke current registration
if (m_dwRegister != 0)
{
LPRUNNINGOBJECTTABLE lpROT = NULL;
GetRunningObjectTable(0, &lpROT);
if (lpROT != NULL)
{
lpROT->Revoke(m_dwRegister);
lpROT->Release();
}
m_dwRegister = 0;
}
RELEASE(m_lpMonikerROT);
m_strMoniker = _T("");
}
BOOL COleLinkingDoc::OnNewDocument()
{
ASSERT_VALID(this);
Revoke();
RegisterIfServerAttached(NULL, TRUE);
if (!COleDocument::OnNewDocument())
return FALSE;
AfxOleSetUserCtrl(TRUE);
return TRUE;
}
BOOL COleLinkingDoc::OnOpenDocument(LPCTSTR lpszPathName)
{
ASSERT_VALID(this);
// always register the document before opening it
Revoke();
if (!RegisterIfServerAttached(lpszPathName, FALSE))
{
// always output a trace (it is just an FYI -- not generally fatal)
TRACE1("Warning: Unable to register moniker '%s' as running\n", lpszPathName);
}
if (!COleDocument::OnOpenDocument(lpszPathName))
{
Revoke();
return FALSE;
}
// if the app was started only to print, don't set user control
CWinApp* pApp = AfxGetApp();
ASSERT(pApp != NULL);
if (pApp->m_pCmdInfo == NULL ||
(pApp->m_pCmdInfo->m_nShellCommand != CCommandLineInfo::FileDDE &&
pApp->m_pCmdInfo->m_nShellCommand != CCommandLineInfo::FilePrint))
{
AfxOleSetUserCtrl(TRUE);
}
return TRUE;
}
BOOL COleLinkingDoc::OnSaveDocument(LPCTSTR lpszPathName)
{
ASSERT_VALID(this);
BOOL bRemember = m_bRemember;
if (!COleDocument::OnSaveDocument(lpszPathName))
return FALSE;
if (bRemember && (m_strMoniker != lpszPathName))
{
// update the moniker/registration since the name has changed
Revoke();
RegisterIfServerAttached(lpszPathName, TRUE);
}
return TRUE;
}
void COleLinkingDoc::OnCloseDocument()
{
InternalAddRef(); // protect document during shutdown
// update lock count before sending notifications
UpdateVisibleLock(FALSE, FALSE);
Revoke(); // cleanup naming support
// remove visible lock if present
if (m_bVisibleLock)
{
m_bVisibleLock = FALSE;
LockExternal(FALSE, FALSE);
}
// cleanup the document but don't delete yet
BOOL bAutoDelete = m_bAutoDelete;
m_bAutoDelete = FALSE;
COleDocument::OnCloseDocument();
ASSERT_VALID(this);
// remove extra reference count and destroy
InterlockedDecrement(&m_dwRef);
if (bAutoDelete)
delete this; // now safe to destroy document
}
void COleLinkingDoc::UpdateVisibleLock(BOOL bVisible, BOOL bRemoveRefs)
{
ASSERT_VALID(this);
if (bVisible != m_bVisibleLock)
{
InternalAddRef(); // make sure document is stable
m_bVisibleLock = bVisible;
LockExternal(bVisible, bRemoveRefs);
InternalRelease(); // may Release the document!
}
}
void COleLinkingDoc::OnShowViews(BOOL bVisible)
{
if (bVisible)
UpdateVisibleLock(bVisible, TRUE);
}
void COleLinkingDoc::SaveToStorage(CObject* pObject)
{
ASSERT_VALID(this);
if (pObject != NULL)
ASSERT_VALID(pObject);
// write the classID of the application to the root storage
if (m_pFactory != NULL)
{
ASSERT(m_lpRootStg != NULL);
WriteClassStg(m_lpRootStg, m_pFactory->GetClassID());
}
COleDocument::SaveToStorage(pObject);
}
BOOL COleLinkingDoc::RegisterIfServerAttached(LPCTSTR lpszPathName, BOOL bMessage)
{
ASSERT_VALID(this);
ASSERT(lpszPathName == NULL || AfxIsValidString(lpszPathName));
CDocTemplate* pTemplate = GetDocTemplate();
ASSERT_VALID(pTemplate);
COleObjectFactory* pFactory =
(COleObjectFactory*)pTemplate->m_pAttachedFactory;
if (pFactory != NULL)
{
// always attach the document to the server at this time
ASSERT_KINDOF(COleObjectFactory, pFactory);
m_pFactory = pFactory;
// register with OLE Server
if (!Register(pFactory, lpszPathName))
{
if (bMessage)
{
// only report error when message box allowed
ReportSaveLoadException(lpszPathName, NULL, FALSE,
AFX_IDP_FAILED_TO_NOTIFY);
}
return FALSE;
}
}
return TRUE;
}
LPOLEITEMCONTAINER COleLinkingDoc::GetContainer()
{
ASSERT_VALID(this);
// get the IOleItemContainer interface via QueryInterface
LPOLEITEMCONTAINER lpContainer;
InternalQueryInterface(&IID_IOleItemContainer, (LPLP)&lpContainer);
return lpContainer;
}
/////////////////////////////////////////////////////////////////////////////
// COleLinkingDoc default implementation
COleServerItem* COleLinkingDoc::OnGetLinkedItem(LPCTSTR /*lpszItemName*/)
{
ASSERT_VALID(this);
// default implementation is in COleServerDoc
return NULL;
}
COleClientItem* COleLinkingDoc::OnFindEmbeddedItem(LPCTSTR lpszItemName)
{
ASSERT_VALID(this);
ASSERT(AfxIsValidString(lpszItemName));
// default implementation walks list of client items looking for
// a case sensitive match
POSITION pos = GetStartPosition();
COleClientItem* pItem;
while ((pItem = GetNextClientItem(pos)) != NULL)
{
// a client item is running if there is a match in name
// and the m_lpObject is also running.
TCHAR szItemName[OLE_MAXITEMNAME];
pItem->GetItemName(szItemName);
if (lstrcmp(szItemName, lpszItemName) == 0)
return pItem;
}
#ifdef _DEBUG
if (afxTraceFlags & traceOle)
{
TRACE0("Warning: default COleLinkingDoc::OnFindEmbeddedItem\n");
TRACE1("\timplementation failed to find item '%s'.\n", lpszItemName);
}
#endif
return NULL; // no matching item found
}
void COleLinkingDoc::LockExternal(BOOL bLock, BOOL bRemoveRefs)
{
// when an item binding is successful, the original document
// is released. To keep it alive and the RPC stubs that make
// it available to the external world (via the running object
// table), we need to place a lock on it.
// a lock created with CoLockObjectExternal adds a reference
// to the object itself (with IUnknown::AddRef) as well
// as keeping the RPC stub alive.
::CoLockObjectExternal((LPUNKNOWN)GetInterface(&IID_IUnknown),
bLock, bRemoveRefs);
if (bLock)
{
// avoid "dead" objects in the running object table (ROT), by
// re-registering this object in the ROT.
if (!m_strPathName.IsEmpty())
{
Revoke();
RegisterIfServerAttached(m_strPathName, FALSE);
}
}
}
void COleLinkingDoc::ReportSaveLoadException(LPCTSTR lpszPathName,
CException* e, BOOL bSaving, UINT nIDPDefault)
{
// watch out for special mode
if (m_bDeferErrors)
{
// Note: CException::Delete does not treat m_bAutoDelete as a
// traditional BOOL. Only if it is greater than zero does it
// take on a TRUE quality. (that is, all tests are for
// m_bAutoDelete > 0). So, if m_bAutoDelete is already "true"
// (1) this will make it false, and if it is already "false"
// it is still considered "false". Valid values for
// m_bAutoDelete are thus negative, 0, and 1. Values greater
// than 1, although not explicitly asserted in CException,
// would be invalid. In short, by using increment and
// decrement operations, we enable this to work with both
// self-deleting and non-self-deleting CException classes.
--e->m_bAutoDelete;
// save the exception for later
m_pLastException = e;
return;
}
// otherwise, just call base class
COleDocument::ReportSaveLoadException(lpszPathName, e, bSaving,
nIDPDefault);
}
SCODE COleLinkingDoc::EndDeferErrors(SCODE sc)
{
ASSERT(m_bDeferErrors != 0);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -