📄 oledoc1.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_OLE_SEG
#pragma code_seg(AFX_OLE_SEG)
#endif
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#define new DEBUG_NEW
/////////////////////////////////////////////////////////////////////////////
// COleDocument - enables both server and client
COleDocument::COleDocument()
{
ASSERT(m_viewList.IsEmpty());
ASSERT(m_docItemList.IsEmpty());
#ifdef _DEBUG
// check for common mistake of not initializing OLE libraries before
// creating an OLE document.
LPMALLOC lpMalloc = NULL;
if (::CoGetMalloc(MEMCTX_TASK, &lpMalloc) != S_OK)
{
TRACE0("Warning: CoGetMalloc(MEMCTX_TASK, ...) failed --\n");
TRACE0("\tperhaps AfxOleInit() has not been called.\n");
}
RELEASE(lpMalloc);
#endif
m_dwNextItemNumber = 1; // item number for first item in document
m_bLastVisible = FALSE;
m_bRemember = TRUE;
m_bSameAsLoad = TRUE;
m_lpRootStg = NULL;
m_ptd = NULL; // default to screen target device
m_bCompoundFile = FALSE;
AfxOleLockApp();
}
COleDocument::~COleDocument()
{
ASSERT_VALID(this);
#ifdef _DEBUG
if (!m_docItemList.IsEmpty())
TRACE1("Warning: destroying COleDocument with %d doc items.\n",
m_docItemList.GetCount());
#endif
// remove all doc-items from the list before shutting down the storage
POSITION pos = GetStartPosition();
while (pos != NULL)
{
CDocItem* pItem = GetNextItem(pos);
ASSERT(pItem != NULL);
delete pItem;
}
// release the hold on the document storage
RELEASE(m_lpRootStg);
CoTaskMemFree(m_ptd);
AfxOleUnlockApp();
}
/////////////////////////////////////////////////////////////////////////////
// DocItem management
void COleDocument::AddItem(CDocItem* pItem)
{
// don't do an ASSERT_VALID until after we've added it !
ASSERT_KINDOF(CDocItem, pItem);
ASSERT(pItem->m_pDocument == NULL); // not yet initialized
m_docItemList.AddTail(pItem);
pItem->m_pDocument = this;
ASSERT_VALID(pItem); // now it must be valid
}
void COleDocument::RemoveItem(CDocItem* pItem)
{
ASSERT_VALID(pItem); // must be valid before detach
ASSERT_KINDOF(CDocItem, pItem);
ASSERT(pItem->m_pDocument == this); // formerly attached
ASSERT(m_docItemList.Find(pItem) != NULL); // must be in list
m_docItemList.RemoveAt(m_docItemList.Find(pItem));
ASSERT(m_docItemList.Find(pItem) == NULL); // must not be in list now
pItem->m_pDocument = NULL;
}
POSITION COleDocument::GetStartPosition() const
{
ASSERT_VALID(this);
return m_docItemList.GetHeadPosition();
}
CDocItem* COleDocument::GetNextItem(POSITION& pos) const
{
// handle special case of !pos -- makes enumeration code smaller
if (pos == NULL)
return NULL;
// otherwise get next item from list
ASSERT_VALID(this);
CDocItem* pItem = (CDocItem*)m_docItemList.GetNext(pos);
ASSERT(pItem != NULL);
ASSERT_KINDOF(CDocItem, pItem);
ASSERT(pItem->m_pDocument == this); // must be ours
return pItem;
}
CDocItem*
COleDocument::GetNextItemOfKind(POSITION& pos, CRuntimeClass* pClass) const
{
while (pos != NULL)
{
CDocItem* pItem = GetNextItem(pos);
ASSERT_VALID(pItem);
if (pItem->IsKindOf(pClass))
return pItem;
}
return NULL; // no suitable item found
}
COleClientItem* COleDocument::GetNextClientItem(POSITION& pos) const
{
COleClientItem *pItem =
(COleClientItem*)GetNextItemOfKind(pos, RUNTIME_CLASS(COleClientItem));
return pItem;
}
COleServerItem* COleDocument::GetNextServerItem(POSITION& pos) const
{
COleServerItem *pItem =
(COleServerItem*)GetNextItemOfKind(pos, RUNTIME_CLASS(COleServerItem));
return pItem;
}
void COleDocument::DeleteContents()
{
// deletes all COleClientItem objects in the doc item list
// (Note: doesn't touch server items or other docitems)
POSITION pos = GetStartPosition();
COleClientItem* pItem;
while ((pItem = GetNextClientItem(pos)) != NULL)
{
if (pItem->m_lpObject != NULL)
{
pItem->Release(OLECLOSE_NOSAVE); // release OLE object
RemoveItem(pItem); // disconnect from document
pItem->InternalRelease(); // may 'delete pItem'
}
}
}
void COleDocument::SetPathName(LPCTSTR lpszPathName, BOOL bAddToMRU)
{
USES_CONVERSION;
CDocument::SetPathName(lpszPathName, bAddToMRU);
// update all of the objects' host names
POSITION pos = GetStartPosition();
COleClientItem* pItem;
while ((pItem = GetNextClientItem(pos)) != NULL)
{
// update that item's host names
pItem->m_lpObject->SetHostNames(T2COLE(AfxGetAppName()),
T2COLE(m_strTitle));
}
}
void COleDocument::Serialize(CArchive& ar)
{
ASSERT_VALID(this);
// serialize all items in the doc item list
if (ar.IsStoring())
{
DWORD dwCount = 0;
POSITION pos = GetStartPosition();
while (pos != NULL)
{
CDocItem* pDocItem = GetNextItem(pos);
ASSERT_VALID(pDocItem);
// only count non-blank ones
if (!pDocItem->IsBlank())
++dwCount;
}
ar << dwCount; // write count of objects
// serialize all the items in the list
pos = GetStartPosition();
while (pos != NULL)
{
CDocItem* pDocItem = GetNextItem(pos);
ASSERT_VALID(pDocItem);
// only write non-blank ones
if (!pDocItem->IsBlank())
ar << pDocItem;
}
}
else
{
// read number of items in the file
DWORD dwCount;
ar >> dwCount;
// read all of them into the list
while (dwCount--)
{
CDocItem* pDocItem;
ar >> pDocItem; // as they are serialized, they are added!
}
}
}
void COleDocument::CommitItems(BOOL bSuccess)
{
// special 'Commit' phase for COleClientItem items
POSITION pos = GetStartPosition();
COleClientItem* pItem;
while ((pItem = GetNextClientItem(pos)) != NULL)
{
// calling CommitItem with FALSE causes the object to revert
// to the original storage. Calling CommitItem TRUE causes
// the item to adopt the new storage created in the Serialize
// function.
pItem->CommitItem(bSuccess);
}
}
BOOL COleDocument::HasBlankItems() const
{
ASSERT_VALID(this);
POSITION pos = GetStartPosition();
while (pos != NULL)
{
CDocItem* pDocItem = GetNextItem(pos);
ASSERT_VALID(pDocItem);
if (pDocItem->IsBlank())
return TRUE; // blank item found
}
return FALSE; // no items found that were blank
}
void COleDocument::UpdateModifiedFlag()
{
ASSERT_VALID(this);
POSITION pos = GetStartPosition();
COleClientItem* pItem;
while ((pItem = GetNextClientItem(pos)) != NULL)
{
if (pItem->IsModified())
{
SetModifiedFlag();
break;
}
}
}
void COleDocument::PreCloseFrame(CFrameWnd* pFrameArg)
{
ASSERT_VALID(this);
ASSERT_VALID(pFrameArg);
// turn off redraw so the user doesn't see the deactivation happening
BOOL bSetRedraw = FALSE;
if (pFrameArg->GetStyle() & WS_VISIBLE)
{
pFrameArg->SendMessage(WM_SETREDRAW, (WPARAM)FALSE);
bSetRedraw = TRUE;
}
// deactivate any inplace active items on this frame
COleClientItem* pItem = GetInPlaceActiveItem(pFrameArg);
if (pItem != NULL)
{
pItem->Deactivate();
pItem->Close(OLECLOSE_NOSAVE);
}
// turn redraw back on
if (bSetRedraw)
pFrameArg->SendMessage(WM_SETREDRAW, (WPARAM)TRUE);
// should not have any inplace active items
ASSERT(GetInPlaceActiveItem(pFrameArg) == NULL);
}
BOOL COleDocument::SaveModified()
{
// determine if necessary to discard changes
if (::InSendMessage())
{
POSITION pos = GetStartPosition();
COleClientItem* pItem;
while ((pItem = GetNextClientItem(pos)) != NULL)
{
ASSERT(pItem->m_lpObject != NULL);
SCODE sc = pItem->m_lpObject->IsUpToDate();
if (sc != OLE_E_NOTRUNNING && FAILED(sc))
{
// inside inter-app SendMessage limits the user's choices
CString name = m_strPathName;
if (name.IsEmpty())
VERIFY(name.LoadString(AFX_IDS_UNTITLED));
CString prompt;
AfxFormatString1(prompt, AFX_IDP_ASK_TO_DISCARD, name);
return AfxMessageBox(prompt, MB_OKCANCEL|MB_DEFBUTTON2,
AFX_IDP_ASK_TO_DISCARD) == IDOK;
}
}
}
// sometimes items change without a notification, so we have to
// update the document's modified flag before calling
// CDocument::SaveModified.
UpdateModifiedFlag();
return CDocument::SaveModified();
}
void COleDocument::OnShowViews(BOOL /*bVisible*/)
{
// no default implementation
}
void COleDocument::OnIdle()
{
ASSERT_VALID(this);
// determine if any visible views are on this document
BOOL bVisible = FALSE;
POSITION pos = GetFirstViewPosition();
while (pos != NULL)
{
CView* pView = GetNextView(pos);
ASSERT_VALID(pView);
CFrameWnd* pFrameWnd = pView->GetParentFrame();
ASSERT_VALID(pFrameWnd);
if (pFrameWnd->GetStyle() & WS_VISIBLE)
{
bVisible = TRUE;
break;
}
}
// when state has changed, call OnShowViews
if (bVisible != m_bLastVisible)
{
OnShowViews(bVisible);
m_bLastVisible = bVisible;
}
}
/////////////////////////////////////////////////////////////////////////////
// COleDocument -> window mapping
CFrameWnd* COleDocument::GetFirstFrame()
{
ASSERT_VALID(this);
// get position of first view in the document
POSITION pos = GetFirstViewPosition();
// get view at that position
CView* pView = GetNextView(pos);
if (pView == NULL)
return NULL;
ASSERT_VALID(pView);
// return the first frame window that is a parent of that view
CFrameWnd* pFrameWnd = (CFrameWnd*)pView->GetParentFrame();
ASSERT_VALID(pFrameWnd);
ASSERT_KINDOF(CFrameWnd, pFrameWnd);
return pFrameWnd;
}
/////////////////////////////////////////////////////////////////////////////
// COleDocument helpers
LPMONIKER COleDocument::GetMoniker(OLEGETMONIKER /*nAssign*/)
{
USES_CONVERSION;
ASSERT_VALID(this);
// no moniker for untitled documents
if (m_strPathName.IsEmpty())
return NULL;
// return file moniker based on current path name
LPMONIKER lpMoniker;
CreateFileMoniker(T2COLE(m_strPathName), &lpMoniker);
return lpMoniker;
}
LPOLEITEMCONTAINER COleDocument::GetContainer()
{
// COleDocument doesn't support IOleClientSite::GetContainer
return NULL;
}
/////////////////////////////////////////////////////////////////////////////
// 'Compound File' enabling in COleDocument
BOOL COleDocument::OnNewDocument()
{
// call base class, which destroys all items
if (!CDocument::OnNewDocument())
return FALSE;
// for file-based compound files, need to create temporary file
if (m_bCompoundFile && !m_bEmbedded)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -