You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3964 lines
120 KiB
3964 lines
120 KiB
//===============================================================
|
|
//
|
|
// tmpprint.cxx : Implementation of the CTemplatePrinter Peer
|
|
//
|
|
// Synposis : This class has two major responsibilities
|
|
// 1) Providing printer UI (dialogs, &c...) to a print template
|
|
// 2) Providing a way for the template document to reach the printer
|
|
//
|
|
//===============================================================
|
|
|
|
#include "headers.h"
|
|
|
|
#pragma MARK_DATA(__FILE__)
|
|
#pragma MARK_CODE(__FILE__)
|
|
#pragma MARK_CONST(__FILE__)
|
|
|
|
#ifndef X_TMPPRINT_HXX_
|
|
#define X_TMPPRINT_HXX_
|
|
#include "tmpprint.hxx"
|
|
#endif
|
|
|
|
#ifndef X_IEXTAG_H_
|
|
#define X_IEXTAG_H_
|
|
#include "iextag.h"
|
|
#endif
|
|
|
|
#ifndef X_SHLGUID_H_
|
|
#define X_SHLGUID_H_
|
|
#include <shlguid.h>
|
|
#endif
|
|
|
|
#ifndef X_MSHTMLRC_H_
|
|
#define X_MSHTMLRC_H_
|
|
#include "mshtmlrc.h" // For default header/footer resource
|
|
#endif
|
|
|
|
#ifndef X_UTILS_HXX_
|
|
#define X_UTILS_HXX_
|
|
#include "utils.hxx"
|
|
#endif
|
|
|
|
#ifndef X_DLGS_H_
|
|
#define X_DLGS_H_
|
|
#include "dlgs.h"
|
|
#endif
|
|
|
|
#ifndef X_VRSSCAN_HXX_
|
|
#define X_VRSSCAN_HXX_
|
|
#include "vrsscan.h"
|
|
#endif
|
|
|
|
#ifndef X_WINSPOOL_H_
|
|
#define X_WINSPOOL_H_
|
|
#include "winspool.h"
|
|
#endif
|
|
|
|
#ifndef X_WINGDI_H_
|
|
#define X_WINGDI_H_
|
|
#include "wingdi.h"
|
|
#endif
|
|
|
|
#include <commctrl.h>
|
|
#include <commdlg.h>
|
|
#include <mshtmcid.h>
|
|
#include <mshtmdid.h>
|
|
#include <dispex.h>
|
|
|
|
// NB (greglett)
|
|
// We need to define this because we're building with a WINVER of 4, and this is only deifned for NT5
|
|
// Remove this as soon as the winver changes.
|
|
#define NEED_BECAUSE_COMPILED_AT_WINVER_4
|
|
#ifdef NEED_BECAUSE_COMPILED_AT_WINVER_4
|
|
#define PD_CURRENTPAGE 0x00400000
|
|
#define PD_NOCURRENTPAGE 0x00800000
|
|
#endif
|
|
|
|
// This is defined in transform.hxx, but we can't access that as a peer.
|
|
inline int MulDivQuick(int nMultiplicand, int nMultiplier, int nDivisor)
|
|
{ Assert(nDivisor); return (!nDivisor-1) & MulDiv(nMultiplicand, nMultiplier, nDivisor); }
|
|
|
|
#define ORIENTPORTRAIT _T("portrait")
|
|
#define ORIENTLANDSCAPE _T("landscape")
|
|
|
|
static const TCHAR *s_aachPrintArg[] =
|
|
{
|
|
_T("__IE_BrowseDocument"), // PRINTARG_BROWSEDOC
|
|
_T("__IE_PrinterCMD_DevNames"), // PRINTARG_DEVNAMES
|
|
_T("__IE_PrinterCMD_DevMode"), // PRINTARG_DEVMODE
|
|
_T("__IE_PrinterCMD_Printer"), // PRINTARG_PRINTER
|
|
_T("__IE_PrinterCMD_Device"), // PRINTARG_DRIVER
|
|
_T("__IE_PrinterCMD_Port"), // PRINTARG_PORT
|
|
_T("__IE_PrintType"), // PRINTARG_TYPE
|
|
};
|
|
|
|
#define DEVCAP_COPIES 0
|
|
#define DEVCAP_COLLATE 1
|
|
#define DEVCAP_DUPLEX 2
|
|
#define DEVCAP_LAST_RETAIL 3 // Add more retail properties before this!
|
|
|
|
#ifndef DBG
|
|
|
|
#define DEVCAP_LAST DEVCAP_LAST_RETAIL
|
|
|
|
#else
|
|
|
|
#define DEVCAP_DBG_PRINTERNAME DEVCAP_LAST_RETAIL
|
|
#define DEVCAP_LAST DEVCAP_LAST_RETAIL + 1
|
|
|
|
#endif
|
|
|
|
static const TCHAR *s_aachDeviceCapabilities[] =
|
|
{
|
|
_T("copies"),
|
|
_T("collate"),
|
|
_T("duplex"), // Add more retail properties after this!
|
|
|
|
#if DBG == 1
|
|
_T("printerName"),
|
|
#endif
|
|
};
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function : InitMultiByteFromWideChar
|
|
//
|
|
// Synopsis : Allocates & creates a wide char string from a multi byte string.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
LPSTR
|
|
InitMultiByteFromWideChar(LPCWSTR pchWide, long cchWide)
|
|
{
|
|
long cchMulti;
|
|
char * pchMulti;
|
|
|
|
//
|
|
// Alloc space on heap for buffer.
|
|
//
|
|
cchMulti = ::WideCharToMultiByte(CP_ACP, 0, pchWide, cchWide, NULL, 0, NULL, NULL);
|
|
Assert(cchMulti > 0);
|
|
|
|
cchMulti++;
|
|
pchMulti = new char[cchMulti];
|
|
if (pchMulti)
|
|
{
|
|
::WideCharToMultiByte(CP_ACP, 0, pchWide, cchWide, pchMulti, cchMulti, NULL, NULL);
|
|
pchMulti[cchMulti - 1] = '\0';
|
|
}
|
|
|
|
return pchMulti;
|
|
}
|
|
inline LPSTR
|
|
InitMultiByteFromWideChar(LPCWSTR pwch)
|
|
{
|
|
return InitMultiByteFromWideChar(pwch, _tcslen(pwch));
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function : InitWideCharFromMultiByte
|
|
//
|
|
// Synopsis : Allocates & creates a multibyte string from a widechar string.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
LPWSTR
|
|
InitWideCharFromMultiByte(LPSTR pchMulti, long cchMulti)
|
|
{
|
|
long cchWide;
|
|
LPWSTR pchWide;
|
|
|
|
//
|
|
// Alloc space on heap for buffer.
|
|
//
|
|
cchWide = ::MultiByteToWideChar(CP_ACP, 0, pchMulti, cchMulti, NULL, 0);
|
|
Assert(cchWide > 0);
|
|
|
|
cchWide++;
|
|
pchWide = new WCHAR[cchWide];
|
|
if (pchWide)
|
|
{
|
|
::MultiByteToWideChar(CP_ACP, 0, pchMulti, cchMulti, pchWide, cchWide);
|
|
pchWide[cchWide - 1] = _T('\0');
|
|
}
|
|
|
|
return pchWide;
|
|
}
|
|
inline LPWSTR
|
|
InitWideCharFromMultiByte(LPSTR pwch)
|
|
{
|
|
return InitWideCharFromMultiByte(pwch, strlen(pwch));
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function : CreateDevNames
|
|
//
|
|
// Synopsis : Takes the three strings in a DEVNAMES structure, allocates &
|
|
// & creates the structure as a GHND.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT
|
|
CreateDevNames(TCHAR *pchDriver, TCHAR *pchPrinter, TCHAR *pchPort, HGLOBAL *pDN)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DWORD dwLenDriver, dwLenPrinter, dwLenPort;
|
|
DWORD nStructSize;
|
|
|
|
Assert(pDN);
|
|
|
|
if (!pchDriver || !pchPrinter || !pchPort)
|
|
{
|
|
hr = E_FAIL;
|
|
goto Cleanup;
|
|
}
|
|
|
|
dwLenDriver = _tcslen(pchDriver) + 1;
|
|
dwLenPrinter = _tcslen(pchPrinter) + 1;
|
|
dwLenPort = _tcslen(pchPort) + 1;
|
|
|
|
nStructSize = sizeof(DEVNAMES)
|
|
+ ((dwLenPrinter + dwLenDriver + dwLenPort) * sizeof(TCHAR));
|
|
(*pDN) = ::GlobalAlloc(GHND, nStructSize);
|
|
|
|
if (!(*pDN))
|
|
{
|
|
hr = E_FAIL;
|
|
goto Cleanup;
|
|
}
|
|
|
|
{
|
|
DEVNAMES *pDevNames = ((DEVNAMES *) ::GlobalLock(*pDN));
|
|
if (pDevNames)
|
|
{
|
|
#pragma warning(disable: 4244)
|
|
pDevNames->wDriverOffset = sizeof(DEVNAMES) / sizeof(TCHAR);
|
|
pDevNames->wDeviceOffset = pDevNames->wDriverOffset + dwLenDriver;
|
|
pDevNames->wOutputOffset = pDevNames->wDeviceOffset + dwLenPrinter;
|
|
#pragma warning(default: 4244)
|
|
_tcscpy((((TCHAR *)pDevNames) + pDevNames->wDriverOffset), pchDriver);
|
|
_tcscpy((((TCHAR *)pDevNames) + pDevNames->wDeviceOffset), pchPrinter);
|
|
_tcscpy((((TCHAR *)pDevNames) + pDevNames->wOutputOffset), pchPort);
|
|
}
|
|
::GlobalUnlock(*pDN);
|
|
}
|
|
|
|
Cleanup:
|
|
return hr;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member : Init - IElementBehavior method impl
|
|
//
|
|
// Synopsis : peer Interface, initialization
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CTemplatePrinter::Init(IElementBehaviorSite * pPeerSite)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
HKEY hKey = NULL;
|
|
|
|
if (!pPeerSite)
|
|
{
|
|
hr = E_POINTER;
|
|
goto Cleanup;
|
|
}
|
|
|
|
// cache our peer element
|
|
_pPeerSite = pPeerSite;
|
|
_pPeerSite->AddRef();
|
|
_pPeerSite->QueryInterface(IID_IElementBehaviorSiteOM, (void**)&_pPeerSiteOM);
|
|
|
|
GetDialogArguments(); // Cache the dialog arguments.
|
|
|
|
// What order should we obtain default print settings?
|
|
// 1. Settings passed in by our host (1a and 1b should be mutually exclusive)
|
|
// 1a. A DEVMODE/DEVNAMES
|
|
// 1b. A printer (and maybe a port & driver name, too)
|
|
// 2. Read defaults from the registry
|
|
// 3. Get the default Windows printer, if any.
|
|
|
|
//
|
|
// READ IN A DEVMODE/DEVNAMES
|
|
//
|
|
{
|
|
VARIANT varDM;
|
|
VARIANT varDN;
|
|
VariantInit(&varDN);
|
|
VariantInit(&varDM);
|
|
|
|
// Only accept arguments in matched pair.
|
|
if ( GetDialogArgument(&varDN, PRINTARG_DEVNAMES) == S_OK
|
|
&& GetDialogArgument(&varDM, PRINTARG_DEVMODE) == S_OK
|
|
&& V_VT(&varDN) == VT_HANDLE
|
|
&& V_VT(&varDM) == VT_HANDLE
|
|
&& V_BYREF(&varDN)
|
|
&& V_BYREF(&varDM) )
|
|
{
|
|
RemoveDialogArgument(PRINTARG_DEVNAMES);
|
|
RemoveDialogArgument(PRINTARG_DEVMODE);
|
|
|
|
_hDevNames = V_BYREF(&varDN); // NB We will release this!
|
|
_hDevMode = V_BYREF(&varDM); // NB We will release this!
|
|
}
|
|
|
|
VariantClear(&varDN);
|
|
VariantClear(&varDM);
|
|
}
|
|
|
|
//
|
|
// READ IN A PRINTER/PORT/DRIVER
|
|
//
|
|
if (!_hDevNames)
|
|
{
|
|
VARIANT varPrinter;
|
|
VARIANT varDriver;
|
|
VARIANT varPort;
|
|
|
|
VariantInit(&varPrinter);
|
|
VariantInit(&varDriver);
|
|
VariantInit(&varPort);
|
|
|
|
Assert(!_hDevMode);
|
|
|
|
if ( GetDialogArgument(&varPrinter, PRINTARG_PRINTER) == S_OK
|
|
&& V_VT(&varPrinter) == VT_BSTR
|
|
&& V_BSTR(&varPrinter) )
|
|
{
|
|
GetDialogArgument(&varDriver, PRINTARG_DRIVER);
|
|
GetDialogArgument(&varPort, PRINTARG_PORT);
|
|
|
|
if (g_fUnicodePlatform)
|
|
hr = ReadDeviceUnicode(V_BSTR(&varPrinter),
|
|
V_VT(&varDriver) == VT_BSTR ? V_BSTR(&varDriver) : NULL,
|
|
V_VT(&varPort) == VT_BSTR ? V_BSTR(&varPort) : NULL );
|
|
else
|
|
hr = ReadDeviceNonUnicode(V_BSTR(&varPrinter),
|
|
V_VT(&varDriver) == VT_BSTR ? V_BSTR(&varDriver) : NULL,
|
|
V_VT(&varPort) == VT_BSTR ? V_BSTR(&varPort) : NULL );
|
|
}
|
|
|
|
VariantClear(&varPrinter);
|
|
VariantClear(&varDriver);
|
|
VariantClear(&varPort);
|
|
}
|
|
|
|
// Get these default settings from the registry, if we can
|
|
// 1. Header/Footer
|
|
// 2. Margins
|
|
// 3. Target device (printer)
|
|
// 4. Page size/Paper source information.
|
|
if (GetRegPrintOptionsKey(PRINTOPTSUBKEY_PAGESETUP, &hKey) == S_OK)
|
|
{
|
|
ReadHeaderFooterFromRegistry(hKey);
|
|
ReadMarginsFromRegistry(hKey);
|
|
|
|
RegCloseKey(hKey);
|
|
}
|
|
|
|
// 5. Table of links
|
|
if (GetRegPrintOptionsKey(PRINTOPTSUBKEY_MAIN, &hKey) == S_OK)
|
|
{
|
|
_fPrintTableOfLinks = ReadBoolFromRegistry(hKey, _T("Print_Shortcuts"));
|
|
|
|
RegCloseKey(hKey);
|
|
}
|
|
|
|
hr = GetDeviceProperties(); // Returns E_FAIL if we don't have a valid printer at this point.
|
|
|
|
//
|
|
// DEFAULT WINDOWS PRINTER
|
|
//
|
|
if (hr)
|
|
hr = GetPrintDialogSettings(FALSE, NULL); // Get printer defaults.
|
|
|
|
Cleanup:
|
|
return hr;
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member : Detach - IElementBehavior method impl
|
|
//
|
|
// Synopsis : peer Interface, destruction work upon detaching from document
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CTemplatePrinter::Detach()
|
|
{
|
|
// Abort any currently printing document.
|
|
if (_hDC)
|
|
{
|
|
::AbortDoc(_hDC);
|
|
::DeleteDC(_hDC);
|
|
_hDC = NULL;
|
|
}
|
|
|
|
// Free any cached resources.
|
|
if (_hInstResource)
|
|
{
|
|
MLFreeLibrary(_hInstResource);
|
|
_hInstResource = NULL;
|
|
}
|
|
if (_hInstRatings)
|
|
{
|
|
FreeLibrary(_hInstRatings);
|
|
_hInstRatings = NULL;
|
|
}
|
|
if (_hInstComctl32)
|
|
{
|
|
FreeLibrary(_hInstComctl32);
|
|
_hInstComctl32 = NULL;
|
|
}
|
|
|
|
ReturnPrintHandles(); // Send our print handles back to the master thread CDoc.
|
|
if (_hDevNames)
|
|
{
|
|
::GlobalFree(_hDevNames);
|
|
_hDevNames = NULL;
|
|
}
|
|
if (_hDevMode)
|
|
{
|
|
::GlobalFree(_hDevMode);
|
|
_hDevMode = NULL;
|
|
}
|
|
|
|
// Clear any COM interfaces we currently reference
|
|
ClearInterface( &_pevDlgArgs );
|
|
ClearInterface( &_pPeerSite );
|
|
ClearInterface( &_pPeerSiteOM );
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member : Notify - IElementBehavior method impl
|
|
//
|
|
// Synopsis : peer Interface, called for notification of document events.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CTemplatePrinter::Notify(LONG lEvent, VARIANT *)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member : (ITemplatePrinter) CTemplatePrinter::printPage
|
|
//
|
|
// Synopsis : takes the passed element and prints it on its own page
|
|
// should be called any number of times after startDoc, and before endDoc.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CTemplatePrinter::printBlankPage()
|
|
{
|
|
// No TEMPLATESECURITYCHECK() required because printPage has one.
|
|
|
|
return printPage(NULL);
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CTemplatePrinter::printPage(IDispatch *pElemDisp)
|
|
{
|
|
TEMPLATESECURITYCHECK()
|
|
|
|
IHTMLElementRender *pRender = NULL;
|
|
HRESULT hr = S_OK;
|
|
|
|
if (!_hDC)
|
|
{
|
|
hr = E_FAIL;
|
|
goto Cleanup;
|
|
}
|
|
|
|
if (::StartPage(_hDC) <= 0)
|
|
{
|
|
// Returns a "nonzero" value on success, "zero" on failure.
|
|
|
|
DWORD dwError = GetLastError();
|
|
Assert(FALSE && "error calling StartPage api");
|
|
hr = E_FAIL;
|
|
goto Cleanup;
|
|
}
|
|
|
|
#ifdef DBG
|
|
RECT rcUnprintTest;
|
|
SIZE szResTest;
|
|
SIZE szPage;
|
|
|
|
szResTest.cx = ::GetDeviceCaps(_hDC, LOGPIXELSX);
|
|
szResTest.cy = ::GetDeviceCaps(_hDC, LOGPIXELSY);
|
|
szPage.cx = ::GetDeviceCaps(_hDC, PHYSICALWIDTH);
|
|
szPage.cy = ::GetDeviceCaps(_hDC, PHYSICALHEIGHT);
|
|
rcUnprintTest.left = ::GetDeviceCaps(_hDC, PHYSICALOFFSETX);
|
|
rcUnprintTest.top = ::GetDeviceCaps(_hDC, PHYSICALOFFSETY);
|
|
rcUnprintTest.right = szPage.cx - ::GetDeviceCaps(_hDC, HORZRES) - rcUnprintTest.left;
|
|
rcUnprintTest.bottom = szPage.cy - ::GetDeviceCaps(_hDC, VERTRES) - rcUnprintTest.top;
|
|
Assert( rcUnprintTest.left == _rcUnprintable.left
|
|
&& rcUnprintTest.right == _rcUnprintable.right
|
|
&& rcUnprintTest.top == _rcUnprintable.top
|
|
&& rcUnprintTest.bottom == _rcUnprintable.bottom );
|
|
#endif
|
|
|
|
// If we have been given an element, draw it to the screen.
|
|
if (pElemDisp)
|
|
{
|
|
hr = pElemDisp->QueryInterface(IID_IHTMLElementRender, (void **)&pRender);
|
|
if (hr)
|
|
goto Cleanup;
|
|
|
|
::SetViewportOrgEx(_hDC, -_rcUnprintable.left,-_rcUnprintable.top, NULL);
|
|
|
|
hr = pRender->DrawToDC(_hDC);
|
|
}
|
|
|
|
if (::EndPage(_hDC) <= 0)
|
|
{
|
|
// Known issues with EndPage:
|
|
// 1. Win95 Fax fails the EndPage API when the "SetUpMyFax" wizard is aborted. dwError=0. (100092)
|
|
DWORD dwError = GetLastError();
|
|
goto Cleanup;
|
|
}
|
|
|
|
Cleanup:
|
|
ReleaseInterface(pRender);
|
|
if (hr)
|
|
stopDoc();
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member : (ITemplatePrinter) CTemplatePrinter::startDoc
|
|
//
|
|
// Synopsis : Gets/Inits the default printer and starts to print a document.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CTemplatePrinter::startDoc(BSTR bstrTitle, VARIANT_BOOL * p)
|
|
{
|
|
TEMPLATESECURITYCHECK()
|
|
|
|
HRESULT hr = S_OK;
|
|
DOCINFO docinfo;
|
|
TCHAR achTitle[MAX_JOBNAME];
|
|
|
|
if (!p)
|
|
{
|
|
hr = E_POINTER;
|
|
goto Cleanup;
|
|
}
|
|
*p = VB_FALSE;
|
|
|
|
if ( _hDC
|
|
|| !_hDevNames
|
|
|| !_hDevMode)
|
|
{
|
|
hr = S_FALSE;
|
|
goto Cleanup;
|
|
}
|
|
|
|
{
|
|
DEVNAMES *pDevNames = ((DEVNAMES *) ::GlobalLock(_hDevNames));
|
|
void *pDevMode = ::GlobalLock(_hDevMode);
|
|
if (pDevNames && pDevMode)
|
|
{
|
|
// (greglett) Non-Unicode badness. See comment at definition of _hDevMode
|
|
if (g_fUnicodePlatform)
|
|
{
|
|
if (!_fUsePrinterCopyCollate)
|
|
{
|
|
// Force template to do its own copies/collation (to prevent both us and the printer from doing so).
|
|
((DEVMODEW *)pDevMode)->dmCollate = FALSE;
|
|
((DEVMODEW *)pDevMode)->dmCopies = 1;
|
|
}
|
|
else
|
|
{
|
|
// We might want to check if the hardware supports copy/collation
|
|
((DEVMODEW *)pDevMode)->dmFields |= DM_COPIES | DM_COLLATE;
|
|
((DEVMODEW *)pDevMode)->dmCollate = _fCollate;
|
|
((DEVMODEW *)pDevMode)->dmCopies = _nCopies;
|
|
}
|
|
|
|
_hDC = ::CreateDCW(((TCHAR *)pDevNames) + pDevNames->wDriverOffset,
|
|
((TCHAR *)pDevNames) + pDevNames->wDeviceOffset,
|
|
NULL,
|
|
(DEVMODEW *) pDevMode);
|
|
}
|
|
else
|
|
{
|
|
LPSTR pchDriver = InitMultiByteFromWideChar(((TCHAR *)pDevNames) + pDevNames->wDriverOffset);
|
|
LPSTR pchDevice = InitMultiByteFromWideChar(((TCHAR *)pDevNames) + pDevNames->wDeviceOffset);
|
|
|
|
if (!_fUsePrinterCopyCollate)
|
|
{
|
|
// Force template to do its own copies/collation (to prevent both us and the printer from doing so).
|
|
((DEVMODEA *)pDevMode)->dmCollate = FALSE;
|
|
((DEVMODEA *)pDevMode)->dmCopies = 1;
|
|
}
|
|
else
|
|
{
|
|
// We might want to check if the hardware supports copy/collation
|
|
((DEVMODEA *)pDevMode)->dmFields |= DM_COPIES | DM_COLLATE;
|
|
((DEVMODEA *)pDevMode)->dmCollate = _fCollate;
|
|
((DEVMODEA *)pDevMode)->dmCopies = _nCopies;
|
|
}
|
|
|
|
if (pchDriver && pchDevice)
|
|
{
|
|
_hDC = ::CreateDCA(pchDriver,
|
|
pchDevice,
|
|
NULL,
|
|
(DEVMODEA *)pDevMode);
|
|
}
|
|
if (pchDriver)
|
|
delete []pchDriver;
|
|
if (pchDevice)
|
|
delete []pchDevice;
|
|
}
|
|
}
|
|
::GlobalUnlock(_hDevNames);
|
|
::GlobalUnlock(_hDevMode);
|
|
|
|
if (!_hDC)
|
|
{
|
|
DWORD dwError = GetLastError();
|
|
Assert(!"Failed to create DC!");
|
|
hr = E_FAIL;
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Fill out the DOCINFO structure
|
|
//
|
|
::ZeroMemory(&docinfo,sizeof(DOCINFO));
|
|
::ZeroMemory(achTitle,sizeof(TCHAR) * MAX_JOBNAME);
|
|
docinfo.cbSize = sizeof(DOCINFO);
|
|
docinfo.fwType = 0;
|
|
|
|
if (bstrTitle)
|
|
_tcsncpy(achTitle, bstrTitle, MAX_JOBNAME - 1);
|
|
docinfo.lpszDocName = achTitle;
|
|
|
|
if (_achFileName[0])
|
|
docinfo.lpszOutput = _achFileName;
|
|
|
|
//
|
|
// Set up the document so that it can begin accepting pages
|
|
//
|
|
if (::StartDoc(_hDC, &docinfo) > 0)
|
|
*p = VB_TRUE;
|
|
#ifdef DBG
|
|
else
|
|
{
|
|
DWORD dwError = GetLastError();
|
|
goto Cleanup;
|
|
}
|
|
#endif
|
|
|
|
Cleanup:
|
|
return hr;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member : (ITemplatePrinter) CTemplatePrinter::endDoc
|
|
//
|
|
// Synopsis : 'Finishes' the doc - takes pages printed via printPage and queues the job
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CTemplatePrinter::stopDoc()
|
|
{
|
|
TEMPLATESECURITYCHECK()
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
if (!_hDC)
|
|
goto Cleanup;
|
|
|
|
if (::EndDoc(_hDC) <=0)
|
|
{
|
|
DWORD dwError = GetLastError();
|
|
Assert(FALSE && "error calling EndDoc API");
|
|
hr = E_FAIL;
|
|
goto Cleanup;
|
|
}
|
|
|
|
::DeleteDC(_hDC);
|
|
_hDC = NULL;
|
|
|
|
Cleanup:
|
|
return hr;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// (ITemplatePrinter) CTemplatePrinter::get/put framesetDocument
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CTemplatePrinter::get_framesetDocument(VARIANT_BOOL * p)
|
|
{
|
|
return GetFlagSafe(p,_fFramesetDocument);
|
|
}
|
|
STDMETHODIMP
|
|
CTemplatePrinter::put_framesetDocument(VARIANT_BOOL v)
|
|
{
|
|
PUTFLAGSAFE(_fFramesetDocument, v);
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// (ITemplatePrinter) CTemplatePrinter::get/put printTableOfLinks
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CTemplatePrinter::get_tableOfLinks(VARIANT_BOOL * p)
|
|
{
|
|
return GetFlagSafe(p,_fPrintTableOfLinks);
|
|
}
|
|
STDMETHODIMP
|
|
CTemplatePrinter::put_tableOfLinks(VARIANT_BOOL v)
|
|
{
|
|
PUTFLAGSAFE(_fPrintTableOfLinks, v);
|
|
}
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// (ITemplatePrinter) CTemplatePrinter::get/put printAllLinkedDocuments
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CTemplatePrinter::get_allLinkedDocuments(VARIANT_BOOL * p)
|
|
{
|
|
return GetFlagSafe(p, _fPrintAllLinkedDocuments);
|
|
}
|
|
STDMETHODIMP
|
|
CTemplatePrinter::put_allLinkedDocuments(VARIANT_BOOL v)
|
|
{
|
|
PUTFLAGSAFE(_fPrintAllLinkedDocuments, v);
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// (ITemplatePrinter) CTemplatePrinter::get/put printFrameActive
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CTemplatePrinter::get_frameActive(VARIANT_BOOL * p)
|
|
{
|
|
return GetFlagSafe(p,_fFrameActive);
|
|
}
|
|
STDMETHODIMP
|
|
CTemplatePrinter::put_frameActive(VARIANT_BOOL v)
|
|
{
|
|
if (!!v)
|
|
_fFrameAsShown = FALSE;
|
|
PUTFLAGSAFE(_fFrameActive, v);
|
|
}
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// (ITemplatePrinter2) CTemplatePrinter::get/put printFrameActive
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CTemplatePrinter::get_frameActiveEnabled(VARIANT_BOOL * p)
|
|
{
|
|
return GetFlagSafe(p,_fFrameActiveEnabled);
|
|
}
|
|
STDMETHODIMP
|
|
CTemplatePrinter::put_frameActiveEnabled(VARIANT_BOOL v)
|
|
{
|
|
PUTFLAGSAFE(_fFrameActiveEnabled, v);
|
|
}
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// (ITemplatePrinter) CTemplatePrinter::get/put printFrameAsShown
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CTemplatePrinter::get_frameAsShown(VARIANT_BOOL * p)
|
|
{
|
|
return GetFlagSafe(p,_fFrameAsShown);
|
|
}
|
|
STDMETHODIMP
|
|
CTemplatePrinter::put_frameAsShown(VARIANT_BOOL v)
|
|
{
|
|
if (!!v)
|
|
_fFrameActive = FALSE;
|
|
PUTFLAGSAFE(_fFrameAsShown, v);
|
|
}
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// (ITemplatePrinter) CTemplatePrinter::get/put printSelection
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CTemplatePrinter::get_selection(VARIANT_BOOL * p)
|
|
{
|
|
return GetFlagSafe(p,_fPrintSelection);
|
|
}
|
|
STDMETHODIMP
|
|
CTemplatePrinter::put_selection(VARIANT_BOOL v)
|
|
{
|
|
PUTFLAGSAFE(_fPrintSelection, v);
|
|
}
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// (ITemplatePrinter2) CTemplatePrinter::get/put printSelectionEnabled
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CTemplatePrinter::get_selectionEnabled(VARIANT_BOOL * p)
|
|
{
|
|
return GetFlagSafe(p,_fPrintSelectionEnabled);
|
|
}
|
|
STDMETHODIMP
|
|
CTemplatePrinter::put_selectionEnabled(VARIANT_BOOL v)
|
|
{
|
|
PUTFLAGSAFE(_fPrintSelectionEnabled, v);
|
|
}
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// (ITemplatePrinter) CTemplatePrinter::get/put printSelectedPages
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CTemplatePrinter::get_selectedPages(VARIANT_BOOL * p)
|
|
{
|
|
return GetFlagSafe(p,_fPrintSelectedPages);
|
|
}
|
|
STDMETHODIMP
|
|
CTemplatePrinter::put_selectedPages(VARIANT_BOOL v)
|
|
{
|
|
PUTFLAGSAFE(_fPrintSelectedPages, v);
|
|
}
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// (ITemplatePrinter) CTemplatePrinter::get/put printCurrentPage
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CTemplatePrinter::get_currentPage(VARIANT_BOOL * p)
|
|
{
|
|
return GetFlagSafe(p,_fPrintCurrentPage);
|
|
}
|
|
STDMETHODIMP
|
|
CTemplatePrinter::put_currentPage(VARIANT_BOOL v)
|
|
{
|
|
PUTFLAGSAFE(_fPrintCurrentPage, v);
|
|
}
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// (ITemplatePrinter) CTemplatePrinter::get/put printCurrentPageAvail
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CTemplatePrinter::get_currentPageAvail(VARIANT_BOOL * p)
|
|
{
|
|
return GetFlagSafe(p,_fCurrentPageAvail);
|
|
}
|
|
STDMETHODIMP
|
|
CTemplatePrinter::put_currentPageAvail(VARIANT_BOOL v)
|
|
{
|
|
PUTFLAGSAFE(_fCurrentPageAvail, v);
|
|
}
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// (ITemplatePrinter) CTemplatePrinter::get/put printCollate
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CTemplatePrinter::get_collate(VARIANT_BOOL * p)
|
|
{
|
|
return GetFlagSafe(p,_fCollate);
|
|
}
|
|
STDMETHODIMP
|
|
CTemplatePrinter::put_collate(VARIANT_BOOL v)
|
|
{
|
|
PUTFLAGSAFE(_fCollate, v);
|
|
}
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// (ITemplatePrinter2) CTemplatePrinter::get/put usePrinterCopyCollate
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CTemplatePrinter::get_usePrinterCopyCollate(VARIANT_BOOL * p)
|
|
{
|
|
return GetFlagSafe(p,_fUsePrinterCopyCollate);
|
|
}
|
|
STDMETHODIMP
|
|
CTemplatePrinter::put_usePrinterCopyCollate(VARIANT_BOOL v)
|
|
{
|
|
PUTFLAGSAFE(_fUsePrinterCopyCollate, v);
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// (ITemplatePrinter) CTemplatePrinter::get_duplex
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CTemplatePrinter::get_duplex(VARIANT_BOOL * p)
|
|
{
|
|
TEMPLATESECURITYCHECK();
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
if (!p)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
goto Cleanup;
|
|
}
|
|
|
|
*p = VB_FALSE;
|
|
|
|
if (_hDevMode)
|
|
{
|
|
void * pDevMode = ::GlobalLock(_hDevMode);
|
|
if (pDevMode)
|
|
{
|
|
// (greglett) Unicode weirdness. DEVMMODEA on Win9x, DEVMODEW on NT.
|
|
if ( ( g_fUnicodePlatform
|
|
&& (((DEVMODEW *)pDevMode)->dmFields & DM_DUPLEX)
|
|
&& ((DEVMODEW *)pDevMode)->dmDuplex != DMDUP_SIMPLEX )
|
|
|| ( !g_fUnicodePlatform
|
|
&& (((DEVMODEA *)pDevMode)->dmFields & DM_DUPLEX)
|
|
&& ((DEVMODEA *)pDevMode)->dmDuplex != DMDUP_SIMPLEX ) )
|
|
{
|
|
*p = VB_TRUE;
|
|
}
|
|
::GlobalUnlock(_hDevMode);
|
|
}
|
|
}
|
|
|
|
Cleanup:
|
|
return hr;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// (ITemplatePrinter) CTemplatePrinter::get/put copies
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CTemplatePrinter::get_copies(WORD * p)
|
|
{
|
|
TEMPLATESECURITYCHECK();
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
if (!p)
|
|
hr = E_POINTER;
|
|
else
|
|
*p = _nCopies;
|
|
|
|
return hr;
|
|
}
|
|
STDMETHODIMP
|
|
CTemplatePrinter::put_copies(WORD v)
|
|
{
|
|
TEMPLATESECURITYCHECK();
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
if (v < 0)
|
|
hr = E_INVALIDARG;
|
|
else
|
|
_nCopies = v;
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// a-naande 7-30-02 winse 25090
|
|
// if the DEVMODE struct isn't null, then the value in dmCopies will supersede
|
|
// nCopies in the PRINTDLG struct, so set it to match _nCopies
|
|
if(SUCCEEDED(hr) && _hDevMode)
|
|
{
|
|
void *pDevMode = ::GlobalLock(_hDevMode);
|
|
if (pDevMode)
|
|
{
|
|
if (g_fUnicodePlatform)
|
|
{
|
|
((DEVMODEW *)pDevMode)->dmCopies = _nCopies;
|
|
}
|
|
else
|
|
{
|
|
((DEVMODEA *)pDevMode)->dmCopies = _nCopies;
|
|
}
|
|
::GlobalUnlock(_hDevMode);
|
|
}
|
|
}
|
|
|
|
|
|
return hr;
|
|
}
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// (ITemplatePrinter) CTemplatePrinter::get/put pageFrom
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CTemplatePrinter::get_pageFrom(WORD * p)
|
|
{
|
|
TEMPLATESECURITYCHECK();
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
if (!p)
|
|
hr = E_POINTER;
|
|
else
|
|
*p = _nPageFrom;
|
|
|
|
return hr;
|
|
}
|
|
STDMETHODIMP
|
|
CTemplatePrinter::put_pageFrom(WORD v)
|
|
{
|
|
TEMPLATESECURITYCHECK();
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
if (v < 0)
|
|
hr = E_INVALIDARG;
|
|
else
|
|
_nPageFrom = v;
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// (ITemplatePrinter) CTemplatePrinter::get/put pageTo
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CTemplatePrinter::get_pageTo(WORD * p)
|
|
{
|
|
TEMPLATESECURITYCHECK();
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
if (!p)
|
|
hr = E_POINTER;
|
|
else
|
|
*p = _nPageTo;
|
|
|
|
return hr;
|
|
}
|
|
STDMETHODIMP
|
|
CTemplatePrinter::put_pageTo(WORD v)
|
|
{
|
|
TEMPLATESECURITYCHECK();
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
if (v < 0)
|
|
hr = E_INVALIDARG;
|
|
else
|
|
_nPageTo = v;
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// (ITemplatePrinter) CTemplatePrinter::get/put marginLeft/Right/Top/Bottom
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CTemplatePrinter::get_marginLeft(long * p)
|
|
{
|
|
TEMPLATESECURITYCHECK();
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
if (!p)
|
|
hr = E_POINTER;
|
|
else
|
|
*p = (_rcMargin.left / 1000);
|
|
|
|
return hr;
|
|
}
|
|
STDMETHODIMP
|
|
CTemplatePrinter::put_marginLeft(long v)
|
|
{
|
|
TEMPLATESECURITYCHECK();
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
if (v < 0)
|
|
hr = E_INVALIDARG;
|
|
else
|
|
_rcMargin.left = v * 1000;
|
|
|
|
return hr;
|
|
}
|
|
STDMETHODIMP
|
|
CTemplatePrinter::get_marginRight(long * p)
|
|
{
|
|
TEMPLATESECURITYCHECK();
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
if (!p)
|
|
hr = E_POINTER;
|
|
else
|
|
*p = (_rcMargin.right / 1000);
|
|
|
|
return hr;
|
|
}
|
|
STDMETHODIMP
|
|
CTemplatePrinter::put_marginRight(long v)
|
|
{
|
|
TEMPLATESECURITYCHECK();
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
if (v < 0)
|
|
hr = E_INVALIDARG;
|
|
else
|
|
_rcMargin.right = v * 1000;
|
|
|
|
return hr;
|
|
}
|
|
STDMETHODIMP
|
|
CTemplatePrinter::get_marginTop(long * p)
|
|
{
|
|
TEMPLATESECURITYCHECK();
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
if (!p)
|
|
hr = E_POINTER;
|
|
else
|
|
// Input in 1/100 inches.
|
|
*p = (_rcMargin.top / 1000);
|
|
|
|
return hr;
|
|
}
|
|
STDMETHODIMP
|
|
CTemplatePrinter::put_marginTop(long v)
|
|
{
|
|
TEMPLATESECURITYCHECK();
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
if (v < 0)
|
|
hr = E_INVALIDARG;
|
|
else
|
|
// Output in 1/100 inches.
|
|
_rcMargin.top = v * 1000;
|
|
|
|
return hr;
|
|
}
|
|
STDMETHODIMP
|
|
CTemplatePrinter::get_marginBottom(long * p)
|
|
{
|
|
TEMPLATESECURITYCHECK();
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
if (!p)
|
|
hr = E_POINTER;
|
|
else
|
|
// Input in 1/100 inches.
|
|
*p = (_rcMargin.bottom / 1000);
|
|
|
|
return hr;
|
|
}
|
|
STDMETHODIMP
|
|
CTemplatePrinter::put_marginBottom(long v)
|
|
{
|
|
TEMPLATESECURITYCHECK();
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
if (v < 0)
|
|
hr = E_INVALIDARG;
|
|
else
|
|
// Output in 1/100 inches.
|
|
_rcMargin.bottom = v * 1000;
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// (ITemplatePrinter) CTemplatePrinter::get pageWidth/Height
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CTemplatePrinter::get_pageWidth(long * p)
|
|
{
|
|
TEMPLATESECURITYCHECK();
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
if (!p)
|
|
hr = E_POINTER;
|
|
else
|
|
// Output in 1/100 inches.
|
|
*p = _ptPaperSize.x / 10;
|
|
|
|
return hr;
|
|
}
|
|
STDMETHODIMP
|
|
CTemplatePrinter::get_pageHeight(long * p)
|
|
{
|
|
TEMPLATESECURITYCHECK();
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
if (!p)
|
|
hr = E_POINTER;
|
|
else
|
|
// Output in 1/100 inches.
|
|
*p = _ptPaperSize.y / 10;
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// (ITemplatePrinter2) CTemplatePrinter::get/put orientation
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CTemplatePrinter::get_orientation(BSTR * p)
|
|
{
|
|
TEMPLATESECURITYCHECK();
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
if (!p)
|
|
{
|
|
hr = E_POINTER;
|
|
goto Cleanup;
|
|
}
|
|
|
|
*p = NULL;
|
|
|
|
if (GetOrientation() == DMORIENT_LANDSCAPE)
|
|
*p = SysAllocString(ORIENTLANDSCAPE);
|
|
else
|
|
*p = SysAllocString(ORIENTPORTRAIT);
|
|
|
|
if (!p)
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
Cleanup:
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CTemplatePrinter::put_orientation(BSTR v)
|
|
{
|
|
TEMPLATESECURITYCHECK();
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
if (!v)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
goto Cleanup;
|
|
}
|
|
|
|
if (_tcsicmp(v, ORIENTPORTRAIT) == 0)
|
|
SetOrientation(DMORIENT_PORTRAIT);
|
|
else if (_tcsicmp(v, ORIENTLANDSCAPE) == 0)
|
|
SetOrientation(DMORIENT_LANDSCAPE);
|
|
else
|
|
hr = E_INVALIDARG;
|
|
|
|
Cleanup:
|
|
return hr;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// (ITemplatePrinter) CTemplatePrinter::get unprintableLeft/Top/Right/Bottom
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CTemplatePrinter::get_unprintableLeft(long * p)
|
|
{
|
|
TEMPLATESECURITYCHECK();
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
if (!p)
|
|
hr = E_POINTER;
|
|
else if (_szResolution.cx == 0)
|
|
*p = 0;
|
|
else
|
|
// Output should be in 1/100 inches, not printer pixels.
|
|
*p = MulDivQuick(_rcUnprintable.left, 100, _szResolution.cx);
|
|
|
|
return hr;
|
|
}
|
|
STDMETHODIMP
|
|
CTemplatePrinter::get_unprintableTop(long * p)
|
|
{
|
|
TEMPLATESECURITYCHECK();
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
if (!p)
|
|
hr = E_POINTER;
|
|
else if (_szResolution.cy == 0)
|
|
*p = 0;
|
|
else
|
|
// Output should be in 1/100 inches, not printer pixels.
|
|
*p = MulDivQuick(_rcUnprintable.top, 100, _szResolution.cy);
|
|
|
|
return hr;
|
|
}
|
|
STDMETHODIMP
|
|
CTemplatePrinter::get_unprintableRight(long * p)
|
|
{
|
|
TEMPLATESECURITYCHECK();
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
if (!p)
|
|
hr = E_POINTER;
|
|
else if (_szResolution.cx == 0)
|
|
*p = 0;
|
|
else
|
|
// Output should be in 1/100 inches, not printer pixels.
|
|
*p = MulDivQuick(_rcUnprintable.right, 100, _szResolution.cx);
|
|
|
|
return hr;
|
|
}
|
|
STDMETHODIMP
|
|
CTemplatePrinter::get_unprintableBottom(long * p)
|
|
{
|
|
TEMPLATESECURITYCHECK();
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
if (!p)
|
|
hr = E_POINTER;
|
|
else if (_szResolution.cy == 0)
|
|
*p = 0;
|
|
else
|
|
// Output should be in 1/100 inches, not printer pixels.
|
|
*p = MulDivQuick(_rcUnprintable.bottom, 100, _szResolution.cy);
|
|
|
|
return hr;
|
|
}
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// (ITemplatePrinter) CTemplatePrinter::get/put header
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CTemplatePrinter::get_header(BSTR * p)
|
|
{
|
|
TEMPLATESECURITYCHECK();
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
if (!p)
|
|
hr = E_POINTER;
|
|
else
|
|
{
|
|
*p = SysAllocString(_achHeader);
|
|
if (!p)
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
STDMETHODIMP
|
|
CTemplatePrinter::put_header(BSTR v)
|
|
{
|
|
TEMPLATESECURITYCHECK();
|
|
|
|
HRESULT hr = S_OK;
|
|
TCHAR *achTemp;
|
|
|
|
achTemp = v;
|
|
if (! (_tcslen(achTemp) <= ARRAY_SIZE(_achHeader) - 1))
|
|
hr = E_INVALIDARG;
|
|
else
|
|
{
|
|
_fPersistHFToRegistry = FALSE;
|
|
_tcscpy(_achHeader, achTemp);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// (ITemplatePrinter) CTemplatePrinter::get/put footer
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CTemplatePrinter::get_footer(BSTR * p)
|
|
{
|
|
TEMPLATESECURITYCHECK();
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
if (!p)
|
|
hr = E_POINTER;
|
|
else
|
|
{
|
|
*p = SysAllocString(_achFooter);
|
|
if (!p)
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
STDMETHODIMP
|
|
CTemplatePrinter::put_footer(BSTR v)
|
|
{
|
|
TEMPLATESECURITYCHECK();
|
|
|
|
HRESULT hr = S_OK;
|
|
TCHAR *achTemp;
|
|
|
|
achTemp = v;
|
|
if (! (_tcslen(achTemp) <= ARRAY_SIZE(_achFooter) - 1))
|
|
hr = E_INVALIDARG;
|
|
else
|
|
{
|
|
_fPersistHFToRegistry = FALSE;
|
|
_tcscpy(_achFooter, achTemp);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// (ITemplatePrinter2) CTemplatePrinter::deviceSupports
|
|
//
|
|
// Takes a BSTR indicating which property to query (supported values in the
|
|
// defined above).
|
|
// Returns information about that property.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CTemplatePrinter::deviceSupports(BSTR bstrProperty, VARIANT * pvar)
|
|
{
|
|
TEMPLATESECURITYCHECK();
|
|
|
|
HRESULT hr = S_OK;
|
|
void *pDevMode = NULL;
|
|
DEVNAMES *pDevNames = NULL;
|
|
TCHAR *achDevice = NULL;
|
|
TCHAR *achPort = NULL;
|
|
int i;
|
|
|
|
if (!pvar)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
goto Cleanup;
|
|
}
|
|
|
|
VariantInit(pvar);
|
|
|
|
pDevMode = ::GlobalLock(_hDevMode);
|
|
pDevNames = ((DEVNAMES *) ::GlobalLock(_hDevNames));
|
|
if (!pDevMode || !pDevNames)
|
|
{
|
|
hr = E_FAIL;
|
|
goto Cleanup;
|
|
}
|
|
|
|
for (i = 0;
|
|
(i < DEVCAP_LAST) && (_tcsicmp(bstrProperty, s_aachDeviceCapabilities[i]) != 0);
|
|
i++);
|
|
|
|
if (i >= DEVCAP_LAST)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
goto Cleanup;
|
|
}
|
|
|
|
achDevice = ((TCHAR *)pDevNames) + (pDevNames->wDeviceOffset);
|
|
achPort = ((TCHAR *)pDevNames) + (pDevNames->wOutputOffset);
|
|
switch (i)
|
|
{
|
|
case DEVCAP_COPIES:
|
|
V_VT(pvar) = VT_INT;
|
|
V_INT(pvar) = ::DeviceCapabilities(achDevice, achPort, DC_COPIES, NULL, NULL);
|
|
break;
|
|
case DEVCAP_COLLATE:
|
|
V_VT(pvar) = VT_BOOL;
|
|
V_BOOL(pvar) = (::DeviceCapabilities(achDevice, achPort, DC_COLLATE, NULL, NULL) != 0) ? VB_TRUE : VB_FALSE;
|
|
break;
|
|
case DEVCAP_DUPLEX:
|
|
V_VT(pvar) = VT_BOOL;
|
|
V_BOOL(pvar) = (::DeviceCapabilities(achDevice, achPort, DC_DUPLEX, NULL, NULL) != 0) ? VB_TRUE : VB_FALSE;
|
|
break;
|
|
#if DBG==1
|
|
case DEVCAP_DBG_PRINTERNAME:
|
|
V_BSTR(pvar) = ::SysAllocString(achDevice);
|
|
if (V_BSTR(pvar))
|
|
V_VT(pvar) = VT_BSTR;
|
|
else
|
|
hr = E_OUTOFMEMORY;
|
|
break;
|
|
#endif
|
|
default:
|
|
Assert(FALSE && "Unrecognized DEVCAP_ value.");
|
|
break;
|
|
}
|
|
|
|
|
|
Cleanup:
|
|
if (pDevNames)
|
|
::GlobalUnlock(_hDevNames);
|
|
if (pDevMode)
|
|
::GlobalUnlock(_hDevMode);
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CTemplatePrinter::updatePageStatus(long * p)
|
|
{
|
|
TEMPLATESECURITYCHECK();
|
|
|
|
VARIANT varHost;
|
|
HRESULT hr = S_OK;
|
|
IOleCommandTarget *pioct = NULL;
|
|
const GUID *pguid = NULL;
|
|
DWORD nCmdId = 0;
|
|
|
|
VariantInit(&varHost);
|
|
|
|
if (!p)
|
|
{
|
|
hr = E_POINTER;
|
|
goto Cleanup;
|
|
}
|
|
|
|
if ( GetDialogArgument(&varHost, PRINTARG_BROWSEDOC) == S_OK
|
|
&& V_VT(&varHost) == VT_UNKNOWN
|
|
&& V_UNKNOWN(&varHost) )
|
|
{
|
|
VARIANT varIn;
|
|
V_VT(&varIn) = VT_I4;
|
|
V_I4(&varIn) = (*p > 0) ? (*p) : 0;
|
|
|
|
hr = V_UNKNOWN(&varHost)->QueryInterface(IID_IOleCommandTarget, (void **)&pioct);
|
|
if (hr)
|
|
goto Cleanup;
|
|
Assert(pioct);
|
|
|
|
hr = pioct->Exec(&CGID_MSHTML, IDM_UPDATEPAGESTATUS, 0, &varIn, 0);
|
|
|
|
hr = S_OK; // If the host isn't listening, we'll get an OLE error. Don't throw it to script!
|
|
}
|
|
|
|
Cleanup:
|
|
ReleaseInterface(pioct);
|
|
VariantClear(&varHost);
|
|
return hr;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// (ITemplatePrinter) CTemplatePrinter::printNonNative
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CTemplatePrinter::printNonNative(IUnknown* pDoc, VARIANT_BOOL *p)
|
|
{
|
|
TEMPLATESECURITYCHECK();
|
|
|
|
HRESULT hr = S_OK;
|
|
IOleCommandTarget *pioct = NULL;
|
|
IPrint *pIPrint = NULL;
|
|
VARIANT varOut;
|
|
VARIANT varIn;
|
|
|
|
VariantInit(&varOut);
|
|
|
|
if (!pDoc || !p)
|
|
{
|
|
hr = E_POINTER;
|
|
goto Cleanup;
|
|
}
|
|
|
|
*p = VB_FALSE;
|
|
|
|
hr = pDoc->QueryInterface(IID_IOleCommandTarget, (void **)&pioct);
|
|
if (hr)
|
|
goto Cleanup;
|
|
Assert(pioct);
|
|
|
|
V_VT(&varIn) = VT_I4;
|
|
V_I4(&varIn) = IPRINT_DOCUMENT;
|
|
hr = pioct->Exec( &CGID_MSHTML,
|
|
IDM_GETIPRINT,
|
|
NULL,
|
|
&varIn,
|
|
&varOut);
|
|
|
|
if ( hr
|
|
|| V_VT(&varOut) != VT_UNKNOWN
|
|
|| !V_UNKNOWN(&varOut))
|
|
goto Cleanup;
|
|
|
|
// We don't get back an IPrint collection unless it has at least one member.
|
|
// At this point, we can claim that we should be printing, and a template does not need to.
|
|
*p = VB_TRUE;
|
|
|
|
hr = PrintIPrintCollection(&varOut);
|
|
|
|
Cleanup:
|
|
VariantClear(&varOut);
|
|
ReleaseInterface(pioct);
|
|
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CTemplatePrinter::printNonNativeFrames(IUnknown *pMarkup, VARIANT_BOOL fActiveFrame)
|
|
{
|
|
TEMPLATESECURITYCHECK();
|
|
|
|
HRESULT hr = S_OK;
|
|
IOleCommandTarget *pioct = NULL;
|
|
VARIANT varOut;
|
|
VARIANT varIn;
|
|
VARIANT varBrowseDoc;
|
|
|
|
if (!pMarkup)
|
|
{
|
|
hr = E_POINTER;
|
|
goto Cleanup;
|
|
}
|
|
|
|
VariantInit(&varOut);
|
|
VariantInit(&varIn);
|
|
VariantInit(&varBrowseDoc);
|
|
|
|
// Use the browse document if one exists - it will have the WebOC frame.
|
|
// NB (greglett)
|
|
// This assumes that the reference we are passed to the browse doc
|
|
// stays good - including nested frames &c... on the browse doc while the WebOC is still
|
|
// loaded & (if it was selected) active.
|
|
// Yes, this may exhibit unexpected behavior if the user Prints and navigates away.
|
|
// A better solution would be appreciated.
|
|
if ( GetDialogArgument(&varBrowseDoc, PRINTARG_BROWSEDOC) == S_OK
|
|
&& V_VT(&varBrowseDoc) == VT_UNKNOWN
|
|
&& V_UNKNOWN(&varBrowseDoc) )
|
|
{
|
|
hr = V_UNKNOWN(&varBrowseDoc)->QueryInterface(IID_IOleCommandTarget, (void **)&pioct);
|
|
}
|
|
|
|
// Otherwise, use the content document
|
|
if (!pioct)
|
|
{
|
|
hr = pMarkup->QueryInterface(IID_IOleCommandTarget, (void **)&pioct);
|
|
if (hr)
|
|
goto Cleanup;
|
|
}
|
|
|
|
Assert(pioct);
|
|
|
|
V_VT(&varIn) = VT_I4;
|
|
V_I4(&varIn) = fActiveFrame ? IPRINT_ACTIVEFRAME : IPRINT_ALLFRAMES;
|
|
hr = pioct->Exec( &CGID_MSHTML,
|
|
IDM_GETIPRINT,
|
|
NULL,
|
|
&varIn,
|
|
&varOut);
|
|
|
|
if ( hr
|
|
|| V_VT(&varOut) != VT_UNKNOWN
|
|
|| !V_UNKNOWN(&varOut))
|
|
goto Cleanup;
|
|
|
|
hr = PrintIPrintCollection(&varOut);
|
|
|
|
Cleanup:
|
|
VariantClear(&varOut);
|
|
VariantClear(&varBrowseDoc);
|
|
ReleaseInterface(pioct);
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
CTemplatePrinter::PrintIPrintCollection(VARIANT * pvarIPrintAry)
|
|
{
|
|
TEMPLATESECURITYCHECK();
|
|
|
|
HRESULT hr = S_OK;
|
|
IDispatch * pIPrintAry = NULL;
|
|
IPrint * pIPrint = NULL;
|
|
VARIANT varInvokeOut;
|
|
VARIANT varInvokeParam;
|
|
DISPPARAMS DispParams;
|
|
DVTARGETDEVICE * pTargetDevice = NULL;
|
|
PAGESET * pPageSet = NULL;
|
|
long cIPrint, i;
|
|
long lFirstPage, lPages, lLastPage;
|
|
|
|
Assert(V_VT(pvarIPrintAry) == VT_UNKNOWN);
|
|
Assert(V_UNKNOWN(pvarIPrintAry));
|
|
|
|
VariantInit(&varInvokeOut);
|
|
VariantInit(&varInvokeParam);
|
|
|
|
hr = V_UNKNOWN(pvarIPrintAry)->QueryInterface(IID_IDispatch, (void **)&pIPrintAry);
|
|
if (hr)
|
|
goto Cleanup;
|
|
Assert(pIPrintAry);
|
|
|
|
DispParams.cNamedArgs = 0;
|
|
DispParams.rgdispidNamedArgs = NULL;
|
|
DispParams.cArgs = 0;
|
|
DispParams.rgvarg = NULL;
|
|
hr = pIPrintAry->Invoke(DISPID_IHTMLIPRINTCOLLECTION_LENGTH,
|
|
IID_NULL,
|
|
LOCALE_USER_DEFAULT,
|
|
DISPATCH_PROPERTYGET,
|
|
&DispParams,
|
|
&varInvokeOut,
|
|
NULL, NULL);
|
|
if ( hr
|
|
|| V_VT(&varInvokeOut) != VT_I4
|
|
|| V_I4(&varInvokeOut) <= 0 )
|
|
goto Cleanup;
|
|
|
|
cIPrint = V_I4(&varInvokeOut);
|
|
VariantClear(&varInvokeOut);
|
|
|
|
hr = CreateIPrintParams(&pTargetDevice, &pPageSet);
|
|
if (hr)
|
|
goto Cleanup;
|
|
|
|
lFirstPage = pPageSet->rgPages[0].nFromPage;
|
|
lLastPage = pPageSet->rgPages[0].nToPage;
|
|
|
|
DispParams.cArgs = 1;
|
|
DispParams.rgvarg = &varInvokeParam;
|
|
V_VT(&varInvokeParam) = VT_I4;
|
|
for (i = 0; i < cIPrint; i++)
|
|
{
|
|
V_I4(&varInvokeParam) = i;
|
|
hr = pIPrintAry->Invoke(DISPID_IHTMLIPRINTCOLLECTION_ITEM,
|
|
IID_NULL,
|
|
LOCALE_USER_DEFAULT,
|
|
DISPATCH_METHOD,
|
|
&DispParams,
|
|
&varInvokeOut,
|
|
NULL, NULL);
|
|
if ( hr
|
|
|| V_VT(&varInvokeOut) != VT_UNKNOWN
|
|
|| !V_UNKNOWN(&varInvokeOut))
|
|
{
|
|
VariantClear(&varInvokeOut);
|
|
continue;
|
|
}
|
|
|
|
hr = V_UNKNOWN(&varInvokeOut)->QueryInterface(IID_IPrint, (void **)&pIPrint);
|
|
VariantClear(&varInvokeOut);
|
|
if (hr)
|
|
continue;
|
|
Assert(pIPrint);
|
|
|
|
hr = pIPrint->Print(
|
|
PRINTFLAG_MAYBOTHERUSER,
|
|
&pTargetDevice,
|
|
&pPageSet,
|
|
NULL,
|
|
NULL,
|
|
lFirstPage,
|
|
&lPages, // out
|
|
&lLastPage // out
|
|
);
|
|
|
|
ReleaseInterface(pIPrint);
|
|
pIPrint = NULL;
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
Cleanup:
|
|
if (pTargetDevice)
|
|
::CoTaskMemFree(pTargetDevice);
|
|
if (pPageSet)
|
|
::CoTaskMemFree(pPageSet);
|
|
|
|
ReleaseInterface(pIPrintAry);
|
|
return hr;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// (ITemplatePrinter) CTemplatePrinter::showPrintDialog, ensurePrintDialogDefaults
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CTemplatePrinter::ensurePrintDialogDefaults(VARIANT_BOOL *p)
|
|
{
|
|
TEMPLATESECURITYCHECK();
|
|
|
|
if (!p)
|
|
return E_POINTER;
|
|
|
|
// If we already have default printer information, use it.
|
|
if (_hDevNames && _hDevMode)
|
|
*p = VB_TRUE;
|
|
|
|
// Otherwise, go get it.
|
|
else
|
|
GetPrintDialogSettings(FALSE, p);
|
|
|
|
return S_OK;
|
|
}
|
|
STDMETHODIMP
|
|
CTemplatePrinter::showPrintDialog(VARIANT_BOOL *p)
|
|
{
|
|
TEMPLATESECURITYCHECK();
|
|
|
|
if (!p)
|
|
return E_POINTER;
|
|
|
|
GetPrintDialogSettings(TRUE, p);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// (ITemplatePrinter) CTemplatePrinter::showPageSetupDialog
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CTemplatePrinter::showPageSetupDialog(VARIANT_BOOL *p)
|
|
{
|
|
TEMPLATESECURITYCHECK();
|
|
|
|
HRESULT hr;
|
|
HWND hWnd;
|
|
BOOL fMetricUnits = FALSE;
|
|
IHTMLEventObj2 *pEvent = NULL; // To populate with dialog parameters
|
|
IDocHostUIHandler *pUIHandler = NULL;
|
|
IOleCommandTarget *pUICommandHandler = NULL;
|
|
HGLOBAL hPageSetup = NULL;
|
|
PAGESETUPDLG * ppagesetupdlg = NULL;
|
|
VARIANT varIn;
|
|
|
|
if (!p)
|
|
{
|
|
hr = E_POINTER;
|
|
goto Cleanup;
|
|
}
|
|
*p = VB_FALSE;
|
|
|
|
if (_hDC)
|
|
{
|
|
hr = E_FAIL;
|
|
goto Cleanup;
|
|
}
|
|
|
|
hPageSetup = ::GlobalAlloc(GHND, sizeof(PAGESETUPDLG));
|
|
if (!hPageSetup)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto Cleanup;
|
|
}
|
|
|
|
ppagesetupdlg = (PAGESETUPDLG *)::GlobalLock(hPageSetup);
|
|
if (!ppagesetupdlg)
|
|
{
|
|
hr = E_FAIL;
|
|
goto Cleanup;
|
|
}
|
|
|
|
hr = InitDialog(&hWnd, &pEvent, &pUICommandHandler);
|
|
if (hr)
|
|
goto Cleanup;
|
|
|
|
{
|
|
// Are we using metric or British (US) for margins?
|
|
TCHAR achLocale[32];
|
|
int iLocale = 32;
|
|
fMetricUnits = ( GetLocaleInfo(LOCALE_SYSTEM_DEFAULT, LOCALE_IMEASURE, achLocale, iLocale)
|
|
&& achLocale[0] == TCHAR('0'));
|
|
}
|
|
|
|
// Now, initialize the event's type and expandos.
|
|
{
|
|
BSTR bstrTemp = SysAllocString( L"pagesetup" );
|
|
VARIANT var;
|
|
|
|
if (bstrTemp)
|
|
{
|
|
pEvent->put_type( bstrTemp );
|
|
SysFreeString(bstrTemp);
|
|
}
|
|
|
|
V_VT(&var) = VT_PTR;
|
|
V_BYREF(&var) = ppagesetupdlg;
|
|
hr = pEvent->setAttribute(_T("pagesetupStruct"), var, 0);
|
|
if (hr)
|
|
goto Cleanup;
|
|
|
|
V_VT(&var) = VT_BSTR;
|
|
bstrTemp = SysAllocString(_achHeader);
|
|
if (bstrTemp)
|
|
{
|
|
V_BSTR(&var) = bstrTemp;
|
|
hr = pEvent->setAttribute(_T("pagesetupHeader"), var, 0);
|
|
SysFreeString(bstrTemp);
|
|
}
|
|
|
|
bstrTemp = SysAllocString(_achFooter);
|
|
if (bstrTemp)
|
|
{
|
|
V_BSTR(&var) = bstrTemp;
|
|
hr = pEvent->setAttribute(_T("pagesetupFooter"), var, 0);
|
|
SysFreeString(bstrTemp);
|
|
}
|
|
}
|
|
|
|
// Fill out PAGESETUPDLG structure
|
|
::ZeroMemory(ppagesetupdlg, sizeof(PAGESETUPDLG));
|
|
ppagesetupdlg->lStructSize = sizeof(PAGESETUPDLG);
|
|
ppagesetupdlg->hwndOwner = hWnd;
|
|
ppagesetupdlg->hDevMode = _hDevMode;
|
|
ppagesetupdlg->hDevNames = _hDevNames;
|
|
ppagesetupdlg->Flags |= PSD_DEFAULTMINMARGINS;
|
|
|
|
if (_ptPaperSize.x != -1)
|
|
{
|
|
ppagesetupdlg->ptPaperSize = _ptPaperSize;
|
|
}
|
|
if (_rcMargin.left != -1)
|
|
{
|
|
ppagesetupdlg->Flags |= PSD_MARGINS;
|
|
ppagesetupdlg->rtMargin = _rcMargin;
|
|
|
|
if (fMetricUnits)
|
|
{
|
|
// Margins from PrintInfoBag are in 1/100000" and need to be converted to 1/100 mm.
|
|
ppagesetupdlg->rtMargin.left = MulDivQuick(ppagesetupdlg->rtMargin.left , 2540, 100000);
|
|
ppagesetupdlg->rtMargin.right = MulDivQuick(ppagesetupdlg->rtMargin.right , 2540, 100000);
|
|
ppagesetupdlg->rtMargin.top = MulDivQuick(ppagesetupdlg->rtMargin.top , 2540, 100000);
|
|
ppagesetupdlg->rtMargin.bottom = MulDivQuick(ppagesetupdlg->rtMargin.bottom, 2540, 100000);
|
|
}
|
|
else
|
|
{
|
|
// Margins from PrintInfoBag are in 1/100000" and need to be converted to 1/1000".
|
|
ppagesetupdlg->rtMargin.left = ppagesetupdlg->rtMargin.left / 100;
|
|
ppagesetupdlg->rtMargin.right = ppagesetupdlg->rtMargin.right / 100;
|
|
ppagesetupdlg->rtMargin.top = ppagesetupdlg->rtMargin.top / 100;
|
|
ppagesetupdlg->rtMargin.bottom = ppagesetupdlg->rtMargin.bottom / 100;
|
|
}
|
|
}
|
|
|
|
CommCtrlNativeFontSupport();
|
|
|
|
V_VT(&varIn) = VT_UNKNOWN;
|
|
V_UNKNOWN(&varIn) = pEvent;
|
|
|
|
// Query host to show dialog
|
|
if (pUICommandHandler)
|
|
{
|
|
// We may be marshalling this call across threads. RPC doesn't allow VT_PTRs to cross threads.
|
|
// We work around this by sticking the structure into a GHND contents and pass the VT_HANDLE.
|
|
// We then delegate to the browse document, who will obtain a copy of the GHND pointer and use that for the VT_PTR
|
|
// the struct. (CDoc::DelegateShowPrintingDialog)
|
|
//
|
|
// In theory, we could detect this by looking at the __IE_uPrintFlags to see if it is flagged synchronous to avoid playing with handles.
|
|
// The downside: as with all dialogArguments, anyone could have mucked around with the flags)
|
|
VARIANT var;
|
|
V_VT(&var) = VT_HANDLE;
|
|
V_BYREF(&var) = hPageSetup;
|
|
pEvent->setAttribute(_T("hPageSetup"), var, 0);
|
|
|
|
// Delegate call to browse Trident
|
|
hr = pUICommandHandler->Exec(
|
|
NULL, // For Trident
|
|
OLECMDID_SHOWPAGESETUP,
|
|
0,
|
|
&varIn,
|
|
NULL);
|
|
|
|
pEvent->removeAttribute(_T("hPageSetup"), 0, NULL);
|
|
}
|
|
|
|
if ( !pUICommandHandler
|
|
|| hr == OLECMDERR_E_NOTSUPPORTED
|
|
|| hr == OLECMDERR_E_UNKNOWNGROUP
|
|
|| hr == E_FAIL
|
|
|| hr == E_NOTIMPL )
|
|
{
|
|
ClearInterface(&pUICommandHandler);
|
|
|
|
// Create backup UI Handler
|
|
// (greglett) Cache this - CoCreate is expensive.
|
|
hr = CoCreateInstance(CLSID_DocHostUIHandler,
|
|
NULL,
|
|
CLSCTX_INPROC_SERVER,
|
|
IID_IDocHostUIHandler,
|
|
(void**)&pUIHandler);
|
|
if (!pUIHandler)
|
|
goto Cleanup;
|
|
|
|
hr = pUIHandler->QueryInterface(IID_IOleCommandTarget,(void**)&pUICommandHandler);
|
|
if (!pUICommandHandler)
|
|
goto Cleanup;
|
|
|
|
hr = pUICommandHandler->Exec(
|
|
&CGID_DocHostCommandHandler, // For a dochost object
|
|
OLECMDID_SHOWPAGESETUP,
|
|
0,
|
|
&varIn,
|
|
NULL);
|
|
}
|
|
|
|
// If the dialog was cancelled, or there was a problem showing the dialog,
|
|
|
|
// do not update values.
|
|
if (hr)
|
|
goto Cleanup;
|
|
|
|
*p = VB_TRUE; // OK was pressed.
|
|
|
|
//
|
|
// Retrieve page setup changes from the page setup dialog structure.
|
|
//
|
|
_hDevMode = ppagesetupdlg->hDevMode;
|
|
_hDevNames = ppagesetupdlg->hDevNames;
|
|
GetDeviceProperties();
|
|
|
|
if (fMetricUnits)
|
|
{
|
|
// Margins from Page Setup dialog are in 1/100 mm and need to be converted to 1/100000"
|
|
_rcMargin.left = MulDivQuick(ppagesetupdlg->rtMargin.left , 100000, 2540);
|
|
_rcMargin.right = MulDivQuick(ppagesetupdlg->rtMargin.right , 100000, 2540);
|
|
_rcMargin.top = MulDivQuick(ppagesetupdlg->rtMargin.top , 100000, 2540);
|
|
_rcMargin.bottom = MulDivQuick(ppagesetupdlg->rtMargin.bottom, 100000, 2540);
|
|
}
|
|
else
|
|
{
|
|
// Margins from Page Setup dialog are in 1/1000" and need to be converted to 1/100000"
|
|
_rcMargin.left = ppagesetupdlg->rtMargin.left * 100;
|
|
_rcMargin.right = ppagesetupdlg->rtMargin.right * 100;
|
|
_rcMargin.top = ppagesetupdlg->rtMargin.top * 100;
|
|
_rcMargin.bottom = ppagesetupdlg->rtMargin.bottom * 100;
|
|
}
|
|
|
|
// (greglett) 99% of OS's use PSD_DEFAULTMINMARGINS to restrict the margins to the printable page area.
|
|
// NT4SP6 without the IE shell extensions doesn't. So, we are forced to do more work for yet another violation of the API documentation.
|
|
// Force margins to be at least as large as the unprintable region.
|
|
// Do we want also to display an error message if they are different? (Otherwise, we change it, and the user doesn't see it.)
|
|
if (_rcMargin.left < MulDivQuick(_rcUnprintable.left, 100000, _szResolution.cx))
|
|
_rcMargin.left = MulDivQuick(_rcUnprintable.left, 100000, _szResolution.cx);
|
|
if (_rcMargin.right < MulDivQuick(_rcUnprintable.right, 100000, _szResolution.cx))
|
|
_rcMargin.right = MulDivQuick(_rcUnprintable.right, 100000, _szResolution.cx);
|
|
if (_rcMargin.top < MulDivQuick(_rcUnprintable.top, 100000, _szResolution.cy))
|
|
_rcMargin.top = MulDivQuick(_rcUnprintable.top, 100000, _szResolution.cy);
|
|
if (_rcMargin.bottom < MulDivQuick(_rcUnprintable.bottom, 100000, _szResolution.cy))
|
|
_rcMargin.bottom = MulDivQuick(_rcUnprintable.bottom, 100000, _szResolution.cy);
|
|
|
|
//
|
|
// Read in Trident specific values from the page setup dialog
|
|
//
|
|
{
|
|
VARIANT var;
|
|
TCHAR *pchTemp;
|
|
|
|
if ( !pEvent->getAttribute(_T("pagesetupHeader"),0,&var)
|
|
&& var.vt == VT_BSTR
|
|
&& var.bstrVal)
|
|
{
|
|
pchTemp = var.bstrVal;
|
|
_tcscpy(_achHeader, pchTemp);
|
|
SysFreeString(var.bstrVal);
|
|
}
|
|
else
|
|
_achHeader[0] = _T('\0');
|
|
|
|
if ( !pEvent->getAttribute(_T("pagesetupFooter"),0,&var)
|
|
&& var.vt == VT_BSTR
|
|
&& var.bstrVal)
|
|
|
|
{
|
|
pchTemp = var.bstrVal;
|
|
_tcscpy(_achFooter, pchTemp);
|
|
SysFreeString(var.bstrVal);
|
|
}
|
|
else
|
|
_achFooter[0] = _T('\0');
|
|
}
|
|
|
|
//
|
|
// Persist results of the page setup dialog out to the registry.
|
|
//
|
|
{
|
|
HKEY keyPageSetup = NULL;
|
|
if (GetRegPrintOptionsKey(PRINTOPTSUBKEY_PAGESETUP,&keyPageSetup) == ERROR_SUCCESS)
|
|
{
|
|
if (_fPersistHFToRegistry)
|
|
{
|
|
WriteHeaderFooterToRegistry(keyPageSetup);
|
|
}
|
|
WriteMarginsToRegistry(keyPageSetup);
|
|
RegCloseKey(keyPageSetup);
|
|
}
|
|
}
|
|
|
|
Cleanup:
|
|
ReleaseInterface(pEvent);
|
|
ReleaseInterface(pUIHandler);
|
|
ReleaseInterface(pUICommandHandler);
|
|
if (hPageSetup)
|
|
{
|
|
if (ppagesetupdlg)
|
|
::GlobalUnlock(hPageSetup);
|
|
::GlobalFree(hPageSetup);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member : CTemplatePrinter::GetPrintDialogSettings
|
|
//
|
|
// Synopsis : 'Finishes' the doc - takes pages printed via printPage and queues the job
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT
|
|
CTemplatePrinter::GetPrintDialogSettings(BOOL fBotherUser, VARIANT_BOOL *pvarfOKOrCancel)
|
|
{
|
|
HRESULT hr;
|
|
HWND hWnd = NULL;
|
|
IHTMLEventObj2 *pEvent = NULL; // To populate with dialog parameters
|
|
IDocHostUIHandler *pUIHandler = NULL;
|
|
IOleCommandTarget *pUICommandHandler = NULL;
|
|
HGLOBAL hPrint = NULL;
|
|
PRINTDLG * pprintdlg = NULL;
|
|
VARIANT varIn;
|
|
int nFontSize;
|
|
void *pDevMode = NULL;
|
|
|
|
if (pvarfOKOrCancel)
|
|
*pvarfOKOrCancel = VB_FALSE;
|
|
|
|
hPrint = ::GlobalAlloc(GHND, sizeof(PRINTDLG));
|
|
if (!hPrint)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto Cleanup;
|
|
}
|
|
|
|
pprintdlg = (PRINTDLG *)::GlobalLock(hPrint);
|
|
if (!pprintdlg)
|
|
{
|
|
hr = E_FAIL;
|
|
goto Cleanup;
|
|
}
|
|
|
|
if (_hDC)
|
|
{
|
|
hr = E_FAIL;
|
|
goto Cleanup;
|
|
}
|
|
|
|
hr = InitDialog(&hWnd, &pEvent, &pUICommandHandler, &nFontSize);
|
|
if (hr)
|
|
goto Cleanup;
|
|
|
|
// PrintDlgEx (only available NT5+) fails with a NULL HWND.
|
|
// It is likely that the DHUI that raises the dialog will use PrintDlgEx (our default DHUI in shdocvw does).
|
|
if ( g_dwPlatformID == VER_PLATFORM_WIN32_NT
|
|
&& hWnd == NULL )
|
|
hWnd = GetDesktopWindow();
|
|
|
|
// PrintDlgEx (only available NT5+) fails with a NULL HWND.
|
|
// It is likely that the DHUI that raises the dialog will use PrintDlgEx (our default DHUI in shdocvw does).
|
|
if ( g_dwPlatformID == VER_PLATFORM_WIN32_NT
|
|
&& hWnd == NULL )
|
|
hWnd = GetDesktopWindow();
|
|
|
|
// Now, initialize the event's type and expandos.
|
|
{
|
|
BSTR bstrTemp = SysAllocString( L"print" );
|
|
VARIANT var;
|
|
|
|
if (bstrTemp)
|
|
{
|
|
pEvent->put_type(bstrTemp);
|
|
SysFreeString(bstrTemp);
|
|
}
|
|
|
|
V_VT(&var) = VT_BOOL;
|
|
V_BOOL(&var) = AreRatingsEnabled() ? VB_TRUE : VB_FALSE;
|
|
hr = pEvent->setAttribute(_T("printfAreRatingsEnabled"), var, 0);
|
|
if (hr)
|
|
goto Cleanup;
|
|
|
|
V_BOOL(&var) = _fFramesetDocument ? VB_TRUE : VB_FALSE;
|
|
hr = pEvent->setAttribute(_T("printfRootDocumentHasFrameset"), var, 0);
|
|
if (hr)
|
|
goto Cleanup;
|
|
|
|
V_BOOL(&var) = _fFrameActive ? VB_TRUE : VB_FALSE;
|
|
hr = pEvent->setAttribute(_T("printfActiveFrame"), var, 0);
|
|
if (hr)
|
|
goto Cleanup;
|
|
|
|
V_BOOL(&var) = _fFrameActiveEnabled ? VB_TRUE : VB_FALSE;
|
|
hr = pEvent->setAttribute(_T("printfActiveFrameEnabled"), var, 0);
|
|
if (hr)
|
|
goto Cleanup;
|
|
|
|
V_BOOL(&var) = _fFrameAsShown ? VB_TRUE : VB_FALSE;
|
|
hr = pEvent->setAttribute(_T("printfAsShown"), var, 0);
|
|
if (hr)
|
|
goto Cleanup;
|
|
|
|
V_BOOL(&var) = _fPrintAllLinkedDocuments ? VB_TRUE : VB_FALSE;
|
|
hr = pEvent->setAttribute(_T("printfLinked"), var, 0);
|
|
if (hr)
|
|
goto Cleanup;
|
|
|
|
V_BOOL(&var) = _fPrintSelectionEnabled ? VB_TRUE : VB_FALSE;
|
|
hr = pEvent->setAttribute(_T("printfSelection"), var, 0);
|
|
if (hr)
|
|
goto Cleanup;
|
|
|
|
V_BOOL(&var) = _fPrintTableOfLinks ? VB_TRUE : VB_FALSE;
|
|
hr = pEvent->setAttribute(_T("printfShortcutTable"), var, 0);
|
|
if (hr)
|
|
goto Cleanup;
|
|
|
|
V_BOOL(&var) = VB_FALSE;
|
|
hr = pEvent->setAttribute(_T("printToFileOk"),var, 0);
|
|
if (hr)
|
|
goto Cleanup;
|
|
|
|
V_VT(&var) = VT_INT;
|
|
V_INT(&var) = nFontSize;
|
|
hr = pEvent->setAttribute(_T("printiFontScaling"), var, 0);
|
|
if (hr)
|
|
goto Cleanup;
|
|
|
|
V_VT(&var) = VT_PTR;
|
|
V_BYREF(&var) = pprintdlg;
|
|
hr = pEvent->setAttribute(_T("printStruct"), var, 0);
|
|
if (hr)
|
|
goto Cleanup;
|
|
|
|
V_VT(&var) = VT_UNKNOWN;
|
|
V_UNKNOWN(&var) = NULL;
|
|
hr = pEvent->setAttribute(_T("printpBodyActiveTarget"), var, 0);
|
|
if (hr)
|
|
goto Cleanup;
|
|
|
|
V_VT(&var) = VT_BSTR;
|
|
bstrTemp = SysAllocString(_achFileName);
|
|
if (bstrTemp)
|
|
{
|
|
V_BSTR(&var) = bstrTemp;
|
|
hr = pEvent->setAttribute(_T("printToFileName"), var, 0);
|
|
SysFreeString(bstrTemp);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Initialize the PRINTDLG structure
|
|
//
|
|
::ZeroMemory(pprintdlg, sizeof(PRINTDLG));
|
|
pprintdlg->lStructSize = sizeof(PRINTDLG);
|
|
pprintdlg->hwndOwner = hWnd;
|
|
pprintdlg->hDevMode = _hDevMode;
|
|
pprintdlg->hDevNames = _hDevNames;
|
|
pprintdlg->nCopies = _nCopies;
|
|
pprintdlg->nFromPage = _nPageFrom;
|
|
pprintdlg->nToPage = _nPageTo;
|
|
pprintdlg->nMinPage = 1;
|
|
pprintdlg->nMaxPage = 0xffff;
|
|
pprintdlg->Flags |= (_fPrintSelectionEnabled ? 0 : PD_NOSELECTION);
|
|
pprintdlg->Flags |= (_fCollate ? PD_COLLATE : 0);
|
|
pprintdlg->Flags |= (_fPrintSelectedPages ? PD_PAGENUMS : 0);
|
|
pprintdlg->Flags |= (_fPrintToFile ? PD_PRINTTOFILE : 0);
|
|
pprintdlg->Flags |= (_fCurrentPageAvail ? (_fPrintCurrentPage ? PD_CURRENTPAGE : 0) : PD_NOCURRENTPAGE);
|
|
|
|
if (!fBotherUser)
|
|
{
|
|
// this indicates we only want to retrieve the defaults,
|
|
// not to bring up the dialog
|
|
pprintdlg->hDevMode = NULL;
|
|
pprintdlg->hDevNames = NULL;
|
|
pprintdlg->Flags |= PD_RETURNDEFAULT;
|
|
}
|
|
|
|
CommCtrlNativeFontSupport();
|
|
V_VT(&varIn) = VT_UNKNOWN;
|
|
V_UNKNOWN(&varIn) = pEvent;
|
|
|
|
// Query host to show dialog
|
|
hr = E_FAIL;
|
|
if ( pvarfOKOrCancel // Don't delegate on the ::Init call. Only delegate script calls.
|
|
&& pUICommandHandler)
|
|
{
|
|
// We may be marshalling this call across threads. RPC doesn't allow VT_PTRs to cross threads.
|
|
// We work around this by sticking the structure into a GHND contents and pass the VT_HANDLE.
|
|
// We then delegate to the browse document, who will obtain a copy of the GHND pointer and use that for the VT_PTR
|
|
// the struct. (CDoc::DelegateShowPrintingDialog)
|
|
//
|
|
// In theory, we could detect this by looking at the __IE_uPrintFlags to see if it is flagged synchronous to avoid playing with handles.
|
|
// The downside: as with all dialogArguments, anyone could have mucked around with the flags)
|
|
VARIANT var;
|
|
V_VT(&var) = VT_HANDLE;
|
|
V_BYREF(&var) = hPrint;
|
|
pEvent->setAttribute(_T("hPrint"), var, 0);
|
|
|
|
// Delegate call to browse Trident
|
|
hr = pUICommandHandler->Exec(
|
|
NULL, // For Trident
|
|
OLECMDID_SHOWPRINT,
|
|
0,
|
|
&varIn,
|
|
NULL);
|
|
|
|
pEvent->removeAttribute(_T("hPrint"), 0, NULL);
|
|
}
|
|
|
|
if ( hr == OLECMDERR_E_NOTSUPPORTED
|
|
|| hr == OLECMDERR_E_UNKNOWNGROUP
|
|
|| hr == E_FAIL
|
|
|| hr == E_NOTIMPL )
|
|
{
|
|
ClearInterface(&pUICommandHandler);
|
|
|
|
// Create backup UI Handler
|
|
// (greglett) Cache this - CoCreate is expensive.
|
|
hr = CoCreateInstance(CLSID_DocHostUIHandler,
|
|
NULL,
|
|
CLSCTX_INPROC_SERVER,
|
|
IID_IDocHostUIHandler,
|
|
(void**)&pUIHandler);
|
|
if (!pUIHandler)
|
|
goto Cleanup;
|
|
|
|
hr = pUIHandler->QueryInterface(IID_IOleCommandTarget,(void**)&pUICommandHandler);
|
|
if (!pUICommandHandler)
|
|
goto Cleanup;
|
|
|
|
hr = pUICommandHandler->Exec(
|
|
&CGID_DocHostCommandHandler,
|
|
OLECMDID_SHOWPRINT,
|
|
0,
|
|
&varIn,
|
|
NULL);
|
|
|
|
}
|
|
|
|
|
|
// If the dialog was cancelled, or there was a problem showing the dialog,
|
|
// do not update values.
|
|
if (FAILED(hr))
|
|
goto Cleanup;
|
|
|
|
// this can be false because either init failed for no installed printer
|
|
// or the user clicked cancel.
|
|
if (hr==S_FALSE)
|
|
{
|
|
// Three cases:
|
|
// fBotherUser *pvarfOkOrCancel
|
|
// 1 1 fBotherUser && varfOkOrCancel - We are being called from script. We tried to raise a dialog, and
|
|
// failed or were cancelled - UI has been displayed in the former case.
|
|
// 0 1 We are being called from script. We tried to get default printer info
|
|
// and failed - this is probably because no default it set. As we used
|
|
// to, we need to raise the dialog (despite the fBotherUser) to get enough info.
|
|
// 0 0 We are being called from the init, with no default printer. We will continue
|
|
// through the procedure to get defaults.
|
|
// 1 0 Never occurs.
|
|
Assert(!(!pvarfOKOrCancel && fBotherUser));
|
|
if (fBotherUser)
|
|
{
|
|
hr = S_OK;
|
|
goto Cleanup;
|
|
}
|
|
else if (pvarfOKOrCancel)
|
|
{
|
|
hr = GetPrintDialogSettings(TRUE, pvarfOKOrCancel);
|
|
goto Cleanup;
|
|
}
|
|
// Otherwise, we need to set the default values.
|
|
else
|
|
hr = S_OK;
|
|
}
|
|
else if (pvarfOKOrCancel)
|
|
*pvarfOKOrCancel = VB_TRUE; // OK was pressed.
|
|
|
|
//
|
|
// Take base print dialog return values and store them.
|
|
//
|
|
_hDevMode = pprintdlg->hDevMode;
|
|
_hDevNames = pprintdlg->hDevNames;
|
|
_nCopies = (fBotherUser) ? pprintdlg->nCopies : 1; // bug in printDLG
|
|
_nPageFrom = pprintdlg->nFromPage;
|
|
_nPageTo = pprintdlg->nToPage;
|
|
_fPrintSelectedPages = (!!(pprintdlg->Flags & PD_PAGENUMS));
|
|
_fPrintSelection = (!!(pprintdlg->Flags & PD_SELECTION));
|
|
_fCollate = (!!(pprintdlg->Flags & PD_COLLATE));
|
|
_fPrintToFile = (!!(pprintdlg->Flags & PD_PRINTTOFILE));
|
|
_fPrintCurrentPage = (!!(pprintdlg->Flags & PD_CURRENTPAGE));
|
|
|
|
// Collate/Copy information is in both the struct and the DEVMODE.
|
|
// The DEVMODE bits instruct the printer to do its own copy/collate information.
|
|
// This means that only one copy of the document is uploaded to the printer/server, and the printer itself does the replication/duplex work.
|
|
if (_hDevMode)
|
|
{
|
|
pDevMode = ::GlobalLock(_hDevMode);
|
|
if (pDevMode)
|
|
{
|
|
// (greglett) DEVMODE is returned A on Win9x platforms, not W. <sigh>
|
|
if (g_fUnicodePlatform)
|
|
{
|
|
if (((DEVMODEW *)pDevMode)->dmFields & DM_COLLATE)
|
|
_fCollate = (((DEVMODEW *)pDevMode)->dmCollate == DMCOLLATE_TRUE) || _fCollate;
|
|
if ( ((DEVMODEW *)pDevMode)->dmFields & DM_COPIES
|
|
&& ((DEVMODEW *)pDevMode)->dmCopies > _nCopies )
|
|
_nCopies = ((DEVMODEW *)pDevMode)->dmCopies;
|
|
}
|
|
else
|
|
{
|
|
if (((DEVMODEA *)pDevMode)->dmFields & DM_COLLATE)
|
|
_fCollate = (((DEVMODEA *)pDevMode)->dmCollate == DMCOLLATE_TRUE) || _fCollate;
|
|
if ( ((DEVMODEA *)pDevMode)->dmFields & DM_COPIES
|
|
&& ((DEVMODEA *)pDevMode)->dmCopies > _nCopies )
|
|
_nCopies = ((DEVMODEA *)pDevMode)->dmCopies;
|
|
}
|
|
::GlobalUnlock(_hDevMode);
|
|
}
|
|
}
|
|
|
|
GetDeviceProperties();
|
|
|
|
// Read in changes to the Trident specific print options.
|
|
{
|
|
VARIANT var;
|
|
// Read changed values from event object
|
|
if (!pEvent->getAttribute(_T("printfLinked"),0,&var))
|
|
{
|
|
Assert(var.vt == VT_BOOL);
|
|
_fPrintAllLinkedDocuments = var.boolVal;
|
|
}
|
|
|
|
if (!pEvent->getAttribute(_T("printfActiveFrame"), 0, &var))
|
|
{
|
|
Assert(var.vt == VT_BOOL);
|
|
_fFrameActive = var.boolVal;
|
|
}
|
|
|
|
if (!pEvent->getAttribute(_T("printfAsShown"), 0, &var))
|
|
{
|
|
Assert(var.vt == VT_BOOL);
|
|
_fFrameAsShown = var.boolVal;
|
|
}
|
|
|
|
if (!pEvent->getAttribute(_T("printfShortcutTable"), 0, &var))
|
|
{
|
|
Assert(var.vt == VT_BOOL);
|
|
_fPrintTableOfLinks = var.boolVal;
|
|
}
|
|
}
|
|
|
|
if (_fPrintToFile)
|
|
{
|
|
// assume failure, treating as canceling
|
|
VARIANT var;
|
|
hr = S_FALSE;
|
|
|
|
if ( !pEvent->getAttribute(_T("printToFileOK"), 0, &var)
|
|
&& var.boolVal)
|
|
{
|
|
if ( !pEvent->getAttribute(_T("printToFileName"), 0, &var)
|
|
&& var.vt == VT_BSTR)
|
|
{
|
|
TCHAR * pchFullPath = var.bstrVal;
|
|
_tcscpy(_achFileName, pchFullPath);
|
|
SysFreeString(var.bstrVal);
|
|
|
|
// (greglett) Code used to update Trident's default save path here. (pre 5.5)
|
|
// Not being internal, we can't do that anymore.
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
|
|
if (hr != S_OK)
|
|
*pvarfOKOrCancel = VB_FALSE;
|
|
}
|
|
|
|
Cleanup:
|
|
ReleaseInterface(pUIHandler);
|
|
ReleaseInterface(pUICommandHandler);
|
|
ReleaseInterface(pEvent);
|
|
if (hPrint)
|
|
{
|
|
if (pprintdlg)
|
|
::GlobalUnlock(hPrint);
|
|
::GlobalFree(hPrint);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member : CTemplatePrinter::InitDialog
|
|
//
|
|
// Synopsis : Does all the COM schtick to get the appropriate interfaces to show
|
|
// a dialog.
|
|
//
|
|
// Parameters: hWnd: Will try to fill with Trident's hWnd. May return as NULL with S_OK.
|
|
// ppEventObj2: Will create an IHTMLEventObj2. Must be created if S_OK is returned.
|
|
// ppUIHandler: Will return Trident's UI Handler. May return NULL with S_OK.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT
|
|
CTemplatePrinter::InitDialog(HWND *phWnd, IHTMLEventObj2 **ppEventObj2, IOleCommandTarget **ppUIHandler, int *pnFontScale)
|
|
{
|
|
HRESULT hr;
|
|
IHTMLElement *pElement = NULL;
|
|
IDispatch *pDispatch = NULL;
|
|
IHTMLDocument2 *pDoc = NULL;
|
|
IOleWindow *pDocWin = NULL;
|
|
IHTMLEventObj *pEventObj = NULL;
|
|
VARIANT varHost;
|
|
|
|
Assert(phWnd);
|
|
Assert(ppEventObj2);
|
|
Assert(ppUIHandler);
|
|
|
|
VariantInit(&varHost);
|
|
|
|
*phWnd = NULL;
|
|
*ppEventObj2 = NULL;
|
|
*ppUIHandler = NULL;
|
|
if (pnFontScale)
|
|
*pnFontScale = 2;
|
|
|
|
if (!_pPeerSiteOM)
|
|
{
|
|
hr = E_FAIL;
|
|
goto Cleanup;
|
|
}
|
|
if (!phWnd || !ppEventObj2 || !ppUIHandler)
|
|
{
|
|
hr = E_POINTER;
|
|
goto Cleanup;
|
|
}
|
|
|
|
hr = _pPeerSite->GetElement(&pElement);
|
|
if (hr)
|
|
goto Cleanup;
|
|
Assert(pElement);
|
|
|
|
hr = pElement->get_document(&pDispatch);
|
|
if (hr)
|
|
goto Cleanup;
|
|
Assert(pDispatch);
|
|
|
|
hr = pDispatch->QueryInterface(IID_IHTMLDocument2, (void**) &pDoc);
|
|
if (hr)
|
|
goto Cleanup;
|
|
|
|
hr = pDoc->QueryInterface(IID_IOleWindow, (void **)&pDocWin);
|
|
if (!hr)
|
|
{
|
|
Assert(pDocWin);
|
|
pDocWin->GetWindow(phWnd);
|
|
}
|
|
|
|
// Create an event object to pass to our host with the print information
|
|
hr = _pPeerSiteOM->CreateEventObject(&pEventObj);
|
|
if (hr)
|
|
goto Cleanup;
|
|
Assert(pEventObj);
|
|
|
|
// Now get the appropriate interface to populate the event object with parameters
|
|
// for the dialog.
|
|
hr = pEventObj->QueryInterface(IID_IHTMLEventObj2, (void**)ppEventObj2);
|
|
if (hr)
|
|
goto Cleanup;
|
|
Assert(ppEventObj2);
|
|
|
|
// Get the instance of the Trident Host UI browse document, if it exists.
|
|
// We use this to delegate to our host.
|
|
if ( GetDialogArgument(&varHost, PRINTARG_BROWSEDOC) == S_OK
|
|
&& V_VT(&varHost) == VT_UNKNOWN
|
|
&& V_UNKNOWN(&varHost) )
|
|
{
|
|
hr = V_UNKNOWN(&varHost)->QueryInterface(IID_IOleCommandTarget, (void **)ppUIHandler);
|
|
Assert(*ppUIHandler);
|
|
}
|
|
|
|
Cleanup:
|
|
ReleaseInterface(pElement);
|
|
ReleaseInterface(pDispatch);
|
|
ReleaseInterface(pDoc);
|
|
ReleaseInterface(pDocWin);
|
|
ReleaseInterface(pEventObj);
|
|
VariantClear(&varHost);
|
|
return hr;
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member : CTemplatePrinter::ReturnPrintHandles
|
|
//
|
|
// Synopsis : Show our print handles to the browse instance of Trident.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
void
|
|
CTemplatePrinter::ReturnPrintHandles()
|
|
{
|
|
HRESULT hr;
|
|
VARIANT varHost;
|
|
VARIANT varIn;
|
|
SAFEARRAYBOUND sabound;
|
|
IOleCommandTarget * pioct = NULL;
|
|
SAFEARRAY * psa = NULL;
|
|
long lArg = 0;
|
|
|
|
VariantInit(&varHost);
|
|
VariantInit(&varIn);
|
|
|
|
if (!_hDevNames || !_hDevMode)
|
|
goto Cleanup;
|
|
|
|
//
|
|
// Get handle back to the browse document to update its print handles.
|
|
//
|
|
if ( GetDialogArgument(&varHost, PRINTARG_BROWSEDOC) != S_OK
|
|
|| V_VT(&varHost) != VT_UNKNOWN
|
|
|| !V_UNKNOWN(&varHost) )
|
|
goto Cleanup;
|
|
|
|
hr = V_UNKNOWN(&varHost)->QueryInterface(IID_IOleCommandTarget, (void **)&pioct);
|
|
if (hr)
|
|
goto Cleanup;
|
|
Assert(pioct);
|
|
|
|
//
|
|
// Create a SAFEARRAY filled with our two print handles { DEVNAMES, DEVMODE }
|
|
//
|
|
sabound.cElements = 2;
|
|
sabound.lLbound = 0;
|
|
psa = SafeArrayCreate(VT_HANDLE, 1, &sabound);
|
|
if (!psa)
|
|
goto Cleanup;
|
|
|
|
//
|
|
// Bundle the array in the Exec argument...
|
|
//
|
|
V_VT(&varIn) = VT_ARRAY | VT_HANDLE;
|
|
V_ARRAY(&varIn) = psa;
|
|
|
|
if ( SafeArrayPutElement(psa, &lArg, &_hDevNames) != S_OK
|
|
|| SafeArrayPutElement(psa, &(++lArg), &_hDevMode) != S_OK )
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Actually make the call, passing our handles to the browse instance
|
|
//
|
|
pioct->Exec( &CGID_MSHTML,
|
|
IDM_SETPRINTHANDLES,
|
|
NULL,
|
|
&varIn,
|
|
NULL);
|
|
|
|
Cleanup:
|
|
VariantClear(&varIn); // Destroys SAFEARRAY.
|
|
VariantClear(&varHost);
|
|
ReleaseInterface(pioct);
|
|
return;
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member : CTemplatePrinter::GetDialogArgument
|
|
//
|
|
// Synopsis : The dialogArgument on the attached print template has several important expandos.
|
|
// This function gets the dialogArguments and caches a ptr to it.
|
|
//
|
|
// Returens: S_OK: dlgArgs saved
|
|
// E_*: Error encounterd
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT
|
|
CTemplatePrinter::GetDialogArguments()
|
|
{
|
|
HRESULT hr;
|
|
IHTMLElement *pElement = NULL;
|
|
IDispatch *pDispatch = NULL;
|
|
IServiceProvider *pIDocSrvProv = NULL;
|
|
IHTMLDialog *pIHTMLDialog = NULL;
|
|
VARIANT varDlgArgs;
|
|
|
|
Assert(_pPeerSite);
|
|
VariantInit(&varDlgArgs);
|
|
|
|
hr = _pPeerSite->GetElement(&pElement);
|
|
if (hr)
|
|
goto Cleanup;
|
|
Assert(pElement);
|
|
|
|
hr = pElement->get_document(&pDispatch);
|
|
if (hr)
|
|
goto Cleanup;
|
|
Assert(pDispatch);
|
|
|
|
hr = pDispatch->QueryInterface(IID_IServiceProvider, (void **)&pIDocSrvProv);
|
|
if (FAILED(hr))
|
|
goto Cleanup;
|
|
Assert(pIDocSrvProv);
|
|
|
|
hr = pIDocSrvProv->QueryService(IID_IHTMLDialog, IID_IHTMLDialog, (void**)&pIHTMLDialog);
|
|
if (FAILED(hr))
|
|
goto Cleanup;
|
|
Assert(pIHTMLDialog);
|
|
|
|
hr = pIHTMLDialog->get_dialogArguments(&varDlgArgs);
|
|
if (hr)
|
|
goto Cleanup;
|
|
|
|
if ( V_VT(&varDlgArgs) != VT_UNKNOWN
|
|
|| !V_UNKNOWN(&varDlgArgs) )
|
|
{
|
|
hr = E_FAIL; // Major badness. This MUST be there.
|
|
goto Cleanup;
|
|
}
|
|
|
|
hr = V_UNKNOWN(&varDlgArgs)->QueryInterface(IID_IHTMLEventObj2, (void**)&_pevDlgArgs);
|
|
if (hr)
|
|
goto Cleanup;
|
|
Assert(_pevDlgArgs);
|
|
|
|
Cleanup:
|
|
ReleaseInterface(pElement);
|
|
ReleaseInterface(pDispatch);
|
|
ReleaseInterface(pIDocSrvProv);
|
|
ReleaseInterface(pIHTMLDialog);
|
|
VariantClear(&varDlgArgs);
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member : CTemplatePrinter::GetDialogArgument
|
|
//
|
|
// Synopsis : The dialogArgument on the attached print template has several important expandos.
|
|
// Function gets the expando specified by the argument enum
|
|
//
|
|
// Returens: S_OK: expando obtained (might be VT_NULL or VT_EMPTY)
|
|
// E_*: Error encounterd
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT
|
|
CTemplatePrinter::GetDialogArgument(VARIANT *pvar, PRINTARG eArg)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
BSTR bstrTarget = NULL;
|
|
|
|
Assert(pvar);
|
|
Assert(eArg >= 0 && eArg < PRINTTYPE_LAST);
|
|
|
|
// (greglett) TODO: Implement a caching system for these args. We access some of
|
|
// often, and shouldn't do the (potentially) cross-thread OLE each time.
|
|
|
|
if (!_pevDlgArgs)
|
|
return E_FAIL;
|
|
|
|
VariantClear(pvar);
|
|
|
|
bstrTarget = SysAllocString(s_aachPrintArg[eArg]);
|
|
if (!bstrTarget)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto Cleanup;
|
|
}
|
|
|
|
hr = _pevDlgArgs->getAttribute(bstrTarget, 0, pvar);
|
|
|
|
Cleanup:
|
|
SysFreeString(bstrTarget);
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member : CTemplatePrinter::RemoveDialogArgument
|
|
//
|
|
// Synopsis : Remove the dialogArgument specified byt he argument enum.
|
|
//
|
|
// Returens: S_OK: expando obtained (might be VT_NULL or VT_EMPTY)
|
|
// E_*: Error encounterd
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT
|
|
CTemplatePrinter::RemoveDialogArgument(PRINTARG eArg)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
BSTR bstrTarget = NULL;
|
|
VARIANT_BOOL fSuccess;
|
|
|
|
Assert(eArg >= 0 && eArg > PRINTTYPE_LAST);
|
|
|
|
if (!_pevDlgArgs)
|
|
return E_FAIL;
|
|
|
|
bstrTarget = SysAllocString(s_aachPrintArg[eArg]);
|
|
if (!bstrTarget)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto Cleanup;
|
|
}
|
|
|
|
hr = _pevDlgArgs->removeAttribute(bstrTarget, 0, &fSuccess);
|
|
|
|
Cleanup:
|
|
SysFreeString(bstrTarget);
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member : CTemplatePrinter::EnsureMLLoadLibrary
|
|
//
|
|
// Synopsis : Ensure the library with the default header/footer/margins has
|
|
// been loaded and return it.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
HINSTANCE
|
|
CTemplatePrinter::EnsureMLLoadLibrary()
|
|
{
|
|
if (!_hInstResource)
|
|
{
|
|
_hInstResource = MLLoadLibrary(_T("shdoclc.dll"), NULL, ML_CROSSCODEPAGE);
|
|
Assert(_hInstResource && "Resource DLL is not loaded!");
|
|
}
|
|
|
|
return _hInstResource;
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------
|
|
//
|
|
// Function: CTemplatePrinter::GetDefaultMargin
|
|
//
|
|
// Purpose: Get default values for the margin from
|
|
// (1) The registry
|
|
// (2) The resource DLL
|
|
// (3) Arbitrary, hard-coded values.
|
|
//
|
|
// Parameters keyOldValues registry key for the margins or NULL
|
|
// pMarginName "margin_top", "margin_bottom", &c...
|
|
// pMarginValue buffer for value
|
|
// cchMargin length of the buffer in TCHARs
|
|
// dwMarginConst const for getting the margin from the resource file
|
|
//-----------------------------------------------------------------------
|
|
HRESULT
|
|
CTemplatePrinter::GetDefaultMargin(HKEY keyOldValues, TCHAR* pMarginName, TCHAR* pMarginValue, DWORD cchMargin, DWORD dwMarginConst)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
DWORD cchLen;
|
|
Assert(pMarginName);
|
|
Assert(pMarginValue);
|
|
Assert(cchMargin > 0);
|
|
|
|
// First try the passed registry key.
|
|
if (keyOldValues != NULL)
|
|
{
|
|
hr = ReadSubkeyFromRegistry(keyOldValues, pMarginName, pMarginValue, cchMargin);
|
|
}
|
|
|
|
// Next try the resource file.
|
|
if (hr)
|
|
{
|
|
cchLen = ::LoadString(EnsureMLLoadLibrary(), dwMarginConst, pMarginValue, cchMargin);
|
|
if (cchLen > 0)
|
|
hr = ERROR_SUCCESS;
|
|
}
|
|
|
|
// Lastly, just do hardcoded values.
|
|
if (hr)
|
|
{
|
|
cchLen = _tcslen(_T("0.750000")) + 1;
|
|
if (cchLen <= cchMargin)
|
|
{
|
|
_tcscpy(pMarginValue,_T("0.750000"));
|
|
hr = ERROR_SUCCESS;
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CTemplatePrinter::GetDefaultHeaderFooter
|
|
//
|
|
// Purpose: Get default values for the header/footer from
|
|
// (1) The registry
|
|
// (2) The resource DLL
|
|
// (3) Arbitrary, hard-coded values.
|
|
//
|
|
// Arguments: keyOldValues If Not Null try to read from the IE3 defaults, If NULL or the read
|
|
// was not successfull, get it from the resources
|
|
// pValueName "header" or "footer"
|
|
// pDefault ptr to the default header or footer
|
|
// cbDefault size of the array to hold the header-footer (in TCHAR)
|
|
// pDefaultLiteral default value if there is no def. in resources
|
|
//
|
|
// Returns : None
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT
|
|
CTemplatePrinter::GetDefaultHeaderFooter(HKEY keyOldValues,
|
|
TCHAR* pValueName,
|
|
TCHAR* pDefault,
|
|
DWORD cchDefault,
|
|
DWORD dwResourceID,
|
|
TCHAR* pDefaultLiteral)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
|
|
Assert(pValueName);
|
|
Assert(pDefault);
|
|
Assert(pDefaultLiteral);
|
|
Assert(cchDefault > 0);
|
|
|
|
// Try registry for a left/right header/footer first.
|
|
if (keyOldValues != NULL)
|
|
{
|
|
TCHAR achName[32];
|
|
TCHAR achLeft [MAX_DEFAULTHEADFOOT] = _T("");
|
|
TCHAR achRight[MAX_DEFAULTHEADFOOT] = _T("");
|
|
TCHAR achSeparator[3] = _T("&b");
|
|
DWORD cchTotal = 0;
|
|
|
|
_tcscpy(achName,pValueName);
|
|
_tcscat(achName,_T("_left"));
|
|
if (!ReadSubkeyFromRegistry(keyOldValues, achName, achLeft, MAX_DEFAULTHEADFOOT))
|
|
cchTotal += _tcslen(achLeft);
|
|
|
|
_tcscpy(achName,pValueName);
|
|
_tcscat(achName,_T("_right"));
|
|
if (!ReadSubkeyFromRegistry(keyOldValues, achName, achRight, MAX_DEFAULTHEADFOOT))
|
|
cchTotal += _tcslen(achRight);
|
|
|
|
if (cchTotal)
|
|
{
|
|
// Include the null - add it in.
|
|
cchTotal += _tcslen(achSeparator) + 1;
|
|
if (cchTotal <= cchDefault)
|
|
{
|
|
_tcscpy(pDefault,achLeft);
|
|
_tcscat(pDefault,achSeparator);
|
|
_tcscat(pDefault,achRight);
|
|
hr = ERROR_SUCCESS;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Concatenate the left/right if it exists and return it.
|
|
if (hr)
|
|
{
|
|
DWORD cchLen;
|
|
cchLen = ::LoadString(EnsureMLLoadLibrary(), dwResourceID, pDefault, cchDefault);
|
|
if (cchLen > 0)
|
|
hr = ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
// Otherwise, use the passed default value.
|
|
if (hr)
|
|
{
|
|
if (_tcslen(pDefaultLiteral) + 1 <= cchDefault)
|
|
{
|
|
_tcscpy(pDefault, pDefaultLiteral);
|
|
hr = ERROR_SUCCESS;
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CTemplatePrinter::GetDefaultPageSetupValues
|
|
//
|
|
// Synopsis: Try to get the old page setup values from HKEY_LOCAL_MACHINE. If found copies them into
|
|
// HKEY_CURRENT_USER, if not, copies the default values
|
|
//
|
|
// Arguments: None
|
|
//
|
|
// Returns : S_OK or E_FAIL
|
|
//
|
|
// Summary : ---
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT
|
|
CTemplatePrinter::GetDefaultPageSetupValues(HKEY keyExplorer,HKEY * pKeyPrintOptions)
|
|
{
|
|
TCHAR achDefaultHeader[MAX_DEFAULTHEADFOOT];
|
|
TCHAR achDefaultFooter[MAX_DEFAULTHEADFOOT];
|
|
TCHAR achDefaultMarginTop [MAX_MARGINLENGTH];
|
|
TCHAR achDefaultMarginBottom [MAX_MARGINLENGTH];
|
|
TCHAR achDefaultMarginLeft [MAX_MARGINLENGTH];
|
|
TCHAR achDefaultMarginRight [MAX_MARGINLENGTH];
|
|
HKEY keyOldValues;
|
|
HRESULT hr = S_OK;
|
|
|
|
if (!pKeyPrintOptions)
|
|
{
|
|
hr = E_POINTER;
|
|
goto Cleanup;
|
|
}
|
|
|
|
// Check the default machine registry values
|
|
if (::RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
|
_T("Software\\Microsoft\\Internet Explorer\\PageSetup"),0,
|
|
KEY_ALL_ACCESS,
|
|
&keyOldValues) != ERROR_SUCCESS)
|
|
{
|
|
keyOldValues = NULL;
|
|
}
|
|
|
|
GetDefaultHeaderFooter(keyOldValues, _T("header"), (TCHAR*)&achDefaultHeader, MAX_DEFAULTHEADFOOT, IDS_DEFAULTHEADER, _T("&w&bPage &p of &P"));
|
|
GetDefaultHeaderFooter(keyOldValues, _T("footer"), (TCHAR*)&achDefaultFooter, MAX_DEFAULTHEADFOOT, IDS_DEFAULTFOOTER, _T("&u&b&d"));
|
|
GetDefaultMargin(keyOldValues, _T("margin_bottom"), (TCHAR*)&achDefaultMarginBottom, MAX_MARGINLENGTH, IDS_DEFAULTMARGINBOTTOM);
|
|
GetDefaultMargin(keyOldValues, _T("margin_top"), (TCHAR*)&achDefaultMarginTop, MAX_MARGINLENGTH, IDS_DEFAULTMARGINTOP);
|
|
GetDefaultMargin(keyOldValues, _T("margin_left"), (TCHAR*)&achDefaultMarginLeft, MAX_MARGINLENGTH, IDS_DEFAULTMARGINLEFT);
|
|
GetDefaultMargin(keyOldValues, _T("margin_right"), (TCHAR*)&achDefaultMarginRight, MAX_MARGINLENGTH, IDS_DEFAULTMARGINRIGHT);
|
|
|
|
::RegCloseKey(keyOldValues);
|
|
keyOldValues = NULL;
|
|
|
|
// Create the new user registry key
|
|
if (::RegCreateKeyEx(keyExplorer,
|
|
_T("PageSetup"),
|
|
0,
|
|
NULL,
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_ALL_ACCESS,
|
|
NULL,
|
|
pKeyPrintOptions,
|
|
NULL) == ERROR_SUCCESS)
|
|
{
|
|
// Put our default values into registry keys.
|
|
WriteSubkeyToRegistry(*pKeyPrintOptions, _T("header"), achDefaultHeader);
|
|
WriteSubkeyToRegistry(*pKeyPrintOptions, _T("footer"), achDefaultFooter);
|
|
WriteSubkeyToRegistry(*pKeyPrintOptions, _T("margin_bottom"), achDefaultMarginBottom);
|
|
WriteSubkeyToRegistry(*pKeyPrintOptions, _T("margin_left"), achDefaultMarginLeft);
|
|
WriteSubkeyToRegistry(*pKeyPrintOptions, _T("margin_right"), achDefaultMarginRight);
|
|
WriteSubkeyToRegistry(*pKeyPrintOptions, _T("margin_top"), achDefaultMarginTop);
|
|
};
|
|
|
|
Cleanup:
|
|
return hr;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CTemplatePrinter::GetRegPrintOptionsKey
|
|
//
|
|
// Synopsis: Get handle of requested key under \HKCU\Software\Microsoft\Internet Explorer
|
|
//
|
|
// Arguments: PrintSubKey - subkey of printoptions root to return key for
|
|
// pKeyPrintOptions - ptr to handle of requested key in registry
|
|
//
|
|
// Returns : S_OK or E_FAIL
|
|
//
|
|
// Summary : First it tries to get the values from "new place"
|
|
// HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\PageSetup
|
|
// If there is no such a key, it creates it and tries to get the values from "old place"
|
|
// HKEY_LOCAL_MACHINE\Software\Microsoft\Internet Explorer\PageSetup
|
|
// If successful it copies the values into the "new place"
|
|
// If not, it tries to get the values from the registry,
|
|
// If no luck, it uses the hardcoded strings
|
|
// NOTE : If the procedure returns with S_OK, it guaranties that they will be a
|
|
// "new place" with values.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT
|
|
CTemplatePrinter::GetRegPrintOptionsKey(PRINTOPTIONS_SUBKEY PrintSubKey, HKEY * pKeyPrintOptions)
|
|
{
|
|
HKEY keyExplorer;
|
|
HRESULT hr = E_FAIL;
|
|
|
|
if (RegOpenKeyEx(
|
|
HKEY_CURRENT_USER,
|
|
_T("Software\\Microsoft\\Internet Explorer"),
|
|
0,
|
|
KEY_ALL_ACCESS,
|
|
&keyExplorer) == ERROR_SUCCESS)
|
|
{
|
|
LPTSTR szSubKey = (PrintSubKey == PRINTOPTSUBKEY_MAIN
|
|
? _T("Main")
|
|
: _T("PageSetup"));
|
|
|
|
if (RegOpenKeyEx(keyExplorer,
|
|
szSubKey,
|
|
0,
|
|
KEY_ALL_ACCESS,
|
|
pKeyPrintOptions) == ERROR_SUCCESS)
|
|
{
|
|
if (PrintSubKey == PRINTOPTSUBKEY_PAGESETUP)
|
|
{
|
|
//
|
|
// For the PageSetup key, we do some additional checks to make
|
|
// sure that (at least) the header and footer keys exist.
|
|
//
|
|
|
|
DWORD dwT;
|
|
|
|
if ( (RegQueryValueEx(*pKeyPrintOptions, _T("header"), 0, NULL, NULL, &dwT) == ERROR_SUCCESS)
|
|
&& (RegQueryValueEx(*pKeyPrintOptions, _T("footer"), 0, NULL, NULL, &dwT) == ERROR_SUCCESS))
|
|
{
|
|
// the header and footer keys exist, we're fine
|
|
hr = S_OK;
|
|
}
|
|
else
|
|
{
|
|
// whoops. fall back...
|
|
hr = GetDefaultPageSetupValues(keyExplorer, pKeyPrintOptions);
|
|
}
|
|
}
|
|
else
|
|
hr = S_OK;
|
|
}
|
|
else
|
|
{
|
|
// For page setup, if we don't have default values, create them.
|
|
if (PrintSubKey == PRINTOPTSUBKEY_PAGESETUP)
|
|
{
|
|
hr = GetDefaultPageSetupValues(keyExplorer, pKeyPrintOptions);
|
|
}
|
|
}
|
|
|
|
RegCloseKey(keyExplorer);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member : CTemplatePrinter::ReadBoolFromRegistry
|
|
//
|
|
// Synopsis : Takes an open registry key and subkey name, and returns the
|
|
// value as a boolean.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
BOOL
|
|
CTemplatePrinter::ReadBoolFromRegistry(HKEY hKey, TCHAR *pSubkeyName)
|
|
{
|
|
TCHAR achBool[MAX_DEFAULTBOOL];
|
|
BOOL fRet = FALSE;
|
|
achBool[0] = '\0';
|
|
|
|
if (!ReadSubkeyFromRegistry(hKey, pSubkeyName, achBool, MAX_DEFAULTBOOL))
|
|
{
|
|
fRet = !_tcsicmp(achBool, _T("yes"));
|
|
}
|
|
|
|
return fRet;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member : CTemplatePrinter::AreRatingsEnabled
|
|
//
|
|
// Synopsis : Checks MS_RATING.DLL to see if ratings are enabled.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
BOOL
|
|
CTemplatePrinter::AreRatingsEnabled()
|
|
{
|
|
BOOL fRet = FALSE;
|
|
|
|
typedef HRESULT (STDAPICALLTYPE *PFN)(void);
|
|
|
|
if (!_hInstRatings)
|
|
LoadLibrary("MSRATING.DLL", &_hInstRatings);
|
|
|
|
if (_hInstRatings)
|
|
{
|
|
PFN pfn;
|
|
pfn = (PFN) ::GetProcAddress(_hInstRatings, "RatingEnabledQuery");
|
|
if (!pfn)
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
fRet = !pfn() ? TRUE: FALSE;
|
|
}
|
|
|
|
Cleanup:
|
|
return fRet;
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member : CTemplatePrinter::DecimalTCHARToMargin
|
|
//
|
|
// Synopsis : Takes a decimal representation in 1" and returns a long
|
|
// with that value in 1/100000"
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
long
|
|
CTemplatePrinter::DecimalTCHARToFixed(TCHAR* pString, int nPowersOfTen)
|
|
{
|
|
TCHAR* p = pString;
|
|
int iLen = _tcslen(pString);
|
|
int i;
|
|
int j = 0;
|
|
int iChar = 0;
|
|
long nRet = 0;
|
|
|
|
if (pString == NULL)
|
|
goto Cleanup;
|
|
|
|
// Clear leading whitespace
|
|
for (i=0;i<iLen;i++,p++)
|
|
if (*p != _T(' '))
|
|
break;
|
|
|
|
// Do the integer part
|
|
for (;i<iLen;i++,p++)
|
|
{
|
|
iChar = *p;
|
|
if ((iChar < _T('0')) || (iChar > _T('9')))
|
|
break;
|
|
nRet = nRet * 10 + (iChar - _T('0'));
|
|
}
|
|
|
|
if (iChar == _T('.'))
|
|
{
|
|
// Do the decimal part.
|
|
for (i++,p++; (i+j<iLen && j<5); j++,p++)
|
|
{
|
|
iChar = *p;
|
|
if ((iChar < _T('0')) || (iChar > _T('9')))
|
|
break;
|
|
nRet = nRet * 10 + (iChar - _T('0'));
|
|
}
|
|
}
|
|
|
|
// Make sure we are in 1/100000"
|
|
for (;j < nPowersOfTen; j++)
|
|
nRet *= 10;
|
|
|
|
Cleanup:
|
|
return nRet;
|
|
}
|
|
|
|
BOOL
|
|
CTemplatePrinter::CommCtrlNativeFontSupport()
|
|
{
|
|
BOOL fRet = FALSE;
|
|
typedef BOOL (APIENTRY *PFN)(LPINITCOMMONCONTROLSEX);
|
|
|
|
if (!_hInstComctl32)
|
|
LoadLibrary("COMCTL32.DLL", &_hInstComctl32);
|
|
|
|
if (_hInstComctl32)
|
|
{
|
|
INITCOMMONCONTROLSEX icc;
|
|
PFN pfn;
|
|
|
|
pfn = (PFN) ::GetProcAddress(_hInstComctl32, "InitCommonControlsEx");
|
|
if (!pfn)
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
icc.dwSize = sizeof(INITCOMMONCONTROLSEX);
|
|
icc.dwICC = ICC_NATIVEFNTCTL_CLASS;
|
|
|
|
fRet = pfn(&icc);
|
|
}
|
|
|
|
Cleanup:
|
|
return fRet;
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member : CTemplatePrinter::WriteFixedToRegistry
|
|
//
|
|
// Synopsis : Takes an open registry key and subkey name, and writes the
|
|
// passed value to the resulting registry key in whole units.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT
|
|
CTemplatePrinter::WriteFixedToRegistry(HKEY hKeyPS, const TCHAR* pValueName,LONG nMargin, int nFactor)
|
|
{
|
|
TCHAR achFixed[MAX_MARGINLENGTH];
|
|
|
|
// Convert 1/100000" units to a TCHAR representation of decimal in 1" units.
|
|
FixedToDecimalTCHAR(nMargin, achFixed, nFactor);
|
|
|
|
return WriteSubkeyToRegistry(hKeyPS, pValueName, achFixed);
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member : CTemplatePrinter::ReadFixedFromRegistry
|
|
//
|
|
// Synopsis : Takes an open registry key and subkey name, and gets a fixed point value
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT
|
|
CTemplatePrinter::ReadFixedFromRegistry(HKEY hKeyPS, const TCHAR *pValueName, LONG *pFixed, int nPowersOfTen)
|
|
{
|
|
HRESULT hr;
|
|
TCHAR achFixed[MAX_MARGINLENGTH];
|
|
achFixed[0] = '\0';
|
|
|
|
Assert(pValueName);
|
|
Assert(pFixed);
|
|
|
|
*pFixed = 0;
|
|
|
|
hr = ReadSubkeyFromRegistry(hKeyPS, pValueName, achFixed, MAX_MARGINLENGTH);
|
|
if (!hr)
|
|
*pFixed = DecimalTCHARToFixed(achFixed, nPowersOfTen);
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member : CTemplatePrinter::ReadDeviceUnicode
|
|
//
|
|
// Synopsis : Creates device information given the printer name,
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT
|
|
CTemplatePrinter::ReadDeviceUnicode(TCHAR *pchPrinter, TCHAR *pchDriver, TCHAR *pchPort)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
HANDLE hPrinter = NULL;
|
|
PRINTER_INFO_2 * pPrintInfo = NULL;
|
|
Assert(pchPrinter);
|
|
|
|
if ( ::OpenPrinter(pchPrinter, &hPrinter, NULL)
|
|
&& hPrinter)
|
|
{
|
|
DWORD nStructSize;
|
|
|
|
if (!pchDriver || !pchPort)
|
|
{
|
|
|
|
::GetPrinter(hPrinter, 2, NULL, 0, &nStructSize);
|
|
pPrintInfo = (PRINTER_INFO_2 *) ::GlobalAlloc(GPTR, nStructSize);
|
|
if (!pPrintInfo)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto Cleanup;
|
|
}
|
|
|
|
if (!::GetPrinter(hPrinter, 2, (byte *)pPrintInfo, nStructSize, &nStructSize))
|
|
{
|
|
hr = E_FAIL;
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
|
|
hr = CreateDevNames(pchDriver ? pchDriver : pPrintInfo->pDriverName,
|
|
pchPrinter,
|
|
pchPort ? pchPort : pPrintInfo->pPortName,
|
|
&_hDevNames);
|
|
if (hr)
|
|
goto Cleanup;
|
|
|
|
nStructSize = ::DocumentProperties(0, hPrinter, pchPrinter, NULL, NULL, 0);
|
|
if (nStructSize < sizeof(DEVMODE))
|
|
{
|
|
Assert(!"Memory size suggested by DocumentProperties is smaller than DEVMODE");
|
|
nStructSize = sizeof(DEVMODE);
|
|
}
|
|
|
|
_hDevMode = ::GlobalAlloc(GHND, nStructSize);
|
|
if (_hDevMode)
|
|
{
|
|
DEVMODE *pDevMode = (DEVMODE *) ::GlobalLock(_hDevMode);
|
|
|
|
if (pDevMode)
|
|
{
|
|
::DocumentProperties(0, hPrinter, pchPrinter, pDevMode, NULL, DM_OUT_BUFFER);
|
|
|
|
pDevMode->dmFields &= ~DM_COLLATE;
|
|
pDevMode->dmCollate = DMCOLLATE_FALSE;
|
|
|
|
::GlobalUnlock(_hDevMode);
|
|
}
|
|
else
|
|
{
|
|
::GlobalFree(_hDevMode);
|
|
_hDevMode = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
Cleanup:
|
|
if (hPrinter)
|
|
::ClosePrinter(hPrinter);
|
|
if (pPrintInfo)
|
|
::GlobalFree(pPrintInfo);
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member : CTemplatePrinter::ReadDeviceNonUnicode
|
|
//
|
|
// Synopsys : Because non-Unicode platforms (Win9x) don't properly implement
|
|
// many of the printing widechar calls, they need to explicitly
|
|
// make multibyte (A) calls.
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
HRESULT
|
|
CTemplatePrinter::ReadDeviceNonUnicode(TCHAR *pchPrinterWide, TCHAR *pchDriverWide, TCHAR *pchPortWide)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
HANDLE hPrinter = NULL;
|
|
LPSTR pchPrinter = NULL;
|
|
TCHAR * pchDriverWideLocal = NULL;
|
|
TCHAR * pchPortWideLocal = NULL;
|
|
PRINTER_INFO_2A * pPrintInfo = NULL;
|
|
|
|
Assert(pchPrinterWide);
|
|
|
|
pchPrinter = InitMultiByteFromWideChar(pchPrinterWide);
|
|
if (!pchPrinter)
|
|
{
|
|
hr = E_FAIL;
|
|
goto Cleanup;
|
|
}
|
|
|
|
if ( ::OpenPrinterA(pchPrinter, &hPrinter, NULL)
|
|
&& hPrinter )
|
|
{
|
|
DWORD nStructSize;
|
|
|
|
if (!pchDriverWide || !pchPortWide)
|
|
{
|
|
::GetPrinterA(hPrinter, 2, NULL, 0, &nStructSize);
|
|
|
|
pPrintInfo = (PRINTER_INFO_2A *)::GlobalAlloc(GPTR, nStructSize);
|
|
if (!pPrintInfo)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto Cleanup;
|
|
}
|
|
|
|
if (!::GetPrinterA(hPrinter, 2, (byte *)pPrintInfo, nStructSize, &nStructSize))
|
|
{
|
|
hr = E_FAIL;
|
|
goto Cleanup;
|
|
}
|
|
|
|
pchDriverWideLocal = InitWideCharFromMultiByte(pPrintInfo->pDriverName);
|
|
pchPortWideLocal = InitWideCharFromMultiByte(pPrintInfo->pPortName);
|
|
}
|
|
|
|
hr = CreateDevNames(pchDriverWide ? pchDriverWide : pchDriverWideLocal,
|
|
pchPrinterWide,
|
|
pchPortWide ? pchPortWide : pchPortWideLocal,
|
|
&_hDevNames);
|
|
if (hr)
|
|
goto Cleanup;
|
|
|
|
// NB (105850) (mikhaill) -- Windows Millennium's routine DocumentPropertiesA()
|
|
// impudently changes processor state. This happens just once after
|
|
// reboot and cause, in particular, unmasking floating point exception flags.
|
|
// At some later moment processor meet any suspicious condition (overflow,
|
|
// underflow, zero-divide, precision loose, etc) in some innocent routine,
|
|
// generates unhandled exception and eventually crashes.
|
|
// The following fsave/frstor pair is an ugly patch that should be removed
|
|
// after millennium bug fix.
|
|
// Windows Millennium build versions tested: 4.90.2485, 4.90.2491.
|
|
#ifdef _M_IX86
|
|
{
|
|
FLOATING_SAVE_AREA fsa;
|
|
_asm fsave fsa;
|
|
#endif //_M_IX86
|
|
nStructSize = ::DocumentPropertiesA(0, hPrinter, pchPrinter, NULL, NULL, 0);
|
|
#ifdef _M_IX86
|
|
_asm frstor fsa;
|
|
}
|
|
#endif //_M_IX86
|
|
|
|
if (nStructSize < sizeof(DEVMODEA))
|
|
{
|
|
Assert(!"Memory size suggested by DocumentProperties is smaller than DEVMODEA");
|
|
nStructSize = sizeof(DEVMODEA);
|
|
}
|
|
|
|
_hDevMode = ::GlobalAlloc(GHND, nStructSize);
|
|
if (_hDevMode)
|
|
{
|
|
DEVMODEA *pDevMode = (DEVMODEA *) ::GlobalLock(_hDevMode);
|
|
|
|
if (pDevMode)
|
|
{
|
|
// NB (109499) same as 105850 above
|
|
// but appeared in Windows98 (mikhaill 5/7/00)
|
|
#ifdef _M_IX86
|
|
{
|
|
FLOATING_SAVE_AREA fsa;
|
|
_asm fsave fsa;
|
|
#endif //_M_IX86
|
|
::DocumentPropertiesA(0, hPrinter, pchPrinter, pDevMode, NULL, DM_OUT_BUFFER);
|
|
#ifdef _M_IX86
|
|
_asm frstor fsa;
|
|
}
|
|
#endif //_M_IX86
|
|
|
|
pDevMode->dmFields &= ~DM_COLLATE;
|
|
pDevMode->dmCollate = DMCOLLATE_FALSE;
|
|
|
|
::GlobalUnlock(_hDevMode);
|
|
}
|
|
else
|
|
{
|
|
::GlobalFree(_hDevMode);
|
|
_hDevMode = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
Cleanup:
|
|
if (hPrinter)
|
|
::ClosePrinter(hPrinter);
|
|
if (pPrintInfo)
|
|
::GlobalFree(pPrintInfo);
|
|
if (pchPrinter)
|
|
delete []pchPrinter;
|
|
if (pchDriverWideLocal)
|
|
delete []pchDriverWideLocal;
|
|
if (pchPortWideLocal)
|
|
delete []pchPortWideLocal;
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+-----------------------------------------------------------------------------
|
|
//
|
|
// Member: CTemplatePrinter::GetDeviceProperties
|
|
//
|
|
// Synopsis : Gets the relevant physical properties of the device currently specified
|
|
// in _hDevNames and _hDevMode
|
|
//
|
|
//------------------------------------------------------------------------------
|
|
HRESULT
|
|
CTemplatePrinter::GetDeviceProperties()
|
|
{
|
|
IHTMLElementRender *pRender = NULL;
|
|
IHTMLElement *pElement = NULL;
|
|
BSTR bstrPrinter = NULL;
|
|
HRESULT hr = E_FAIL;
|
|
|
|
if (_hDevNames && _hDevMode)
|
|
{
|
|
DEVNAMES *pDevNames = ((DEVNAMES *)::GlobalLock(_hDevNames));
|
|
void *pDevMode = ::GlobalLock(_hDevMode);
|
|
if (pDevNames && pDevMode)
|
|
{
|
|
HDC hDC = NULL;
|
|
|
|
// (greglett) Non-Unicode badness. See comment at definition of _hDevMode
|
|
if (g_fUnicodePlatform)
|
|
{
|
|
hDC = ::CreateICW(((TCHAR *)pDevNames) + pDevNames->wDriverOffset,
|
|
((TCHAR *)pDevNames) + pDevNames->wDeviceOffset,
|
|
NULL,
|
|
(DEVMODEW *)pDevMode);
|
|
}
|
|
else
|
|
{
|
|
LPSTR pchDriver = InitMultiByteFromWideChar(((TCHAR *)pDevNames) + pDevNames->wDriverOffset);
|
|
LPSTR pchDevice = InitMultiByteFromWideChar(((TCHAR *)pDevNames) + pDevNames->wDeviceOffset);
|
|
if (pchDriver && pchDevice)
|
|
{
|
|
hDC = ::CreateICA(pchDriver,
|
|
pchDevice,
|
|
NULL,
|
|
(DEVMODEA *)pDevMode);
|
|
}
|
|
if (pchDriver)
|
|
delete []pchDriver;
|
|
if (pchDevice)
|
|
delete []pchDevice;
|
|
}
|
|
|
|
if (hDC)
|
|
{
|
|
SIZE szPage;
|
|
|
|
// Obtain the resolution and unprintable areas for this device.
|
|
_szResolution.cx = ::GetDeviceCaps(hDC, LOGPIXELSX);
|
|
_szResolution.cy = ::GetDeviceCaps(hDC, LOGPIXELSY);
|
|
szPage.cx = ::GetDeviceCaps(hDC, PHYSICALWIDTH);
|
|
szPage.cy = ::GetDeviceCaps(hDC, PHYSICALHEIGHT);
|
|
_rcUnprintable.left = ::GetDeviceCaps(hDC, PHYSICALOFFSETX);
|
|
_rcUnprintable.top = ::GetDeviceCaps(hDC, PHYSICALOFFSETY);
|
|
_rcUnprintable.right = szPage.cx - ::GetDeviceCaps(hDC, HORZRES) - _rcUnprintable.left;
|
|
_rcUnprintable.bottom = szPage.cy - ::GetDeviceCaps(hDC, VERTRES) - _rcUnprintable.top;
|
|
Assert(_rcUnprintable.right >= 0);
|
|
Assert(_rcUnprintable.bottom >= 0);
|
|
|
|
_ptPaperSize.x = (_szResolution.cx)
|
|
? MulDivQuick(szPage.cx, 1000, _szResolution.cx)
|
|
: 8500;
|
|
_ptPaperSize.y = (_szResolution.cy)
|
|
? MulDivQuick(szPage.cy, 1000, _szResolution.cy)
|
|
: 11000;
|
|
|
|
|
|
hr = _pPeerSite->GetElement(&pElement);
|
|
if (!hr)
|
|
{
|
|
Assert(pElement);
|
|
|
|
hr = pElement->QueryInterface(IID_IHTMLElementRender, (void **)&pRender);
|
|
if (!hr)
|
|
{
|
|
Assert(pRender);
|
|
|
|
bstrPrinter = ::SysAllocString(((TCHAR *)pDevNames) + pDevNames->wDeviceOffset);
|
|
if (bstrPrinter)
|
|
pRender->SetDocumentPrinter(bstrPrinter,hDC);
|
|
else
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
|
|
::DeleteDC(hDC);
|
|
}
|
|
}
|
|
|
|
::GlobalUnlock(_hDevNames);
|
|
::GlobalUnlock(_hDevMode);
|
|
|
|
hr = S_OK;
|
|
}
|
|
|
|
ReleaseInterface(pElement);
|
|
ReleaseInterface(pRender);
|
|
if (bstrPrinter)
|
|
::SysFreeString(bstrPrinter);
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
CTemplatePrinter::CreateIPrintParams(DVTARGETDEVICE **ppTargetDevice, PAGESET **ppPageSet)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DWORD nStructSize;
|
|
|
|
Assert(ppTargetDevice && ppPageSet);
|
|
(*ppTargetDevice) = NULL;
|
|
(*ppPageSet) = NULL;
|
|
|
|
// Create a PAGESET.
|
|
(*ppPageSet) = (PAGESET *)::CoTaskMemAlloc(sizeof(PAGESET));
|
|
if (!(*ppPageSet))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto Cleanup;
|
|
}
|
|
::ZeroMemory(*ppPageSet, sizeof(PAGESET));
|
|
|
|
(*ppPageSet)->cbStruct = sizeof(PAGESET) ;
|
|
(*ppPageSet)->cPageRange = 1;
|
|
if (_fPrintSelectedPages)
|
|
{
|
|
(*ppPageSet)->rgPages[0].nFromPage = _nPageFrom;
|
|
(*ppPageSet)->rgPages[0].nToPage = _nPageTo;
|
|
}
|
|
else
|
|
{
|
|
(*ppPageSet)->rgPages[0].nFromPage = 1;
|
|
(*ppPageSet)->rgPages[0].nToPage = PAGESET_TOLASTPAGE;
|
|
}
|
|
|
|
(*ppTargetDevice) = InitTargetDevice();
|
|
if (!(*ppTargetDevice))
|
|
{
|
|
// Error! Clear the PageSet structure.
|
|
::CoTaskMemFree(*ppPageSet);
|
|
(*ppPageSet) = NULL;
|
|
|
|
hr = E_FAIL;
|
|
goto Cleanup;
|
|
}
|
|
|
|
Cleanup:
|
|
return hr;
|
|
}
|
|
|
|
|
|
// NB (greglett)
|
|
// Alas, Win9x returns a ASCII DEVMODE and a Unicode DEVNAMES from the dialog functions.
|
|
// The old code avoided converting the second structure, *except* to create a TARGETDEVICE for IPrint objects.
|
|
// Since we will need to do this, I have brought this function over.
|
|
// If this function works *really* well, then maybe we can always convert and get rid of all the explicit calls to
|
|
// ANSI functions above. (CreateICA, CreateDCA, OpenPrinterA, &c...).
|
|
DVTARGETDEVICE *
|
|
DevModeWFromDevModeA( DVTARGETDEVICE *ptd )
|
|
{
|
|
// NOTE: Only the DEVMODE structure is in the wrong (ascii) format!
|
|
DEVMODEA * lpdma = NULL;
|
|
DVTARGETDEVICE * ptdW = NULL;
|
|
|
|
if (!ptd || !ptd->tdExtDevmodeOffset)
|
|
goto Cleanup;
|
|
|
|
lpdma = (DEVMODEA *) (((BYTE *)ptd) + ptd->tdExtDevmodeOffset);
|
|
|
|
// If the reported size is too small for our conception of a DEVMODEA, don't risk a GPF
|
|
// in our code and bail out now.
|
|
if ( (DWORD)lpdma->dmSize + lpdma->dmDriverExtra < offsetof(DEVMODEA, dmLogPixels) )
|
|
goto Cleanup;
|
|
|
|
ptdW = (DVTARGETDEVICE *)::CoTaskMemAlloc( ptd->tdSize + (sizeof(BCHAR) - sizeof(char)) * (CCHDEVICENAME + CCHFORMNAME) );
|
|
|
|
if (ptdW)
|
|
{
|
|
// Copy the entire structure up to DEVMODE part.
|
|
memcpy(ptdW, ptd, ptd->tdExtDevmodeOffset);
|
|
|
|
// Account for the increase of the two DEVMODE unicode strings.
|
|
ptdW->tdSize += (sizeof(BCHAR) - sizeof(char)) * (CCHDEVICENAME + CCHFORMNAME);
|
|
|
|
// Convert the devmode structure.
|
|
{
|
|
DEVMODEW * lpdmw = (DEVMODEW *) (((BYTE *)ptdW) + ptdW->tdExtDevmodeOffset);
|
|
long nCapChar;
|
|
|
|
// Copy the first string (CCHDEVICENAME).
|
|
// Really, 0 indicates a conversion error. However, we really can't do much about it other than construct a NULL string.
|
|
if (!::MultiByteToWideChar(CP_ACP, 0, (char *)lpdma->dmDeviceName, -1, lpdmw->dmDeviceName, CCHDEVICENAME))
|
|
{
|
|
lpdmw->dmDeviceName[0] = _T('\0');
|
|
}
|
|
|
|
// Copy the gap between strings.
|
|
memcpy( &lpdmw->dmSpecVersion,
|
|
&lpdma->dmSpecVersion,
|
|
offsetof(DEVMODEA, dmFormName) -
|
|
offsetof(DEVMODEA, dmSpecVersion) );
|
|
|
|
// Copy the first string (CCHDEVICENAME).
|
|
if (!::MultiByteToWideChar(CP_ACP, 0, (char *)lpdma->dmFormName, -1, lpdmw->dmFormName, CCHFORMNAME))
|
|
{
|
|
lpdmw->dmFormName[0] = _T('\0');
|
|
}
|
|
|
|
|
|
// Copy the last part including the driver-specific DEVMODE part (dmDriverExtra).
|
|
memcpy( &lpdmw->dmLogPixels,
|
|
&lpdma->dmLogPixels,
|
|
(DWORD)lpdma->dmSize + lpdma->dmDriverExtra -
|
|
offsetof(DEVMODEA, dmLogPixels) );
|
|
|
|
// Correct the dmSize member by accounting for larger unicode strings.
|
|
lpdmw->dmSize += (sizeof(BCHAR) - sizeof(char)) * (CCHDEVICENAME + CCHFORMNAME);
|
|
}
|
|
}
|
|
|
|
Cleanup:
|
|
|
|
return ptdW;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------
|
|
//
|
|
// Function: InitPrintHandles
|
|
//
|
|
// Purpose: Allocate a DVTARGETDEVICE structure, and initialize
|
|
// it according to the hDevMode and hDevNames.
|
|
// Also allocated an HIC.
|
|
//
|
|
// Note: IMPORTANT: Note that the DEVMODE structure is not wrapped
|
|
// on non-unicode platforms. (See comments below for details.)
|
|
//
|
|
// Returns: HRESULT
|
|
//
|
|
//-----------------------------------------------------------------------
|
|
DVTARGETDEVICE *
|
|
CTemplatePrinter::InitTargetDevice()
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LPDEVNAMES pDN = NULL;
|
|
LPDEVMODE pDM = NULL;
|
|
LPDEVMODEA pDMA = NULL;
|
|
DVTARGETDEVICE * ptd = NULL;
|
|
WORD nMaxOffset;
|
|
DWORD dwDevNamesSize, dwDevModeSize, dwPtdSize;
|
|
int nNameLength;
|
|
|
|
if (!_hDevNames || !_hDevMode)
|
|
goto Cleanup;
|
|
|
|
pDN = (LPDEVNAMES)::GlobalLock(_hDevNames);
|
|
if (!pDN)
|
|
goto Cleanup;
|
|
if (g_fUnicodePlatform)
|
|
{
|
|
pDM = (LPDEVMODE)::GlobalLock(_hDevMode);
|
|
if (!pDM)
|
|
goto Cleanup;
|
|
}
|
|
else
|
|
{
|
|
pDMA = (LPDEVMODEA)::GlobalLock(_hDevMode);
|
|
if (!pDMA)
|
|
goto Cleanup;
|
|
}
|
|
|
|
// IMPORTANT: We have painstakingly
|
|
// converted only the hDevNames parameter and NOT hDevMode (NOT!!!) to have TCHAR
|
|
// members.
|
|
|
|
nMaxOffset = max( pDN->wDriverOffset, pDN->wDeviceOffset );
|
|
nMaxOffset = max( nMaxOffset, pDN->wOutputOffset );
|
|
nNameLength = _tcslen( (TCHAR *)pDN + nMaxOffset );
|
|
|
|
// dw* are in bytes, not TCHARS
|
|
|
|
dwDevNamesSize = sizeof(TCHAR) * ((DWORD)nMaxOffset + nNameLength + 1);
|
|
dwDevModeSize = g_fUnicodePlatform ? ((DWORD)pDM->dmSize + pDM->dmDriverExtra)
|
|
: ((DWORD)pDMA->dmSize + pDMA->dmDriverExtra);
|
|
|
|
dwPtdSize = sizeof(DWORD) + dwDevNamesSize + dwDevModeSize;
|
|
|
|
ptd = (DVTARGETDEVICE *)::CoTaskMemAlloc(dwPtdSize);
|
|
if (!ptd)
|
|
goto Cleanup;
|
|
else
|
|
{
|
|
ptd->tdSize = dwPtdSize;
|
|
|
|
// This is an ugly trick. ptd->tdDriverNameOffset and pDN happen
|
|
// to match up, so we just copy that plus the data in one big chunk.
|
|
// Remember, I didn't write this -- this code is based on the OLE2 SDK.
|
|
|
|
// Offsets are in characters, not bytes.
|
|
memcpy( &ptd->tdDriverNameOffset, pDN, dwDevNamesSize );
|
|
ptd->tdDriverNameOffset *= sizeof(TCHAR);
|
|
ptd->tdDriverNameOffset += sizeof(DWORD);
|
|
ptd->tdDeviceNameOffset *= sizeof(TCHAR);
|
|
ptd->tdDeviceNameOffset += sizeof(DWORD);
|
|
ptd->tdPortNameOffset *= sizeof(TCHAR);
|
|
ptd->tdPortNameOffset += sizeof(DWORD);
|
|
|
|
// IMPORTANT: We are not converting the DEVMODE structure back and forth
|
|
// from ASCII to Unicode on Win9x anymore because we are not touching the
|
|
// two strings or any other member. Converting the DEVMODE structure can
|
|
// be tricky because of potential and common discrepancies between the
|
|
// value of the dmSize member and sizeof(DEVMODE). (25155)
|
|
|
|
if (g_fUnicodePlatform)
|
|
memcpy((BYTE *)&ptd->tdDriverNameOffset + dwDevNamesSize, pDM, dwDevModeSize);
|
|
else
|
|
memcpy((BYTE *)&ptd->tdDriverNameOffset + dwDevNamesSize, pDMA, dwDevModeSize);
|
|
|
|
ptd->tdExtDevmodeOffset = USHORT(sizeof(DWORD) + dwDevNamesSize);
|
|
|
|
// We must return a corrent (all WCHAR) DVTARGETDEVICEW structure.
|
|
// Convert the nasty DEVMODEA if we've just copied it over.
|
|
if (!g_fUnicodePlatform)
|
|
{
|
|
DVTARGETDEVICE *ptdOld;
|
|
ptdOld = ptd;
|
|
ptd = DevModeWFromDevModeA(ptdOld);
|
|
::CoTaskMemFree(ptdOld);
|
|
}
|
|
}
|
|
|
|
Cleanup:
|
|
if (pDM || pDMA)
|
|
::GlobalUnlock(_hDevMode);
|
|
if (pDN)
|
|
::GlobalUnlock(_hDevNames);
|
|
|
|
return ptd;
|
|
}
|
|
|
|
|
|
#ifdef DBG
|
|
//
|
|
// CTemplatePrinter Debug-Only functions
|
|
//
|
|
void
|
|
CTemplatePrinter::VerifyOrientation()
|
|
{
|
|
// Verify that the page size reflects the current orientation bit in the DEVMODE
|
|
// These properties should always be in sync.
|
|
if (_hDevMode)
|
|
{
|
|
void *pDevMode = ::GlobalLock(_hDevMode);
|
|
if (pDevMode)
|
|
{
|
|
BOOL fOrientationValid;
|
|
BOOL fLandscape;
|
|
|
|
// (greglett) Non-Unicode badness. See comment at definition of _hDevMode
|
|
if (g_fUnicodePlatform)
|
|
{
|
|
fOrientationValid = !!(((DEVMODEW *)pDevMode)->dmFields & DM_ORIENTATION);
|
|
fLandscape = (((DEVMODEW *)pDevMode)->dmOrientation == DMORIENT_LANDSCAPE);
|
|
}
|
|
else
|
|
{
|
|
fOrientationValid = !!(((DEVMODEA *)pDevMode)->dmFields & DM_ORIENTATION);
|
|
fLandscape = (((DEVMODEA *)pDevMode)->dmOrientation == DMORIENT_LANDSCAPE);
|
|
}
|
|
|
|
Assert( !fOrientationValid
|
|
|| fLandscape == (_ptPaperSize.x > _ptPaperSize.y) );
|
|
|
|
::GlobalUnlock(_hDevMode);
|
|
}
|
|
}
|
|
}
|
|
#endif
|