419 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			419 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /***************************************************************************
 | |
|  * DSOFPRINT.CPP
 | |
|  *
 | |
|  * CDsoDocObject: Print Code for CDsoDocObject object
 | |
|  *
 | |
|  *  Copyright ©1999-2004; Microsoft Corporation. All rights reserved.
 | |
|  *  Written by Microsoft Developer Support Office Integration (PSS DSOI)
 | |
|  * 
 | |
|  *  This code is provided via KB 311765 as a sample. It is not a formal
 | |
|  *  product and has not been tested with all containers or servers. Use it
 | |
|  *  for educational purposes only. See the EULA.TXT file included in the
 | |
|  *  KB download for full terms of use and restrictions.
 | |
|  *
 | |
|  *  THIS CODE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 
 | |
|  *  EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
 | |
|  *  WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
 | |
|  *
 | |
|  ***************************************************************************/
 | |
| #include "dsoframer.h"
 | |
| 
 | |
| ////////////////////////////////////////////////////////////////////////
 | |
| // CDsoFramerControl::_PrintOutOld
 | |
| //
 | |
| //  Prints the current object by calling IOleCommandTarget for Print.
 | |
| //
 | |
| STDMETHODIMP CDsoFramerControl::_PrintOutOld(VARIANT PromptToSelectPrinter)
 | |
| {
 | |
|     DWORD dwOption = BOOL_FROM_VARIANT(PromptToSelectPrinter, FALSE) 
 | |
|                    ? OLECMDEXECOPT_PROMPTUSER : OLECMDEXECOPT_DODEFAULT;
 | |
| 
 | |
|     TRACE1("CDsoFramerControl::_PrintOutOld(%d)\n", dwOption);
 | |
|     CHECK_NULL_RETURN(m_pDocObjFrame, ProvideErrorInfo(DSO_E_DOCUMENTNOTOPEN));
 | |
| 
 | |
|  // Cannot access object if in modal condition...
 | |
|     if ((m_fModalState) || (m_pDocObjFrame->InPrintPreview()))
 | |
|         return ProvideErrorInfo(DSO_E_INMODALSTATE);
 | |
| 
 | |
| 	return m_pDocObjFrame->DoOleCommand(OLECMDID_PRINT, dwOption, NULL, NULL);
 | |
| }
 | |
| 
 | |
| ////////////////////////////////////////////////////////////////////////
 | |
| // CDsoFramerControl::PrintOut
 | |
| //
 | |
| //  Prints document using either IPrint or IOleCommandTarget, depending
 | |
| //  on parameters passed. This offers a bit more control over printing if
 | |
| //  the doc object server supports IPrint interface.
 | |
| //
 | |
| STDMETHODIMP CDsoFramerControl::PrintOut(VARIANT PromptUser, VARIANT PrinterName,
 | |
|                 VARIANT Copies, VARIANT FromPage, VARIANT ToPage, VARIANT OutputFile)
 | |
| {
 | |
|     HRESULT hr;
 | |
|     BOOL fPromptUser   = BOOL_FROM_VARIANT(PromptUser, FALSE);
 | |
|     LPWSTR pwszPrinter = LPWSTR_FROM_VARIANT(PrinterName);
 | |
|     LPWSTR pwszOutput  = LPWSTR_FROM_VARIANT(OutputFile);
 | |
|     LONG lCopies       = LONG_FROM_VARIANT(Copies, 1);
 | |
|     LONG lFrom         = LONG_FROM_VARIANT(FromPage, 0);
 | |
|     LONG lTo           = LONG_FROM_VARIANT(ToPage, 0);
 | |
| 
 | |
| 	TRACE3("CDsoFramerControl::PrintOut(%d, %S, %d)\n", fPromptUser, pwszPrinter, lCopies);
 | |
|     CHECK_NULL_RETURN(m_pDocObjFrame, ProvideErrorInfo(DSO_E_DOCUMENTNOTOPEN));
 | |
| 
 | |
|  // First we do validation of all parameters passed to the function...
 | |
|     if ((pwszPrinter) && (*pwszPrinter == L'\0'))
 | |
|         return E_INVALIDARG;
 | |
| 
 | |
|     if ((pwszOutput) && (*pwszOutput == L'\0'))
 | |
|         return E_INVALIDARG;
 | |
| 
 | |
|     if ((lCopies < 1) || (lCopies > 200))
 | |
|         return E_INVALIDARG;
 | |
| 
 | |
|     if (((lFrom != 0) || (lTo != 0)) && ((lFrom < 1) || (lTo < lFrom)))
 | |
|         return E_INVALIDARG;
 | |
| 
 | |
|  // Cannot access object if in modal condition...
 | |
|     if ((m_fModalState) || (m_pDocObjFrame->InPrintPreview()))
 | |
|         return ProvideErrorInfo(DSO_E_INMODALSTATE);
 | |
| 
 | |
|  // If no printer name was provided, we can print to the default device
 | |
|  // using IOleCommandTarget with OLECMDID_PRINT...
 | |
|     if (pwszPrinter == NULL)
 | |
|         return _PrintOutOld(PromptUser);
 | |
| 
 | |
|  // Ask the embedded document to print itself to specific printer...
 | |
|     hr = m_pDocObjFrame->PrintDocument(pwszPrinter, pwszOutput, (UINT)lCopies, 
 | |
|                         (UINT)lFrom, (UINT)lTo, fPromptUser);
 | |
| 
 | |
|  // If call failed because interface doesn't exist, change error
 | |
|  // to let caller know it is because DocObj doesn't support this command...
 | |
|     if (FAILED(hr) && (hr == E_NOINTERFACE))
 | |
|         hr = DSO_E_COMMANDNOTSUPPORTED;
 | |
| 
 | |
|     return ProvideErrorInfo(hr);
 | |
| }
 | |
| 
 | |
| ////////////////////////////////////////////////////////////////////////
 | |
| // CDsoFramerControl::PrintPreview
 | |
| //
 | |
| //  Asks embedded object to attempt a print preview (only Office docs do this).
 | |
| //
 | |
| STDMETHODIMP CDsoFramerControl::PrintPreview()
 | |
| {
 | |
|     HRESULT hr;
 | |
| 	ODS("CDsoFramerControl::PrintPreview\n");
 | |
|     CHECK_NULL_RETURN(m_pDocObjFrame, ProvideErrorInfo(DSO_E_DOCUMENTNOTOPEN));
 | |
| 
 | |
|     if (m_fModalState) // Cannot access object if in modal condition...
 | |
|         return ProvideErrorInfo(DSO_E_INMODALSTATE);
 | |
| 
 | |
|  // Try to set object into print preview mode...
 | |
|     hr = m_pDocObjFrame->StartPrintPreview();
 | |
| 
 | |
|  // If call failed because interface doesn't exist, change error
 | |
|  // to let caller know it is because DocObj doesn't support this command...
 | |
|     if (FAILED(hr) && (hr == E_NOINTERFACE))
 | |
|         hr = DSO_E_COMMANDNOTSUPPORTED;
 | |
| 
 | |
|     return ProvideErrorInfo(hr);
 | |
| }
 | |
| 
 | |
| ////////////////////////////////////////////////////////////////////////
 | |
| // CDsoFramerControl::PrintPreviewExit
 | |
| //
 | |
| //  Closes an active preview.
 | |
| //
 | |
| STDMETHODIMP CDsoFramerControl::PrintPreviewExit()
 | |
| {
 | |
| 	ODS("CDsoFramerControl::PrintPreviewExit\n");
 | |
|     CHECK_NULL_RETURN(m_pDocObjFrame, ProvideErrorInfo(DSO_E_DOCUMENTNOTOPEN));
 | |
| 
 | |
|  // Try to set object out of print preview mode...
 | |
|     if (m_pDocObjFrame->InPrintPreview())
 | |
|         m_pDocObjFrame->ExitPrintPreview(TRUE);
 | |
| 
 | |
|     return S_OK;
 | |
| }
 | |
| 
 | |
| 
 | |
| ////////////////////////////////////////////////////////////////////////
 | |
| // CDsoDocObject::PrintDocument
 | |
| //
 | |
| //  We can use the IPrint interface for an ActiveX Document object to 
 | |
| //  selectively print object to a given printer. 
 | |
| //
 | |
| STDMETHODIMP CDsoDocObject::PrintDocument(LPCWSTR pwszPrinter, LPCWSTR pwszOutput, UINT cCopies, UINT nFrom, UINT nTo, BOOL fPromptUser)
 | |
| {
 | |
|     HRESULT hr;
 | |
|     IPrint *print;
 | |
|     HANDLE hPrint;
 | |
|     DVTARGETDEVICE* ptd = NULL;
 | |
| 
 | |
|     ODS("CDsoDocObject::PrintDocument\n");
 | |
|     CHECK_NULL_RETURN(m_pole, E_UNEXPECTED);
 | |
| 
 | |
|  // First thing we need to do is ask object for IPrint. If it does not
 | |
|  // support it, we cannot continue. It is up to DocObj if this is allowed...
 | |
|     hr = m_pole->QueryInterface(IID_IPrint, (void**)&print);
 | |
|     RETURN_ON_FAILURE(hr);
 | |
| 
 | |
|  // Now setup printer settings into DEVMODE for IPrint. Open printer 
 | |
|  // settings and gather default DEVMODE...
 | |
|     if (FOpenPrinter(pwszPrinter, &hPrint))
 | |
|     {
 | |
|         LPDEVMODEW pdevMode     = NULL;
 | |
|         LPWSTR pwszDefProcessor = NULL;
 | |
|         LPWSTR pwszDefDriver    = NULL;
 | |
|         LPWSTR pwszDefPort      = NULL;
 | |
|         LPWSTR pwszPort;
 | |
|         DWORD  cbDevModeSize;
 | |
| 
 | |
|         if (FGetPrinterSettings(hPrint, &pwszDefProcessor, 
 | |
|                 &pwszDefDriver, &pwszDefPort, &pdevMode, &cbDevModeSize) && (pdevMode))
 | |
|         {
 | |
|             DWORD cbPrintName, cbDeviceName, cbOutputName;
 | |
|             DWORD cbDVTargetSize;
 | |
| 
 | |
|             pdevMode->dmFields |= DM_COPIES;
 | |
|             pdevMode->dmCopies = (WORD)((cCopies) ? cCopies : 1);
 | |
| 
 | |
|             pwszPort = ((pwszOutput) ? (LPWSTR)pwszOutput : pwszDefPort);
 | |
|          
 | |
|          // We calculate the size we will need for the TARGETDEVICE structure...
 | |
|             cbPrintName  = ((lstrlenW(pwszDefProcessor) + 1) * sizeof(WCHAR));
 | |
|             cbDeviceName = ((lstrlenW(pwszDefDriver)    + 1) * sizeof(WCHAR));
 | |
|             cbOutputName = ((lstrlenW(pwszPort)         + 1) * sizeof(WCHAR));
 | |
| 
 | |
|             cbDVTargetSize = sizeof(DWORD) + sizeof(DEVNAMES) + cbPrintName +
 | |
|                             cbDeviceName + cbOutputName + cbDevModeSize;
 | |
| 
 | |
|          // Allocate new target device using COM Task Allocator...
 | |
|             ptd = (DVTARGETDEVICE*)CoTaskMemAlloc(cbDVTargetSize);
 | |
|             if (ptd)
 | |
|             {
 | |
|              // Copy all the data in the DVT...
 | |
|                 DWORD dwOffset = sizeof(DWORD) + sizeof(DEVNAMES);
 | |
|                 ptd->tdSize = cbDVTargetSize;
 | |
| 
 | |
|                 ptd->tdDriverNameOffset = (WORD)dwOffset;
 | |
|                 memcpy((BYTE*)(((BYTE*)ptd) + dwOffset), pwszDefProcessor, cbPrintName);
 | |
|                 dwOffset += cbPrintName;
 | |
| 
 | |
|                 ptd->tdDeviceNameOffset = (WORD)dwOffset;
 | |
|                 memcpy((BYTE*)(((BYTE*)ptd) + dwOffset), pwszDefDriver, cbDeviceName);
 | |
|                 dwOffset += cbDeviceName;
 | |
| 
 | |
|                 ptd->tdPortNameOffset = (WORD)dwOffset;
 | |
|                 memcpy((BYTE*)(((BYTE*)ptd) + dwOffset), pwszPort, cbOutputName);
 | |
|                 dwOffset += cbOutputName;
 | |
| 
 | |
|                 ptd->tdExtDevmodeOffset = (WORD)dwOffset;
 | |
|                 memcpy((BYTE*)(((BYTE*)ptd) + dwOffset), pdevMode, cbDevModeSize);
 | |
|                 dwOffset += cbDevModeSize;
 | |
| 
 | |
|                 ASSERT(dwOffset == cbDVTargetSize);
 | |
|             }
 | |
|             else hr = E_OUTOFMEMORY;
 | |
| 
 | |
|          // We're done with the devmode...
 | |
|             DsoMemFree(pdevMode);
 | |
|         }
 | |
|         else hr = E_WIN32_LASTERROR;
 | |
| 
 | |
|         SAFE_FREESTRING(pwszDefPort);
 | |
|         SAFE_FREESTRING(pwszDefDriver);
 | |
|         SAFE_FREESTRING(pwszDefProcessor);
 | |
|         ClosePrinter(hPrint);
 | |
|     }
 | |
|     else hr = E_WIN32_LASTERROR;
 | |
| 
 | |
|  // If we were successful in getting TARGETDEVICE struct, provide the page range
 | |
|  // for the print job and ask docobj server to print it...
 | |
|     if (SUCCEEDED(hr))
 | |
|     {
 | |
|         PAGESET *ppgset;
 | |
|         DWORD cbPgRngSize = sizeof(PAGESET) + sizeof(PAGERANGE);
 | |
|         LONG cPages, cLastPage;
 | |
|         DWORD grfPrintFlags;
 | |
| 
 | |
|      // Setup the page range to print...
 | |
|         if ((ppgset = (PAGESET*)CoTaskMemAlloc(cbPgRngSize)) != NULL)
 | |
|         {
 | |
|             ppgset->cbStruct = cbPgRngSize;
 | |
|             ppgset->cPageRange   = 1;
 | |
|             ppgset->fOddPages    = TRUE;
 | |
|             ppgset->fEvenPages   = TRUE;
 | |
|             ppgset->cPageRange   = 1;
 | |
|             ppgset->rgPages[0].nFromPage = ((nFrom) ? nFrom : 1);
 | |
|             ppgset->rgPages[0].nToPage   = ((nTo) ? nTo : PAGESET_TOLASTPAGE);
 | |
| 
 | |
|          // Give indication we are waiting (on the print)...
 | |
|             HCURSOR hCur = SetCursor(LoadCursor(NULL, IDC_WAIT));
 | |
| 
 | |
|             SEH_TRY
 | |
| 
 | |
|         // Setup the initial page number (optional)...
 | |
|             print->SetInitialPageNum(ppgset->rgPages[0].nFromPage);
 | |
| 
 | |
|             grfPrintFlags = (PRINTFLAG_MAYBOTHERUSER | PRINTFLAG_RECOMPOSETODEVICE);
 | |
|             if (fPromptUser) grfPrintFlags |= PRINTFLAG_PROMPTUSER;
 | |
|             if (pwszOutput)  grfPrintFlags |= PRINTFLAG_PRINTTOFILE;
 | |
| 
 | |
|          // Now ask server to print it using settings passed...
 | |
|             hr = print->Print(grfPrintFlags, &ptd, &ppgset, NULL, (IContinueCallback*)&m_xContinueCallback, 
 | |
|                     ppgset->rgPages[0].nFromPage, &cPages, &cLastPage);
 | |
| 
 | |
|             SEH_EXCEPT(hr)
 | |
| 
 | |
|             SetCursor(hCur);
 | |
| 
 | |
|             if (ppgset)
 | |
|                 CoTaskMemFree(ppgset);
 | |
|         }
 | |
|         else hr = E_OUTOFMEMORY;
 | |
|     }
 | |
| 
 | |
|  // We are done...
 | |
|     if (ptd) CoTaskMemFree(ptd);
 | |
|     print->Release();
 | |
|     return hr;
 | |
| }
 | |
| 
 | |
| 
 | |
| ////////////////////////////////////////////////////////////////////////
 | |
| // CDsoDocObject::StartPrintPreview
 | |
| //
 | |
| //  Ask embedded object to go into print preview (if supportted).
 | |
| //
 | |
| STDMETHODIMP CDsoDocObject::StartPrintPreview()
 | |
| {
 | |
|     HRESULT hr;
 | |
|     IOleInplacePrintPreview *prev;
 | |
|     HCURSOR hCur;
 | |
| 
 | |
|     ODS("CDsoDocObject::StartPrintPreview\n");
 | |
|     CHECK_NULL_RETURN(m_pole, E_UNEXPECTED);
 | |
| 
 | |
|  // No need to do anything if already in preview...
 | |
|     if (InPrintPreview()) return S_FALSE;
 | |
| 
 | |
|  // Otherwise, ask document server if it supports preview...
 | |
|     hr = m_pole->QueryInterface(IID_IOleInplacePrintPreview, (void**)&prev);
 | |
|     if (SUCCEEDED(hr))
 | |
|     {
 | |
|      // Tell user we waiting (switch to preview can be slow for very large docs)...
 | |
|         hCur = SetCursor(LoadCursor(NULL, IDC_WAIT));
 | |
| 
 | |
|      // If it does, make sure it can go into preview mode...
 | |
|         hr = prev->QueryStatus();
 | |
|         if (SUCCEEDED(hr))
 | |
|         {
 | |
|             SEH_TRY
 | |
| 
 | |
|             if (m_hwndCtl) // Notify the control that preview started...
 | |
|                 SendMessage(m_hwndCtl, DSO_WM_ASYNCH_STATECHANGE, DSO_STATE_INTERACTIVE, (LPARAM)FALSE);
 | |
| 
 | |
|          // We will allow application to bother user and switch printers...
 | |
|             hr = prev->StartPrintPreview(
 | |
|                 (PREVIEWFLAG_MAYBOTHERUSER | PREVIEWFLAG_PROMPTUSER | PREVIEWFLAG_USERMAYCHANGEPRINTER),
 | |
|                 NULL, (IOlePreviewCallback*)&m_xPreviewCallback, 1);
 | |
| 
 | |
|             SEH_EXCEPT(hr)
 | |
| 
 | |
|          // If the call succeeds, we keep hold of interface to close preview later
 | |
|             if (SUCCEEDED(hr)) 
 | |
| 			{ 
 | |
| 				SAFE_SET_INTERFACE(m_pprtprv, prev);
 | |
| 			}
 | |
| 			else
 | |
| 			{ // Otherwise, notify the control that preview failed...
 | |
| 				if (m_hwndCtl) 
 | |
| 					PostMessage(m_hwndCtl, DSO_WM_ASYNCH_STATECHANGE, DSO_STATE_INTERACTIVE, (LPARAM)TRUE);
 | |
| 			}
 | |
|         }
 | |
| 
 | |
|         SetCursor(hCur);
 | |
|         prev->Release();
 | |
|     }
 | |
|     else if (IsPPTObject() && (m_hwndUIActiveObj))
 | |
|     {
 | |
|      // PowerPoint doesn't have print preview, but it does have slide show mode, so we can use this to
 | |
|      // toggle the viewing into slideshow...
 | |
|         if (PostMessage(m_hwndUIActiveObj, WM_KEYDOWN, VK_F5, 0x00000001) &&
 | |
|             PostMessage(m_hwndUIActiveObj, WM_KEYUP,   VK_F5, 0xC0000001))
 | |
|         {
 | |
|             hr = S_OK; m_fAttemptPptPreview = TRUE;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     return hr;
 | |
| }
 | |
| 
 | |
| ////////////////////////////////////////////////////////////////////////
 | |
| // CDsoDocObject::ExitPrintPreview
 | |
| //
 | |
| //  Drop out of print preview and restore items as needed.
 | |
| //
 | |
| STDMETHODIMP CDsoDocObject::ExitPrintPreview(BOOL fForceExit)
 | |
| {
 | |
|     TRACE1("CDsoDocObject::ExitPrintPreview(fForceExit=%d)\n", (DWORD)fForceExit);
 | |
| 
 | |
|  // Need to be in preview to run this function...
 | |
|     if (!InPrintPreview()) return S_FALSE;
 | |
| 
 | |
|  // If the user closes the app or otherwise terminates the preview, we need
 | |
|  // to notify the ActiveDocument server to leave preview mode...
 | |
|     if (m_pprtprv)
 | |
|     {
 | |
|         if (fForceExit) // Tell docobj we want to end preview...
 | |
|         {
 | |
|             HRESULT hr = m_pprtprv->EndPrintPreview(TRUE);
 | |
|             ASSERT(SUCCEEDED(hr)); (void)hr;
 | |
|         }
 | |
|     }
 | |
|     else if (m_fInPptSlideShow)
 | |
|     {
 | |
|         if ((fForceExit) && (m_hwndUIActiveObj))
 | |
|         {
 | |
|          // HACK: When it goes into slideshow, PPT 2007 changes the active window but 
 | |
|          // doesn't call SetActiveObject to update us with new object and window handle.
 | |
|          // If we post VK_ESCAPE to the window handle we have, it can fail. It needs to go
 | |
|          // to the slideshow window that PPT failed to give us handle for. As workaround,
 | |
|          // setting focus to the UI window we have handle for will automatically forward
 | |
|          // to the right window, so we can use that trick to get the right window and 
 | |
|          // make the call in a way that that should succeed regardless of PPT version...
 | |
|             SetFocus(m_hwndUIActiveObj);
 | |
|             PostMessage(GetFocus(), WM_KEYDOWN, VK_ESCAPE, 0x00000001);
 | |
|             PostMessage(GetFocus(), WM_KEYUP,   VK_ESCAPE, 0xC0000001);
 | |
|         }
 | |
|         m_fAttemptPptPreview = FALSE;
 | |
|         m_fInPptSlideShow = FALSE;
 | |
|     }
 | |
| 
 | |
|     if (m_hwndCtl) // Notify the control that preview ended...
 | |
|         SendMessage(m_hwndCtl, DSO_WM_ASYNCH_STATECHANGE, DSO_STATE_INTERACTIVE, (LPARAM)TRUE);
 | |
| 
 | |
|  // Free our reference to preview interface...
 | |
|     SAFE_RELEASE_INTERFACE(m_pprtprv);
 | |
|     return S_OK;
 | |
| }
 | |
| 
 | |
| ////////////////////////////////////////////////////////////////////////
 | |
| // CDsoDocObject::CheckForPPTPreviewChange
 | |
| //
 | |
| //  Used to update control when PPT goes in/out of slideshow asynchronously.
 | |
| //
 | |
| STDMETHODIMP_(void) CDsoDocObject::CheckForPPTPreviewChange()
 | |
| {
 | |
|     if (m_fInPptSlideShow)
 | |
|     {
 | |
|         ExitPrintPreview(FALSE);
 | |
|     }
 | |
|     else if (m_fAttemptPptPreview)
 | |
|     {
 | |
|         m_fInPptSlideShow = TRUE;
 | |
|         m_fAttemptPptPreview = FALSE;
 | |
|         if (m_hwndCtl) // Notify the control that preview started...
 | |
|             SendMessage(m_hwndCtl, DSO_WM_ASYNCH_STATECHANGE, DSO_STATE_INTERACTIVE, (LPARAM)FALSE);
 | |
|     }
 | |
| } | 
