📄 olesvr1.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"
#include <shellapi.h>
#ifdef AFX_OLE4_SEG
#pragma code_seg(AFX_OLE4_SEG)
#endif
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#define new DEBUG_NEW
//////////////////////////////////////////////////////////////////////////////
// COleServerDoc implementation
COleServerDoc::COleServerDoc()
{
m_lpClientSite = NULL; // will be non-NULL when document is embedding
m_bCntrVisible = FALSE;
m_pInPlaceFrame = NULL; // will be non-NULL when in-place active
m_pOrigParent = NULL;
m_dwOrigStyle = 0;
m_dwOrigStyleEx = 0;
m_bClosing = FALSE;
m_pEmbeddedItem = NULL; // will be non-NULL if embedded item needed
m_pDocObjectServer = NULL; // becomes non-NULL if DocObject support enabled
}
COleServerDoc::~COleServerDoc()
{
DeleteContents(); // Note: will not call derived class
if (m_pEmbeddedItem != NULL)
{
m_pEmbeddedItem->ExternalRelease();
m_pEmbeddedItem = NULL;
}
// disconnect (remove) all items from the document
POSITION pos = GetStartPosition();
COleServerItem* pItem;
while ((pItem = GetNextServerItem(pos)) != NULL)
RemoveItem(pItem);
// release doc object manager, if any
if (m_pDocObjectServer != NULL)
{
delete m_pDocObjectServer;
m_pDocObjectServer = NULL;
}
// should not be in-place active when doc is destroyed!
ASSERT(m_pInPlaceFrame == NULL);
// Note: this must be done before the client site is released
RELEASE(m_lpRootStg);
// release client-site pointer
RELEASE(m_lpClientSite);
}
void COleServerDoc::DeleteContents()
{
COleLinkingDoc::DeleteContents();
// protect all server items with an extra reference count
POSITION pos = GetStartPosition();
COleServerItem* pItem;
while ((pItem = GetNextServerItem(pos)) != NULL)
pItem->InternalAddRef();
// delete any autodelete server items
pos = GetStartPosition();
while ((pItem = GetNextServerItem(pos)) != NULL)
{
if (pItem->m_bAutoDelete)
delete pItem;
}
// remove extra reference added above
pos = GetStartPosition();
while ((pItem = GetNextServerItem(pos)) != NULL)
pItem->InternalRelease();
}
COleServerItem* COleServerDoc::GetEmbeddedItem()
{
// allocate embedded item if necessary
if (m_pEmbeddedItem == NULL)
{
m_pEmbeddedItem = OnGetEmbeddedItem();
m_pEmbeddedItem->ExternalAddRef();
}
ASSERT_VALID(m_pEmbeddedItem);
return m_pEmbeddedItem;
}
CDocObjectServer* COleServerDoc::GetDocObjectServer(LPOLEDOCUMENTSITE pDocSite)
{
// by default, we're not DocObject enabled
UNUSED_ALWAYS(pDocSite);
return NULL;
}
HRESULT COleServerDoc::OnExecOleCmd(const GUID* pguidCmdGroup, DWORD nCmdID,
DWORD nCmdExecOpt, VARIANTARG* pvarargIn, VARIANTARG* pvarargOut)
{
UNUSED_ALWAYS(pguidCmdGroup);
UNUSED_ALWAYS(nCmdID);
UNUSED_ALWAYS(nCmdExecOpt);
UNUSED_ALWAYS(pvarargIn);
UNUSED_ALWAYS(pvarargOut);
return E_NOTIMPL;
}
LPUNKNOWN COleServerDoc::GetInterfaceHook(const void* piid)
{
LPUNKNOWN lpUnk = NULL;
// are we Doc Object supporters?
if (m_pDocObjectServer != NULL)
{
// don't be tricked into handing out a different IUnknown
DWORD lData1 = ((IID*)piid)->Data1;
BOOL bUnknown = ((DWORD*)&IID_IUnknown)[0] == lData1 &&
((DWORD*)piid)[1] == ((DWORD*)&IID_IUnknown)[1] &&
((DWORD*)piid)[2] == ((DWORD*)&IID_IUnknown)[2] &&
((DWORD*)piid)[3] == ((DWORD*)&IID_IUnknown)[3];
if (bUnknown)
return NULL;
lpUnk = m_pDocObjectServer->GetInterface(piid);
}
// failing that, try the base class
if (lpUnk == NULL)
lpUnk = COleLinkingDoc::GetInterfaceHook(piid);
return lpUnk;
}
void COleServerDoc::ActivateDocObject()
{
if (m_pDocObjectServer != NULL)
m_pDocObjectServer->ActivateDocObject();
}
/////////////////////////////////////////////////////////////////////////////
// COleServerDoc client notifications
void COleServerDoc::NotifyRename(LPCTSTR lpszNewName)
{
ASSERT_VALID(this);
ASSERT(AfxIsValidString(lpszNewName));
if (m_pFactory != NULL)
{
// update running object table with new moniker
Revoke();
Register(m_pFactory, lpszNewName);
// notify all items of the new moniker
POSITION pos = GetStartPosition();
COleServerItem* pItem;
while ((pItem = GetNextServerItem(pos)) != NULL)
{
// notify client directly
LPMONIKER lpMoniker = pItem->GetMoniker(OLEGETMONIKER_ONLYIFTHERE);
pItem->NotifyClient(OLE_RENAMED, (DWORD)lpMoniker);
RELEASE(lpMoniker);
}
}
}
void COleServerDoc::NotifyAllItems(OLE_NOTIFICATION nCode, DWORD dwParam)
{
ASSERT_VALID(this);
POSITION pos = GetStartPosition();
COleServerItem* pItem;
while ((pItem = GetNextServerItem(pos)) != NULL)
{
// notify client directly
pItem->NotifyClient(nCode, dwParam);
}
}
// UpdateAllItems is much like UpdateAllViews, but for server items
void COleServerDoc::UpdateAllItems(COleServerItem* pSender,
LPARAM lHint, CObject* pHint, DVASPECT nDrawAspect)
{
ASSERT_VALID(this);
POSITION pos = GetStartPosition();
COleServerItem* pItem;
while ((pItem = GetNextServerItem(pos)) != NULL)
{
// notify client indirectly through OnUpdate
if (pItem != pSender)
pItem->OnUpdate(pSender, lHint, pHint, nDrawAspect);
}
}
void COleServerItem::OnUpdate(COleServerItem* /*pSender*/,
LPARAM /*lHint*/, CObject* /*pHint*/, DVASPECT nDrawAspect)
{
// the default implementation always notifies the container, regardless
// of the specific hint or sender.
NotifyChanged(nDrawAspect);
}
/////////////////////////////////////////////////////////////////////////////
// COleServerDoc attributes
BOOL COleServerDoc::GetZoomFactor(LPSIZE lpSizeNum, LPSIZE lpSizeDenom,
LPCRECT lpPosRect) const
{
ASSERT_VALID(this);
ASSERT(lpSizeNum == NULL || AfxIsValidAddress(lpSizeNum, sizeof(SIZE)));
ASSERT(lpSizeDenom == NULL || AfxIsValidAddress(lpSizeDenom, sizeof(SIZE)));
ASSERT(lpPosRect == NULL ||
AfxIsValidAddress(lpPosRect, sizeof(RECT), FALSE));
if (!IsInPlaceActive())
{
if (lpSizeNum != NULL)
{
ASSERT(lpSizeDenom != NULL);
lpSizeNum->cx = 1;
lpSizeNum->cy = 1;
*lpSizeDenom = *lpSizeNum;
}
return FALSE;
}
ASSERT_VALID(m_pInPlaceFrame);
// the zoom factor is (Size(position-rect) / m_sizeExtent)
CSize sizeNum;
if (lpPosRect == NULL)
{
// use current position rect
sizeNum = m_pInPlaceFrame->m_rectPos.Size();
}
else
{
// use new position rect
sizeNum.cx = lpPosRect->right - lpPosRect->left;
sizeNum.cy = lpPosRect->bottom - lpPosRect->top;
}
// m_sizeExtent is in HIMETRIC units -- need to convert to pixels.
CSize sizeDenom(0, 0);
COleServerItem* pItem = ((COleServerDoc*)this)->GetEmbeddedItem();
ASSERT_VALID(pItem);
ASSERT_KINDOF(COleServerItem, pItem);
// get zoom denominator, which is based on the current extent
((COleServerItem*)pItem)->OnGetExtent(DVASPECT_CONTENT, sizeDenom);
if (sizeDenom.cx == 0 || sizeDenom.cy == 0)
{
// no extent from container available, so use natural extent instead
pItem->OnGetExtent(DVASPECT_CONTENT, sizeDenom);
}
// convert extent to pixels first
((CDC*)NULL)->HIMETRICtoDP(&sizeDenom);
// might be bad to have zoom denominator of zero!
if (sizeDenom.cy == 0 || sizeDenom.cx == 0)
{
TRACE0("Warning: zero 'zoom denominator', using 100%% zoom instead.\n");
sizeDenom = sizeNum;
}
// store the results
if (lpSizeNum != NULL)
{
ASSERT(lpSizeDenom != NULL);
*lpSizeNum = sizeNum;
*lpSizeDenom = sizeDenom;
}
// if 100% scaling, return FALSE
return sizeNum != sizeDenom;
}
void COleServerDoc::GetItemPosition(LPRECT lpPosRect) const
{
ASSERT_VALID(this);
ASSERT(AfxIsValidAddress(lpPosRect, sizeof(RECT)));
ASSERT(IsInPlaceActive());
ASSERT_VALID(m_pInPlaceFrame);
// copy the current rectangle
*lpPosRect = m_pInPlaceFrame->m_rectPos;
}
void COleServerDoc::GetItemClipRect(LPRECT lpClipRect) const
{
ASSERT_VALID(this);
ASSERT(AfxIsValidAddress(lpClipRect, sizeof(RECT)));
ASSERT(IsInPlaceActive());
ASSERT_VALID(m_pInPlaceFrame);
// copy the current rectangle
*lpClipRect = m_pInPlaceFrame->m_rectClip;
}
/////////////////////////////////////////////////////////////////////////////
// COleServerDoc overrideables
COleServerItem* COleServerDoc::OnGetLinkedItem(LPCTSTR lpszItemName)
{
ASSERT_VALID(this);
ASSERT(AfxIsValidString(lpszItemName));
// default implementation walks list of server items looking for
// a case sensitive match
POSITION pos = GetStartPosition();
COleServerItem* pItem;
while ((pItem = GetNextServerItem(pos)) != NULL)
{
// return item if name matches (case sensitive)
if (lstrcmp(pItem->GetItemName(), lpszItemName) == 0)
return pItem;
}
#ifdef _DEBUG
if (afxTraceFlags & traceOle)
{
TRACE0("Warning: default COleServerDoc::OnGetLinkedItem implementation\n");
TRACE1("\tfailed to find item '%s'.\n", lpszItemName);
}
#endif
return NULL; // not found (no link found)
}
void COleServerDoc::OnClose(OLECLOSE dwCloseOption)
{
ASSERT_VALID(this);
// do nothing if already in the process of closing the document
if (m_bClosing)
return;
// OLECLOSE_PROMPTSAVE is handled like OLECLOSE_SAVEIFDIRTY if invisible
CFrameWnd* pFrameWnd = GetFirstFrame();
if (pFrameWnd != NULL && pFrameWnd->IsWindowVisible())
dwCloseOption = OLECLOSE_SAVEIFDIRTY;
// handle modified document and special dwCloseOption flags
TRY
{
if (IsModified())
{
switch (dwCloseOption)
{
case OLECLOSE_PROMPTSAVE:
if (!SaveModifiedPrompt())
AfxThrowOleException(OLE_E_PROMPTSAVECANCELLED);
break;
case OLECLOSE_SAVEIFDIRTY:
SaveEmbedding();
break;
}
}
}
END_TRY
// deactivate in-place session
if (m_pInPlaceFrame != NULL)
{
OnDeactivate();
ASSERT(m_pInPlaceFrame == NULL);
}
// close the document
BOOL bAutoDelete = m_bAutoDelete;
m_bAutoDelete = FALSE;
OnCloseDocument();
m_bAutoDelete = bAutoDelete;
}
BOOL COleServerDoc::SaveModifiedPrompt()
{
ASSERT_VALID(this);
if (m_lpClientSite == NULL)
return SaveModified();
UpdateModifiedFlag(); // check for modified client items
if (!IsModified())
return TRUE; // ok to continue
CString prompt;
AfxFormatString1(prompt, AFX_IDP_ASK_TO_UPDATE, m_strTitle);
switch (AfxMessageBox(prompt, MB_YESNOCANCEL, AFX_IDP_ASK_TO_UPDATE))
{
case IDCANCEL:
return FALSE; // don't continue
case IDYES:
if (!OnUpdateDocument())
{
TRACE0("Warning: OnUpdateDocument failed to update.\n");
// keep going, close will flush it
}
break;
}
return TRUE; // keep going
}
BOOL COleServerDoc::CanCloseFrame(CFrameWnd* pFrame)
{
m_bClosing = TRUE;
if (!COleLinkingDoc::CanCloseFrame(pFrame))
{
m_bClosing = FALSE;
return FALSE;
}
return TRUE;
}
BOOL COleServerDoc::GetFileTypeString(CString& rString)
{
ASSERT_VALID(this);
CDocTemplate* pTemplate = GetDocTemplate();
if (pTemplate == NULL)
return FALSE;
pTemplate->GetDocString(rString, CDocTemplate::fileNewName);
return !rString.IsEmpty();
}
void COleServerDoc::OnSetHostNames(LPCTSTR lpszHost, LPCTSTR lpszHostObj)
{
ASSERT_VALID(this);
ASSERT(lpszHost == NULL || AfxIsValidString(lpszHost));
ASSERT(lpszHostObj == NULL || AfxIsValidString(lpszHostObj));
UNUSED(lpszHost); // unused in release builds
// only change the title for embedded documents
if (m_lpClientSite != NULL)
{
// save name of document for File.Exit update
if (lpszHostObj == NULL)
m_strHostObj.LoadString(AFX_IDS_UNTITLED);
else
m_strHostObj = lpszHostObj;
// attempt to get the document name from the document template
CString strFileType;
if (!GetFileTypeString(strFileType))
return;
// format the string into <server-name> in <docname>
CString strTitle;
AfxFormatString2(strTitle, AFX_IDS_APP_TITLE_EMBEDDING,
strFileType, m_strHostObj);
// change title of document to that for an embedded item
// (this call will update all of the frames)
SetTitle(strTitle);
}
}
void COleServerDoc::SaveEmbedding()
{
ASSERT_VALID(this);
// tell the client site to save the object
if (m_lpClientSite != NULL && !::InSendMessage())
{
SCODE sc = m_lpClientSite->SaveObject();
if (sc != S_OK)
AfxThrowOleException(sc);
}
ASSERT_VALID(this);
}
BOOL COleServerDoc::OnUpdateDocument()
{
ASSERT_VALID(this);
// don't save if already up-to-date
if (!IsModified())
return TRUE;
// save a server document -> update
TRY
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -