home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tricks of the Windows Gam…ming Gurus (2nd Edition)
/
Disc2.iso
/
vc98
/
mfc
/
src
/
oledoccl.cpp
< prev
next >
Wrap
C/C++ Source or Header
|
1998-06-16
|
14KB
|
513 lines
// 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 _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif
#define new DEBUG_NEW
/////////////////////////////////////////////////////////////////////////////
// COleDocObjectItem
IMPLEMENT_DYNAMIC(COleDocObjectItem, COleClientItem)
BEGIN_INTERFACE_MAP(COleDocObjectItem, COleClientItem)
INTERFACE_PART(COleDocObjectItem, IID_IOleDocumentSite, OleDocumentSite)
END_INTERFACE_MAP()
COleDocObjectItem::COleDocObjectItem(COleDocument* pContainerDoc)
: COleClientItem(pContainerDoc)
{
m_pHelpPopupMenu = NULL;
m_pActiveView = NULL;
m_pIPrint = NULL;
m_bInHelpMenu = FALSE;
}
COleDocObjectItem::~COleDocObjectItem()
{
if (m_pHelpPopupMenu != NULL)
m_pHelpPopupMenu->RemoveMenu(0, MF_BYPOSITION);
delete m_pHelpPopupMenu;
}
/////////////////////////////////////////////////////////////////////////////
// IOleDocumentSite interface
STDMETHODIMP_(ULONG) COleDocObjectItem::XOleDocumentSite::AddRef()
{
METHOD_PROLOGUE_EX(COleDocObjectItem, OleDocumentSite)
return pThis->ExternalAddRef();
}
STDMETHODIMP_(ULONG) COleDocObjectItem::XOleDocumentSite::Release()
{
METHOD_PROLOGUE_EX(COleDocObjectItem, OleDocumentSite)
return pThis->ExternalRelease();
}
STDMETHODIMP COleDocObjectItem::XOleDocumentSite::QueryInterface(
REFIID iid, LPVOID* ppvObj)
{
METHOD_PROLOGUE_EX(COleDocObjectItem, OleDocumentSite)
return pThis->ExternalQueryInterface(&iid, ppvObj);
}
STDMETHODIMP COleDocObjectItem::XOleDocumentSite::ActivateMe(
LPOLEDOCUMENTVIEW pViewToActivate)
{
METHOD_PROLOGUE_EX(COleDocObjectItem, OleDocumentSite)
LPOLEDOCUMENT lpDocument;
LPOLECLIENTSITE lpClientSite = pThis->GetClientSite();
LPOLEINPLACESITE lpInPlaceSite =
(LPOLEINPLACESITE) pThis->GetInterface(&IID_IOleInPlaceSite);
if (lpClientSite == NULL || lpInPlaceSite == NULL)
return E_FAIL;
// if we've gotten a NULL view, we're to create one ourselves
if (pViewToActivate == NULL)
{
// if we already have a view, we can simply activate it
if (pThis->m_pActiveView != NULL && pThis->m_pView != NULL)
{
pThis->ActivateAndShow();
return NOERROR;
}
ASSERT(pThis->m_lpObject != NULL);
if (pThis->m_lpObject == NULL)
return E_FAIL;
lpDocument = QUERYINTERFACE(pThis->m_lpObject, IOleDocument);
if (lpDocument == NULL)
return E_FAIL;
if (FAILED(
lpDocument->CreateView(lpInPlaceSite, NULL, 0, &pViewToActivate)))
{
lpDocument->Release();
return E_OUTOFMEMORY;
}
// we're done with the document pointer
lpDocument->Release();
}
else if (pThis->m_pActiveView != NULL && pThis->m_pActiveView == pViewToActivate)
{
// we already own this view, so no need to addref
// simply make it visible and resize it
pThis->ActivateAndShow();
return NOERROR;
}
else
{
// set the in-place site
pViewToActivate->SetInPlaceSite(lpInPlaceSite);
pViewToActivate->AddRef();
}
// it must've created
ASSERT(pThis->m_pView != NULL);
// if we had an old one, release it
if (pThis->m_pActiveView != NULL)
{
pThis->m_pActiveView->Show(FALSE);
pThis->m_pActiveView->UIActivate(FALSE);
pThis->m_pActiveView->Release();
if (pThis->m_pIPrint != (IPrint*) -1 && pThis->m_pIPrint != NULL)
pThis->m_pIPrint->Release();
pThis->m_pIPrint = NULL;
}
// remember it for later
pThis->m_pActiveView = pViewToActivate;
// activate and position it
pThis->ActivateAndShow();
return NOERROR;
}
/////////////////////////////////////////////////////////////////////////////
// IOleDocumentSite implementation helper
void COleDocObjectItem::ActivateAndShow()
{
// set up toolbars and menus for the object
m_pActiveView->UIActivate(TRUE);
// set the window size, avoiding new toolbars
RECT rc;
m_pView->GetClientRect(&rc);
m_pActiveView->SetRect(&rc);
// make everything visible
m_pActiveView->Show(TRUE);
return;
}
void COleDocObjectItem::OnGetItemPosition(CRect& rPosition)
{
ASSERT_VALID(this);
ASSERT(AfxIsValidAddress(&rPosition, sizeof(RECT)));
// doc objects [almost] always in the exact rect of the view
ASSERT_VALID(m_pView);
m_pView->GetClientRect(&rPosition);
}
LPOLEDOCUMENTVIEW COleDocObjectItem::GetActiveView() const
{
return m_pActiveView;
}
void COleDocObjectItem::Release(OLECLOSE dwCloseOption)
{
RELEASE(m_pActiveView);
if (m_pIPrint != (IPrint*) -1)
RELEASE(m_pIPrint);
COleClientItem::Release(dwCloseOption);
}
HRESULT COleDocObjectItem::ExecCommand(DWORD nCmdID,
DWORD nCmdExecOpt /* = OLECMDEXECOPT_DONTPROMPTUSER */,
const GUID* pguidCmdGroup /* = NULL */)
{
LPOLECOMMANDTARGET lpCt = QUERYINTERFACE(m_lpObject, IOleCommandTarget);
HRESULT hr = E_NOTIMPL;
if (lpCt != NULL)
hr = lpCt->Exec(pguidCmdGroup, nCmdID, nCmdExecOpt, NULL, NULL);
RELEASE(lpCt);
return hr;
}
BOOL COleDocObjectItem::SupportsIPrint()
{
// did someone already ask? -1 means we know it doesn't,
// non-NULL means we know it does (and we point at it)
// NULL means we don't know
if (m_pIPrint == NULL)
{
// QI for it
m_pIPrint = QUERYINTERFACE(m_lpObject, IPrint);
if (m_pIPrint == NULL)
{
// if the server isn't running, we'll need to
// start it in order to print
if (FAILED(::OleRun(m_lpObject)))
m_pIPrint = (IPrint*) -1;
else
m_pIPrint = QUERYINTERFACE(m_lpObject, IPrint);
}
}
return (m_pIPrint != NULL && m_pIPrint != (IPrint*) -1);
}
BOOL COleDocObjectItem::GetPageCount(LPLONG pnFirstPage, LPLONG pcPages)
{
if (!SupportsIPrint())
return FALSE;
//WINBUG: The proxy in DOCOBJ.DLL is broken; it doesn't allow
// NULL parameters to IPrint::GetPageInfo(), even though the spec
// says it should.
LONG lPages;
LONG lFirstPage;
HRESULT hr = m_pIPrint->GetPageInfo(&lFirstPage, &lPages);
if (pnFirstPage != NULL)
*pnFirstPage = lFirstPage;
if (pcPages != NULL)
*pcPages = lPages;
if (SUCCEEDED(hr))
return TRUE;
else
return FALSE;
}
CMenu* COleDocObjectItem::GetHelpMenu(UINT& nPosition)
{
CFrameWnd* pFrame = m_pView->GetTopLevelFrame();
CMenu* pMenuFrame = CMenu::FromHandle(pFrame->m_hMenuDefault);
if (pMenuFrame != NULL)
nPosition = pMenuFrame->GetMenuItemCount() -1;
return pMenuFrame;
}
void COleDocObjectItem::OnInsertMenus(CMenu* pMenuShared,
LPOLEMENUGROUPWIDTHS lpMenuWidths)
{
ASSERT_VALID(this);
ASSERT_VALID(pMenuShared);
ASSERT(AfxIsValidAddress(lpMenuWidths, sizeof(OLEMENUGROUPWIDTHS)));
// initialize the group widths array
lpMenuWidths->width[0] = 1;
lpMenuWidths->width[2] = 0;
lpMenuWidths->width[4] = 0;
// get menu from document template
CDocTemplate* pTemplate = GetDocument()->GetDocTemplate();
HMENU hMenuOLE = pTemplate->m_hMenuInPlace;
// only copy the popups if there is a menu loaded
if (hMenuOLE == NULL)
return;
UINT nItem;
CMenu* pMenuFrame = GetHelpMenu(nItem);
if (pMenuFrame != NULL)
{
CString strHelpMenuName;
int nSeparator = pMenuFrame->GetMenuString(nItem,
strHelpMenuName, MF_BYPOSITION);
if (nSeparator == 0)
{
TRACE0("Error: COleDocObjectItem::OnInsertMenus() found no help menu!\n");
return;
}
CString strTearOffName;
strTearOffName.Format(_T("%s %s"), AfxGetAppName(), strHelpMenuName);
strTearOffName.Remove('&');
// get the normal frame menu
int nCount = pMenuFrame->GetMenuItemCount();
HMENU hMenu = GetSubMenu(pMenuFrame->m_hMenu, nCount-1);
// clean up old menu and allocate a new one
if (m_pHelpPopupMenu == NULL)
{
m_pHelpPopupMenu = new CMenu;
// create new sub-popup menu and add container's Help tearoff
// then add help menu from main window
m_pHelpPopupMenu->CreateMenu();
m_pHelpPopupMenu->InsertMenu((UINT) -1, MF_BYPOSITION | MF_POPUP,
(UINT) hMenu, strTearOffName);
}
pMenuShared->InsertMenu(1, MF_BYPOSITION | MF_POPUP,
(UINT) m_pHelpPopupMenu->m_hMenu, strHelpMenuName);
// tell the object we added our Help menu
lpMenuWidths->width[5] = 1;
}
// insert our menu items and adjust group widths array
AfxMergeMenus(pMenuShared->GetSafeHmenu(), hMenuOLE,
&lpMenuWidths->width[0], 0);
}
void COleDocObjectItem::OnRemoveMenus(CMenu *pMenuShared)
{
int cItemsShared = pMenuShared->GetMenuItemCount();
if (cItemsShared != 0)
{
CMenu *pMenuHelp = pMenuShared->GetSubMenu(cItemsShared - 1);
int cItemsHelp = pMenuHelp->GetMenuItemCount();
int nItem;
for (nItem = cItemsHelp-1; nItem > 0; nItem--)
pMenuHelp->DeleteMenu(nItem, MF_BYPOSITION);
pMenuShared->RemoveMenu(cItemsShared - 1, MF_BYPOSITION);
}
COleClientItem::OnRemoveMenus(pMenuShared);
}
BOOL COleDocObjectItem::OnPreparePrinting(CView* pCaller,
CPrintInfo* pInfo, BOOL bPrintAll)
{
LONG lDocObjectPages = 0;
CDocument* pDoc = pCaller->GetDocument();
COleDocument* pOleDoc = DYNAMIC_DOWNCAST(COleDocument, pDoc);
if (pOleDoc == NULL)
return FALSE;
POSITION pos = pOleDoc->GetStartPosition();
while (pos != NULL)
{
COleClientItem* pItem = pOleDoc->GetNextClientItem(pos);
COleDocObjectItem* pDocItem =
DYNAMIC_DOWNCAST(COleDocObjectItem, pItem);
if (pDocItem == NULL)
continue;
// if this isn't the view, continue
if (!bPrintAll)
{
if (pItem->m_pView == NULL ||
pItem->m_pView->m_hWnd != pCaller->m_hWnd)
continue;
}
if (pDocItem->SupportsIPrint())
{
LONG lThisObjectPages;
if (pDocItem->GetPageCount(NULL, &lThisObjectPages))
lDocObjectPages += lThisObjectPages;
pInfo->m_bDocObject = TRUE;
}
else
lDocObjectPages++;
if (!bPrintAll)
break;
}
if (lDocObjectPages > 0)
{
UINT nMaxPage = pInfo->GetMaxPage();
// set the page count; increment it if previously set
if (nMaxPage == 0xFFFF)
pInfo->SetMaxPage(lDocObjectPages);
else
pInfo->SetMaxPage(nMaxPage + lDocObjectPages);
pInfo->m_bDocObject = TRUE;
}
if (pInfo->m_bDocObject)
{
// we can't show the "selection" button for DocObjects
pInfo->m_pPD->m_pd.Flags |= PD_NOSELECTION;
// if it's a doc object, and we're printing all, then we
// shouldn't show the selection
if (bPrintAll)
pInfo->m_pPD->m_pd.Flags |= PD_NOPAGENUMS;
}
return TRUE;
}
void COleDocObjectItem::OnPrint(CView* pCaller, CPrintInfo* pInfo,
BOOL bPrintAll)
{
// Note that this function ignores pInfo->m_nCurPage, and will always
// print the whole range of pages in the CPrintInfo object. That's
// because DocObjects don't support any mechanism to _continue_
// printing to an existing print job.
CDocument* pDoc = pCaller->GetDocument();
COleDocument* pOleDoc = DYNAMIC_DOWNCAST(COleDocument, pDoc);
if (pOleDoc == NULL)
return;
POSITION pos = pOleDoc->GetStartPosition();
while (pos != NULL)
{
COleClientItem* pItem = pOleDoc->GetNextClientItem(pos);
COleDocObjectItem* pDocItem = DYNAMIC_DOWNCAST(COleDocObjectItem, pItem);
if (pDocItem == NULL)
continue;
// if this isn't the view, continue
if (!bPrintAll)
{
if (pItem->m_pView == NULL || pItem->m_pView->m_hWnd != pCaller->m_hWnd)
continue;
}
HRESULT hrThisPage = E_UNEXPECTED;
if (pDocItem->SupportsIPrint())
{
DVTARGETDEVICE* pTargetDevice = NULL;
LPDEVNAMES lpDevNames = NULL;
LPDEVMODE lpDevMode = NULL;
lpDevNames = (LPDEVNAMES) GlobalLock(pInfo->m_pPD->m_pd.hDevNames);
if (lpDevNames != NULL)
{
lpDevMode = (LPDEVMODE) GlobalLock(pInfo->m_pPD->m_pd.hDevMode);
if (lpDevMode != NULL)
{
pTargetDevice = _AfxOleCreateTargetDevice(lpDevNames, lpDevMode);
if (pTargetDevice != NULL)
{
PAGESET* pps = (PAGESET*) CoTaskMemAlloc(sizeof(PAGESET));
if (pps != NULL)
{
pps->cbStruct = sizeof(PAGESET);
ASSERT((pps->cbStruct % 4) == 0);
pps->fOddPages = TRUE;
pps->fEvenPages = TRUE;
pps->cPageRange = 1;
pps->rgPages[0].nFromPage = pInfo->GetFromPage();
pps->rgPages[0].nToPage = pInfo->GetToPage();
LONG lLastPage = pps->rgPages[0].nFromPage;
LONG lPagesPrinted;
DWORD dwFlags = PRINTFLAG_RECOMPOSETODEVICE;
if (pInfo->m_pPD->m_pd.Flags & PD_PRINTTOFILE)
dwFlags |= PRINTFLAG_PRINTTOFILE;
hrThisPage = pDocItem->m_pIPrint->Print(dwFlags,
&pTargetDevice, &pps, NULL, NULL,
pInfo->m_nCurPage, &lPagesPrinted,
&lLastPage);
if (!SUCCEEDED(hrThisPage))
TRACE1("IPrint::Print() returned %8.8X\n", hrThisPage);
CoTaskMemFree(pps);
}
CoTaskMemFree(pTargetDevice);
}
GlobalUnlock(pInfo->m_pPD->m_pd.hDevMode);
}
GlobalUnlock(pInfo->m_pPD->m_pd.hDevNames);
}
}
else
{
// try through IOleCommandTarget
hrThisPage = pDocItem->ExecCommand(OLECMDID_PRINT);
if (!SUCCEEDED(hrThisPage))
TRACE1("IOleCommandTarget::Exec() returned %8.8X\n", hrThisPage);
}
}
return;
}