// 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

/////////////////////////////////////////////////////////////////////////////
// CDocObjectServer

IMPLEMENT_DYNAMIC(CDocObjectServer, CCmdTarget)

BEGIN_MESSAGE_MAP(CDocObjectServer, CCmdTarget)
	//{{AFX_MSG_MAP(CDocObjectServer)
		// NOTE - the ClassWizard will add and remove mapping macros here.
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

BEGIN_INTERFACE_MAP(CDocObjectServer, CCmdTarget)
	INTERFACE_PART(CDocObjectServer, IID_IOleObject, OleObject)
	INTERFACE_PART(CDocObjectServer, IID_IOleDocument, OleDocument)
	INTERFACE_PART(CDocObjectServer, IID_IOleDocumentView, OleDocumentView)
	INTERFACE_PART(CDocObjectServer, IID_IOleCommandTarget, OleCommandTarget)
	INTERFACE_PART(CDocObjectServer, IID_IPrint, Print)
END_INTERFACE_MAP()


/////////////////////////////////////////////////////////////////////////////
// CDocObjectServer implementation

CDocObjectServer::CDocObjectServer(COleServerDoc* pDoc,
	LPOLEDOCUMENTSITE pDocSite /* = NULL */)
{
	// Initialize DocObject data
	m_pDocSite  = pDocSite;
	m_pViewSite = NULL;

	m_pOwner = pDoc;
	ASSERT(m_pOwner != NULL);

	m_nFirstPage = 1;

	// All Binder-Compatible documents use Compound Files as their
	// storage mechanism
	m_pOwner->EnableCompoundFile(TRUE);

	m_nFirstPage = -1;
}

CDocObjectServer::~CDocObjectServer()
{
	ReleaseDocSite();
}

void CDocObjectServer::ReleaseDocSite()
{
	if (m_pDocSite != NULL)
	{
		m_pDocSite->Release();
		m_pDocSite = NULL;
	}
}

void CDocObjectServer::SetDocSite(LPOLEDOCUMENTSITE pNewSite)
{
	ReleaseDocSite();
	m_pDocSite = pNewSite;
}

void CDocObjectServer::OnCloseDocument()
{
	// Clean up pointer to document site, if any
	ReleaseDocSite();
	m_pOwner->OnCloseDocument();
}

void CDocObjectServer::ActivateDocObject()
{
	ASSERT(m_pOwner != NULL);
	if (m_pOwner->IsDocObject())
	{
		ASSERT(m_pDocSite != NULL);
		m_pDocSite->ActivateMe(NULL);
	}
}

STDMETHODIMP CDocObjectServer::OnExecOleCmd(
   const GUID* pguidCmdGroup, DWORD nCmdID, DWORD nCmdExecOpt,
   VARIANTARG* pvarargIn, VARIANTARG* pvarargOut)
{
	ASSERT(m_pOwner != NULL);
	if (m_pOwner == NULL)
		return E_NOTIMPL;
	else
		return m_pOwner->OnExecOleCmd(pguidCmdGroup, nCmdID,
			nCmdExecOpt, pvarargIn, pvarargOut);
}

COleDocIPFrameWnd* CDocObjectServer::GetControllingFrame() const
{
	COleDocIPFrameWnd* pFrame = NULL;
	POSITION pos = m_pOwner->GetFirstViewPosition();
	if (pos != NULL)
	{
		CView* pView = m_pOwner->GetNextView(pos);
		if (pView != NULL)
		{
			CWnd* pParent = pView->GetParentFrame();
			pFrame = DYNAMIC_DOWNCAST(COleDocIPFrameWnd, pParent);
		}
	}

#ifdef _DEBUG
	// This TRACE will trip if you've not converted your application to
	// use a COleDocIPFrameWnd, or if you've incorrectly hooked up
	// DocObject support in your application.

	if (pFrame == NULL)
		TRACE0("Error: An appropriate DocObject frame could not be found.\n");
#endif

	return pFrame;
}

BOOL CDocObjectServer::DoPreparePrinting(CView* pView, CPrintInfo* printInfo)
{
	return pView->OnPreparePrinting(printInfo);
}

void CDocObjectServer::DoPrepareDC(CView* pView, CDC* pdcPrint,
	CPrintInfo* pprintInfo)
{
	pView->OnPrepareDC(pdcPrint, pprintInfo);
}

void CDocObjectServer::DoPrint(CView* pView, CDC* pdcPrint,
	CPrintInfo* pprintInfo)
{
	pView->OnPrint(pdcPrint, pprintInfo);
}

void CDocObjectServer::DoBeginPrinting(CView* pView,
	CDC* pDC, CPrintInfo* pprintInfo)
{
	pView->OnBeginPrinting(pDC, pprintInfo);
}

void CDocObjectServer::DoEndPrinting(CView* pView,
	CDC* pDC, CPrintInfo* pprintInfo)
{
	pView->OnEndPrinting(pDC, pprintInfo);
}


/////////////////////////////////////////////////////////////////////////////
// IPrint interface

extern BOOL CALLBACK _AfxAbortProc(HDC, int);   // from VIEWPRNT.CPP

STDMETHODIMP_(ULONG) CDocObjectServer::XPrint::AddRef()
{
	METHOD_PROLOGUE_EX(CDocObjectServer, Print)
	return pThis->m_pOwner->ExternalAddRef();
}

STDMETHODIMP_(ULONG) CDocObjectServer::XPrint::Release()
{
	METHOD_PROLOGUE_EX(CDocObjectServer, Print)
	return pThis->m_pOwner->ExternalRelease();
}

STDMETHODIMP CDocObjectServer::XPrint::QueryInterface(
	REFIID iid, LPVOID* ppvObj)
{
	METHOD_PROLOGUE_EX(CDocObjectServer, Print)
	return pThis->ExternalQueryInterface(&iid, ppvObj);
}

STDMETHODIMP CDocObjectServer::XPrint::SetInitialPageNum(
   LONG nFirstPage)
{
	METHOD_PROLOGUE_EX(CDocObjectServer, Print)
	ASSERT_VALID(pThis);
	pThis->m_nFirstPage = nFirstPage;

	return S_OK;
}

STDMETHODIMP CDocObjectServer::XPrint::GetPageInfo(
   LPLONG pnFirstPage, LPLONG pcPages)
{
	METHOD_PROLOGUE_EX(CDocObjectServer, Print)
	ASSERT_VALID(pThis);

	// find the view we need to print

	CView* pView = NULL;
	POSITION pos = pThis->m_pOwner->GetFirstViewPosition();
	if (pos != NULL)
		pView = pThis->m_pOwner->GetNextView(pos);

	if (pView == NULL)
		return E_UNEXPECTED;

	// tell the view that we're not actually printing
	// and just need to measure the print job

	CPrintInfo printInfo;
	printInfo.m_bDocObject = TRUE;
	printInfo.m_dwFlags = PRINTFLAG_DONTACTUALLYPRINT;

	// ask the view about it

	if (!pThis->DoPreparePrinting(pView, &printInfo))
		return E_UNEXPECTED;

	// pnFirstPage and pcPages are allowed to be NULL
	// if NULL, don't return results to caller

	if (pnFirstPage != NULL)
	{
		if (pThis->m_nFirstPage == -1)
			*pnFirstPage = printInfo.GetMinPage();
		else
			*pnFirstPage = pThis->m_nFirstPage;
	}

	if (pcPages != NULL)
	{
		if (printInfo.GetToPage() == 0xFFFF)
			*pcPages = 0xFFFF;
		else
			*pcPages = printInfo.GetToPage() - printInfo.GetFromPage() +1;
	}

	return S_OK;
}

STDMETHODIMP CDocObjectServer::XPrint::Print(
   DWORD grfFlags, DVTARGETDEVICE** ppTD, PAGESET** ppPageSet,
   LPSTGMEDIUM pstgmOptions, LPCONTINUECALLBACK pCallback, LONG nFirstPage,
   LPLONG pcPagesPrinted, LPLONG pnLastPage)
{
	METHOD_PROLOGUE_EX(CDocObjectServer, Print)
	ASSERT_VALID(pThis);
	UNUSED_ALWAYS(pstgmOptions);
	UNUSED_ALWAYS(pnLastPage);

	// try to get out of this without doing any work

	if (pcPagesPrinted == NULL || ppTD == NULL || ppPageSet == NULL)
		return E_POINTER;

	if (*ppTD == NULL)
		return E_INVALIDARG;

	// get initialized

	DVTARGETDEVICE* ptd = *ppTD;
	pThis->m_nFirstPage = nFirstPage;
	*pcPagesPrinted = 0;

	// find the view we need to print

	CView* pView = NULL;
	POSITION pos = pThis->m_pOwner->GetFirstViewPosition();
	if (pos != NULL)
		pView = pThis->m_pOwner->GetNextView(pos);

	if (pView == NULL)
		return E_UNEXPECTED;

	// get default print info
	CPrintInfo printInfo;
	ASSERT(printInfo.m_pPD != NULL);    // must be set
	printInfo.m_bDocObject = TRUE;
	printInfo.m_dwFlags = grfFlags;
	printInfo.m_nOffsetPage = nFirstPage;

	printInfo.m_pPD->m_pd.hDC = _AfxOleCreateDC(*ppTD);
	if (printInfo.m_pPD->m_pd.hDC == NULL)
	{
		if (grfFlags & PRINTFLAG_MAYBOTHERUSER)
			AfxMessageBox(AFX_IDP_FAILED_TO_START_PRINT);
		return E_UNEXPECTED;
	}

	if (pThis->DoPreparePrinting(pView, &printInfo))
	{
		// hDC must be set (did you remember to call DoPreparePrinting?)
		ASSERT(printInfo.m_pPD->m_pd.hDC != NULL);

		// set file to print to if print-to-file selected
		CString strOutput;
		if (grfFlags & PRINTFLAG_PRINTTOFILE)
			strOutput = (LPOLESTR)((BYTE*)ptd + ptd->tdPortNameOffset);

		// if we were to prompt, we'll need to copy info from the
		// user back to the client

		if (grfFlags & PRINTFLAG_PROMPTUSER)
		{
			if (grfFlags & PRINTFLAG_USERMAYCHANGEPRINTER)
			{
				LPDEVNAMES lpDevNames =
					(LPDEVNAMES) GlobalLock(printInfo.m_pPD->m_pd.hDevNames);
				LPDEVMODE lpDevMode =
					(LPDEVMODE) GlobalLock(printInfo.m_pPD->m_pd.hDevMode);

				if (lpDevNames == NULL || lpDevMode == NULL)
					*ppTD = NULL;
				else
					*ppTD = _AfxOleCreateTargetDevice(lpDevNames, lpDevMode);

				GlobalUnlock(printInfo.m_pPD->m_pd.hDevNames);
				GlobalUnlock(printInfo.m_pPD->m_pd.hDevMode);
			}

			// MFC page ranges (for now) only have one PAGERANGE

			LPMALLOC pMalloc = NULL;

			// if the caller didn't supply a buffer, allocate one
			// else, make sure the buffer is big enough

			if (*ppPageSet == NULL)
			{
				HRESULT hrCopying = CoGetMalloc(1, &pMalloc);
				if (FAILED(hrCopying))
					return hrCopying;

				*ppPageSet =
					(PAGESET*) pMalloc->Alloc(sizeof(PAGESET) + sizeof(PAGERANGE));
			}
			else
			{
				if ((*ppPageSet)->cPageRange < 1 ||
					(*ppPageSet)->cbStruct != sizeof(PAGESET))
				{
					return E_INVALIDARG;
				}
			}

			if (*ppPageSet != NULL)
			{
				(*ppPageSet)->cbStruct = sizeof(PAGESET);
				(*ppPageSet)->fOddPages = TRUE;
				(*ppPageSet)->fEvenPages = TRUE;
				(*ppPageSet)->cPageRange = 1;

				(*ppPageSet)->rgPages[0].nFromPage = printInfo.GetFromPage();
				(*ppPageSet)->rgPages[0].nToPage = printInfo.GetToPage();
			}

			RELEASE(pMalloc);

			if (*ppTD == NULL || *ppPageSet == NULL)
				return E_UNEXPECTED;
		}

		// if the client didn't really want to print,
		// we've collected all the information we need
		if (grfFlags & PRINTFLAG_DONTACTUALLYPRINT)
			return S_OK;

		// set up document info and start the document printing process
		CString strTitle;
		CDocument* pDoc = pThis->m_pOwner;
		if (pDoc != NULL)
			strTitle = pDoc->GetTitle();
		else
			pView->GetParentFrame()->GetWindowText(strTitle);

		if (strTitle.GetLength() > 31)
			strTitle.ReleaseBuffer(31);

		DOCINFO docInfo;
		memset(&docInfo, 0, sizeof(DOCINFO));
		docInfo.cbSize = sizeof(DOCINFO);
		docInfo.lpszDocName = strTitle;
		CString strPortName;
		int nFormatID;
		if (strOutput.IsEmpty())
		{
			docInfo.lpszOutput = NULL;
			strPortName = (LPOLESTR)((BYTE*)ptd + ptd->tdPortNameOffset);
			nFormatID = AFX_IDS_PRINTONPORT;
		}
		else
		{
			docInfo.lpszOutput = strOutput;
			AfxGetFileTitle(strOutput,
				strPortName.GetBuffer(_MAX_PATH), _MAX_PATH);
			nFormatID = AFX_IDS_PRINTTOFILE;
		}

		// setup the printing DC
		CDC dcPrint;
		dcPrint.Attach(printInfo.m_pPD->m_pd.hDC);  // attach printer dc
		dcPrint.m_bPrinting = TRUE;
		pThis->DoBeginPrinting(pView, &dcPrint, &printInfo);
		dcPrint.SetAbortProc(_AfxAbortProc);

		// disable main window while printing & init printing status dialog
		AfxGetMainWnd()->EnableWindow(FALSE);

		CString strTemp;

		// start document printing process
		if (dcPrint.StartDoc(&docInfo) == SP_ERROR)
		{
			// enable main window before proceeding
			AfxGetMainWnd()->EnableWindow(TRUE);

			// cleanup and show error message
			pThis->DoEndPrinting(pView, &dcPrint, &printInfo);
			dcPrint.Detach();   // will be cleaned up by CPrintInfo destructor
			AfxMessageBox(AFX_IDP_FAILED_TO_START_PRINT);
			return E_UNEXPECTED;
		}

		// Guarantee values are in the valid range
		UINT nEndPage = printInfo.GetToPage();
		UINT nStartPage = printInfo.GetFromPage();

		if (nEndPage < printInfo.GetMinPage())
			nEndPage = printInfo.GetMinPage();
		if (nEndPage > printInfo.GetMaxPage())
			nEndPage = printInfo.GetMaxPage();

		if (nStartPage < printInfo.GetMinPage())
			nStartPage = printInfo.GetMinPage();
		if (nStartPage > printInfo.GetMaxPage())
			nStartPage = printInfo.GetMaxPage();

		int nStep = (nEndPage >= nStartPage) ? 1 : -1;
		nEndPage = (nEndPage == 0xffff) ? 0xffff : nEndPage + nStep;

		VERIFY(strTemp.LoadString(AFX_IDS_PRINTPAGENUM));

		// begin page printing loop
		BOOL bError = FALSE;
		HRESULT hrContinue = S_OK;

		for (printInfo.m_nCurPage = nStartPage;
			printInfo.m_nCurPage != nEndPage; printInfo.m_nCurPage += nStep)
		{
			// check even/odd filter
			if (printInfo.m_nCurPage % 2 == 1 && !(*ppPageSet)->fOddPages)
				continue;
			if (printInfo.m_nCurPage % 2 == 0 && !(*ppPageSet)->fEvenPages)
				continue;

			// check PAGERANGE if supplied
			if (ppPageSet != NULL && (*ppPageSet)->cPageRange > 0)
			{
				ULONG nCheckRange;
				BOOL bFound = FALSE;
				for (nCheckRange = 0; (nCheckRange < (*ppPageSet)->cPageRange) && !bFound; nCheckRange++)
				{
					if ( ((*ppPageSet)->rgPages[nCheckRange].nFromPage <= (LONG) printInfo.m_nCurPage ) &&
						 ((*ppPageSet)->rgPages[nCheckRange].nToPage >= (LONG) printInfo.m_nCurPage) )
					{
						bFound = TRUE;
					}
				}

				if (!bFound)
					continue;
			}

			pThis->DoPrepareDC(pView, &dcPrint, &printInfo);

			// check for end of print
			if (!printInfo.m_bContinuePrinting)
				break;

			// set up drawing rect to entire page (in logical coordinates)
			printInfo.m_rectDraw.SetRect(0, 0,
				dcPrint.GetDeviceCaps(HORZRES),
				dcPrint.GetDeviceCaps(VERTRES));
			dcPrint.DPtoLP(&printInfo.m_rectDraw);

			// attempt to start the current page
			if (dcPrint.StartPage() < 0)
			{
				bError = TRUE;
				break;
			}

			// must call OnPrepareDC on newer versions of Windows because
			// StartPage now resets the device attributes.
			if (afxData.bMarked4)
				pThis->DoPrepareDC(pView, &dcPrint, &printInfo);

			ASSERT(printInfo.m_bContinuePrinting);

			hrContinue = S_OK;

			if (pCallback != NULL)
			{
				hrContinue = pCallback->FContinuePrinting(printInfo.m_nCurPage,
					printInfo.m_nCurPage + printInfo.m_nOffsetPage, NULL);
			}

			// page successfully started, so now render the page
			pThis->DoPrint(pView, &dcPrint, &printInfo);
			if (dcPrint.EndPage() < 0 ||
				!_AfxAbortProc(dcPrint.m_hDC, 0) ||
				hrContinue != S_OK)
			{
				bError = TRUE;
				break;
			}

			// increment count
			(*pcPagesPrinted)++;
		}

		// cleanup document printing process
		if (!bError)
			dcPrint.EndDoc();
		else
			dcPrint.AbortDoc();

		AfxGetMainWnd()->EnableWindow();    // enable main window

		// clean up after printing
		pThis->DoEndPrinting(pView, &dcPrint, &printInfo);
		dcPrint.Detach();   // will be cleaned up by CPrintInfo destructor

		if (bError)
		{
			if (hrContinue != S_OK)
				return PRINT_E_CANCELLED;
			else
				return E_UNEXPECTED;
		}
	}

	return S_OK;
}

/////////////////////////////////////////////////////////////////////////////
// IOleDocument interface

STDMETHODIMP_(ULONG) CDocObjectServer::XOleDocument::AddRef()
{
	METHOD_PROLOGUE_EX(CDocObjectServer, OleDocument)
	return pThis->m_pOwner->ExternalAddRef();
}

STDMETHODIMP_(ULONG) CDocObjectServer::XOleDocument::Release()
{
	METHOD_PROLOGUE_EX(CDocObjectServer, OleDocument)
	return pThis->m_pOwner->ExternalRelease();
}

STDMETHODIMP CDocObjectServer::XOleDocument::QueryInterface(
	REFIID iid, LPVOID* ppvObj)
{
	METHOD_PROLOGUE_EX(CDocObjectServer, OleDocument)
	return pThis->ExternalQueryInterface(&iid, ppvObj);
}

STDMETHODIMP CDocObjectServer::XOleDocument::CreateView(
   LPOLEINPLACESITE pipsite, LPSTREAM pstm,
   DWORD dwReserved, LPOLEDOCUMENTVIEW* ppview)
{
   METHOD_PROLOGUE_EX(CDocObjectServer, OleDocument)
   ASSERT_VALID(pThis);

   *ppview = NULL;

   HRESULT hr = E_FAIL;

   if (dwReserved == 0 && pThis->m_pDocSite != NULL)
   {
	  // We only support a single view...so if view site is already
	  // set, fail.
	  if (pThis->m_pViewSite == NULL)
	  {
		 LPOLEDOCUMENTVIEW pView =
			(LPOLEDOCUMENTVIEW)pThis->GetInterface(&IID_IOleDocumentView);
		 ASSERT(pView != NULL);

		 // Set the site for the view
		 hr = pView->SetInPlaceSite(pipsite);
		 if (hr == NOERROR)
		 {
			// Return the IOleDocumentView pointer
			pView->AddRef();
			*ppview = pView;
		 }

		 // If a saved view state is provided, restore the view state
		 if (pstm)
			hr = pView->ApplyViewState(pstm);
	  }
	  else
		 TRACE0("CDocObjectServer::XOleDocument::CreateView view already exists!\n");
   }

   return hr;
}

STDMETHODIMP CDocObjectServer::XOleDocument::GetDocMiscStatus(
   LPDWORD pdwStatus)
{
   METHOD_PROLOGUE_EX(CDocObjectServer, OleDocument)
   ASSERT_VALID(pThis);
   ASSERT(pdwStatus != NULL);

   // Our implementation of DocObjects can't create multiple views,
   // does not support complex rectangles, supports open editing,
   // and supports read/write to a file. Thus DOCMISC == 0.
   *pdwStatus = 0;

   return NOERROR;
}

STDMETHODIMP CDocObjectServer::XOleDocument::EnumViews(
   LPENUMOLEDOCUMENTVIEWS* ppEnumView, LPOLEDOCUMENTVIEW* ppView)
{
   METHOD_PROLOGUE_EX(CDocObjectServer, OleDocument)
   ASSERT_VALID(pThis);
   ASSERT(ppEnumView != NULL);
   ASSERT(ppView != NULL);

   // We only support a single view
   *ppEnumView = NULL;
   HRESULT hr = QueryInterface(IID_IOleDocumentView, (LPVOID*)ppView);
   return hr;
}

/////////////////////////////////////////////////////////////////////////////
// IOleObject interface

STDMETHODIMP_(ULONG) CDocObjectServer::XOleObject::AddRef()
{
	METHOD_PROLOGUE_EX(CDocObjectServer, OleObject)
	return pThis->m_pOwner->ExternalAddRef();
}

STDMETHODIMP_(ULONG) CDocObjectServer::XOleObject::Release()
{
	METHOD_PROLOGUE_EX(CDocObjectServer, OleObject)
	return pThis->m_pOwner->ExternalRelease();
}

STDMETHODIMP CDocObjectServer::XOleObject::QueryInterface(
	REFIID iid, LPVOID* ppvObj)
{
	METHOD_PROLOGUE_EX(CDocObjectServer, OleObject)
	return pThis->m_pOwner->ExternalQueryInterface(&iid, ppvObj);
}

STDMETHODIMP CDocObjectServer::XOleObject::SetClientSite(
	LPOLECLIENTSITE pClientSite)
{
	METHOD_PROLOGUE_EX(CDocObjectServer, OleObject)
	ASSERT_VALID(pThis);
	HRESULT hr = NOERROR;

	// Perform normal SetClientSite processing.
	hr = pThis->m_pOwner->m_xOleObject.SetClientSite(pClientSite);
	if (hr != S_OK)
		return hr;

	// If we currently have a document site pointer,
	// release it.

	pThis->ReleaseDocSite();

	// Check to see whether this object should act
	// as a document object by querying for
	// IOleDocumentSite.
	if (pClientSite != NULL)
		hr = pClientSite->QueryInterface(IID_IOleDocumentSite,
			(LPVOID*)&pThis->m_pDocSite);
	return hr;
}

STDMETHODIMP CDocObjectServer::XOleObject::GetClientSite(
	LPOLECLIENTSITE* ppClientSite)
{
	METHOD_PROLOGUE_EX(CDocObjectServer, OleObject)
	ASSERT_VALID(pThis);
	return pThis->m_pOwner->m_xOleObject.GetClientSite(ppClientSite);
}

STDMETHODIMP CDocObjectServer::XOleObject::SetHostNames(
	LPCOLESTR lpszContainerApp, LPCOLESTR lpszContainerObj)
{
	METHOD_PROLOGUE_EX(CDocObjectServer, OleObject)
	ASSERT_VALID(pThis);
	return pThis->m_pOwner->m_xOleObject.SetHostNames(lpszContainerApp,
										   lpszContainerObj);
}

STDMETHODIMP CDocObjectServer::XOleObject::Close(DWORD dwSaveOption)
{
	METHOD_PROLOGUE_EX(CDocObjectServer, OleObject)
	ASSERT_VALID(pThis);
	return pThis->m_pOwner->m_xOleObject.Close(dwSaveOption);
}

STDMETHODIMP CDocObjectServer::XOleObject::SetMoniker(
	DWORD dwWhichMoniker, LPMONIKER pmk)
{
	METHOD_PROLOGUE_EX(CDocObjectServer, OleObject)
	ASSERT_VALID(pThis);
	return pThis->m_pOwner->m_xOleObject.SetMoniker(dwWhichMoniker, pmk);
}

STDMETHODIMP CDocObjectServer::XOleObject::GetMoniker(
	DWORD dwAssign, DWORD dwWhichMoniker, LPMONIKER* ppMoniker)
{
	METHOD_PROLOGUE_EX(CDocObjectServer, OleObject)
	ASSERT_VALID(pThis);
	return pThis->m_pOwner->m_xOleObject.GetMoniker(dwAssign, dwWhichMoniker,
										 ppMoniker);
}

STDMETHODIMP CDocObjectServer::XOleObject::InitFromData(
	LPDATAOBJECT pDataObject, BOOL bCreation, DWORD dwReserved)
{
	METHOD_PROLOGUE_EX(CDocObjectServer, OleObject)
	ASSERT_VALID(pThis);
	return pThis->m_pOwner->m_xOleObject.InitFromData(pDataObject, bCreation,
										   dwReserved);
}

STDMETHODIMP CDocObjectServer::XOleObject::GetClipboardData(
	DWORD dwReserved, LPDATAOBJECT* ppDataObject)
{
	METHOD_PROLOGUE_EX(CDocObjectServer, OleObject)
	ASSERT_VALID(pThis);
	return pThis->m_pOwner->m_xOleObject.GetClipboardData(dwReserved,
											   ppDataObject);

}

STDMETHODIMP CDocObjectServer::XOleObject::DoVerb(
	LONG iVerb, LPMSG lpmsg, LPOLECLIENTSITE pActiveSite, LONG lindex,
	HWND hwndParent, LPCRECT lpPosRect)
{
	METHOD_PROLOGUE_EX(CDocObjectServer, OleObject)
	ASSERT_VALID(pThis);
	return pThis->m_pOwner->m_xOleObject.DoVerb(iVerb, lpmsg,
		pActiveSite, lindex, hwndParent, lpPosRect);
}

STDMETHODIMP CDocObjectServer::XOleObject::EnumVerbs(
	IEnumOLEVERB** ppenumOleVerb)
{
	METHOD_PROLOGUE_EX(CDocObjectServer, OleObject)
	ASSERT_VALID(pThis);
	return pThis->m_pOwner->m_xOleObject.EnumVerbs(ppenumOleVerb);
}

STDMETHODIMP CDocObjectServer::XOleObject::Update()
{
	METHOD_PROLOGUE_EX(CDocObjectServer, OleObject)
	ASSERT_VALID(pThis);
	return pThis->m_pOwner->m_xOleObject.Update();
}

STDMETHODIMP CDocObjectServer::XOleObject::IsUpToDate()
{
	METHOD_PROLOGUE_EX(CDocObjectServer, OleObject)
	ASSERT_VALID(pThis);
	return pThis->m_pOwner->m_xOleObject.IsUpToDate();
}

STDMETHODIMP CDocObjectServer::XOleObject::GetUserClassID(CLSID* lpClassID)
{
	METHOD_PROLOGUE_EX(CDocObjectServer, OleObject)
	ASSERT_VALID(pThis);
	return pThis->m_pOwner->m_xOleObject.GetUserClassID(lpClassID);
}

STDMETHODIMP CDocObjectServer::XOleObject::GetUserType(
	DWORD dwFormOfType, LPOLESTR* ppszUserType)
{
	METHOD_PROLOGUE_EX(CDocObjectServer, OleObject)
	ASSERT_VALID(pThis);
	return pThis->m_pOwner->m_xOleObject.GetUserType(dwFormOfType, ppszUserType);
}

STDMETHODIMP CDocObjectServer::XOleObject::SetExtent(
	DWORD dwDrawAspect, LPSIZEL lpsizel)
{
	METHOD_PROLOGUE_EX(CDocObjectServer, OleObject)
	ASSERT_VALID(pThis);

	// DocObjects ignore SetExtent calls, so returne E_FAIL
	if (pThis->m_pOwner->IsDocObject())
		return E_FAIL;

	// Otherwise, just do the normal processing
	return pThis->m_pOwner->m_xOleObject.SetExtent(dwDrawAspect, lpsizel);
}

STDMETHODIMP CDocObjectServer::XOleObject::GetExtent(
	DWORD dwDrawAspect, LPSIZEL lpsizel)
{
	METHOD_PROLOGUE_EX(CDocObjectServer, OleObject)
	ASSERT_VALID(pThis);
	return pThis->m_pOwner->m_xOleObject.GetExtent(dwDrawAspect, lpsizel);
}

STDMETHODIMP CDocObjectServer::XOleObject::Advise(
	LPADVISESINK pAdvSink, DWORD* pdwConnection)
{
	METHOD_PROLOGUE_EX(CDocObjectServer, OleObject)
	ASSERT_VALID(pThis);
	return pThis->m_pOwner->m_xOleObject.Advise(pAdvSink, pdwConnection);
}

STDMETHODIMP CDocObjectServer::XOleObject::Unadvise(DWORD dwConnection)
{
	METHOD_PROLOGUE_EX(CDocObjectServer, OleObject)
	ASSERT_VALID(pThis);
	return pThis->m_pOwner->m_xOleObject.Unadvise(dwConnection);
}

STDMETHODIMP CDocObjectServer::XOleObject::EnumAdvise(
	LPENUMSTATDATA* ppenumStatData)
{
	METHOD_PROLOGUE_EX(CDocObjectServer, OleObject)
	ASSERT_VALID(pThis);
	return pThis->m_pOwner->m_xOleObject.EnumAdvise(ppenumStatData);
}

STDMETHODIMP CDocObjectServer::XOleObject::GetMiscStatus(
	DWORD dwAspect, DWORD* pdwStatus)
{
	METHOD_PROLOGUE_EX(CDocObjectServer, OleObject)
	ASSERT_VALID(pThis);
	return pThis->m_pOwner->m_xOleObject.GetMiscStatus(dwAspect, pdwStatus);
}

STDMETHODIMP CDocObjectServer::XOleObject::SetColorScheme(LPLOGPALETTE lpLogpal)
{
	METHOD_PROLOGUE_EX(CDocObjectServer, OleObject)
	ASSERT_VALID(pThis);
	return pThis->m_pOwner->m_xOleObject.SetColorScheme(lpLogpal);
}


/////////////////////////////////////////////////////////////////////////////
// CDocObjectServer diagnostics

#ifdef _DEBUG
void CDocObjectServer::AssertValid() const
{
	ASSERT(m_pOwner != NULL);
	CCmdTarget::AssertValid();
}

void CDocObjectServer::Dump(CDumpContext& dc) const
{
	CCmdTarget::Dump(dc);
	dc << "m_pDocSite = " << m_pDocSite << "\n";
	dc << "m_pViewSite = " << m_pViewSite << "\n";
}
#endif //_DEBUG


/////////////////////////////////////////////////////////////////////////////
// CDocObjectServerItem implementation

IMPLEMENT_DYNAMIC(CDocObjectServerItem, COleServerItem)

CDocObjectServerItem::CDocObjectServerItem(COleServerDoc* pServerDoc, BOOL bAutoDelete)
	: COleServerItem(pServerDoc, bAutoDelete)
{
}

CDocObjectServerItem::~CDocObjectServerItem()
{
}

void CDocObjectServerItem::OnDoVerb(LONG iVerb)
{
   COleServerDoc* pDoc = GetDocument();
   ASSERT_VALID(pDoc);

   if (pDoc->IsDocObject() && (iVerb == OLEIVERB_INPLACEACTIVATE || iVerb == OLEIVERB_SHOW) )
	  OnShow();
   else
	  COleServerItem::OnDoVerb(iVerb);
}

void CDocObjectServerItem::OnHide()
{
   COleServerDoc* pDoc = GetDocument();
   ASSERT_VALID(pDoc);

   if (pDoc->IsDocObject())
	  AfxThrowOleException(OLEOBJ_E_INVALIDVERB);
   else
	  COleServerItem::OnHide();
}

void CDocObjectServerItem::OnOpen()
{
   COleServerDoc* pDoc = GetDocument();
   ASSERT_VALID(pDoc);

   if (pDoc->IsDocObject())
	  pDoc->ActivateDocObject();
   else
	  COleServerItem::OnOpen();
}

void CDocObjectServerItem::OnShow()
{
   COleServerDoc* pDoc = GetDocument();
   ASSERT_VALID(pDoc);

   if (pDoc->IsDocObject())
	  pDoc->ActivateDocObject();
   else
	  COleServerItem::OnShow();
}

#ifdef _DEBUG
void CDocObjectServerItem::AssertValid() const
{
	COleServerItem::AssertValid();
}

void CDocObjectServerItem::Dump(CDumpContext& dc) const
{
	COleServerItem::Dump(dc);
}
#endif
