mirror of https://github.com/lianthony/NT4.0
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.
799 lines
18 KiB
799 lines
18 KiB
/*****************************************************************************
|
|
*
|
|
* PRINT.C
|
|
*
|
|
* Copyright (C) Microsoft Corporation 1990.
|
|
* All Rights reserved.
|
|
*
|
|
******************************************************************************
|
|
*
|
|
* Module Intent
|
|
*
|
|
* Code to print help topics.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
#include "help.h"
|
|
|
|
#pragma hdrstop
|
|
|
|
#include <string.h>
|
|
|
|
#include "inc\printset.h"
|
|
|
|
#define MAX_PRINTING 100
|
|
|
|
#define fPrintInsert 0
|
|
#define fPrintRegular 1
|
|
|
|
typedef BOOL (APIENTRY* DLGPRINTPROC)(LPPRINTDLG);
|
|
typedef DWORD (APIENTRY* COMMDLGEXTENDEDERROR)(VOID);
|
|
|
|
BOOL (APIENTRY* pPrintDlg)(LPPRINTDLG);
|
|
DWORD (APIENTRY* pCommDlgExtendedError)(void);
|
|
|
|
// Prototypes
|
|
|
|
INT EXPORT AbortPrint(HDC, INT);
|
|
BOOL EXPORT AbortPrintDlg(HWND, UINT, WPARAM, LPARAM);
|
|
|
|
static int STDCALL DyPrintLayoutHde(HDE, BOOL, RECT, int, int *);
|
|
|
|
void STDCALL ReportComDlgError(DWORD Error);
|
|
|
|
// Global Variables:
|
|
|
|
BOOL fQuitHelp; // Set to TRUE if we should quit help
|
|
|
|
static HDC hdcPrint;
|
|
static BOOL fStartPage;
|
|
|
|
#ifndef NO_PRAGMAS
|
|
#pragma data_seg(".text", "CODE")
|
|
#endif
|
|
const char txtPrintDlg[] = "PrintDlgA";
|
|
const char txtCommDlgError[] = "CommDlgExtendedError";
|
|
#ifndef NO_PRAGMAS
|
|
#pragma data_seg()
|
|
#endif
|
|
|
|
PRINTDLG* ppd;
|
|
extern int cxAspect, cyAspect, cBitCount, cPlanes; // used in bitmap.c
|
|
|
|
|
|
HDC STDCALL HdcGetPrinter(void)
|
|
{
|
|
#ifdef _DEBUG
|
|
LPSTR qchPrinter, qchDriver, qchPort;
|
|
#endif
|
|
HDC hdc;
|
|
PDEVMODE lpDevMode;
|
|
LPDEVNAMES lpDevNames;
|
|
|
|
if (!InitPrintDialogStruct(ahwnd[iCurWindow].hwndParent))
|
|
return NULL;
|
|
|
|
// Let the user know where we are printing to, and give them the option
|
|
// of changing things like DPI if the driver supports it.
|
|
|
|
ASSERT(pPrintDlg);
|
|
#ifdef _DEBUG
|
|
ppd->Flags = PD_NOPAGENUMS | PD_NOSELECTION |
|
|
PD_USEDEVMODECOPIES;
|
|
#else
|
|
ppd->Flags = PD_NOPAGENUMS | PD_NOSELECTION | PD_DISABLEPRINTTOFILE |
|
|
PD_USEDEVMODECOPIES;
|
|
#endif
|
|
|
|
|
|
for (;;) {
|
|
DWORD result = pPrintDlg(ppd);
|
|
if (result == 0 && !PrintDlgFailed()) // did the user cancel?
|
|
return NULL;
|
|
else
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* Commdlg is around and we did get DevNames info. Use it in creating
|
|
* our print DC.
|
|
*/
|
|
|
|
if (ppd->hDevNames) {
|
|
if (ppd->hDevMode)
|
|
lpDevMode = (DEVMODE*) GlobalLock(ppd->hDevMode);
|
|
lpDevNames = (LPDEVNAMES) GlobalLock(ppd->hDevNames);
|
|
}
|
|
else {
|
|
Error(wERRS_NOPRINTSETUP, wERRA_RETURN);
|
|
return NULL;
|
|
}
|
|
|
|
#ifdef _DEBUG
|
|
qchDriver = (LPSTR) lpDevNames + lpDevNames->wDriverOffset;
|
|
qchPrinter = (LPSTR) lpDevNames + lpDevNames->wDeviceOffset;
|
|
qchPort = (LPSTR) lpDevNames + lpDevNames->wOutputOffset;
|
|
#endif
|
|
|
|
hdc = CreateDC((LPSTR) lpDevNames + lpDevNames->wDriverOffset,
|
|
(LPSTR) lpDevNames + lpDevNames->wDeviceOffset,
|
|
(LPSTR) lpDevNames + lpDevNames->wOutputOffset, lpDevMode);
|
|
|
|
GlobalUnlock(ppd->hDevNames);
|
|
GlobalUnlock(ppd->hDevMode);
|
|
|
|
if (!hdc)
|
|
Error(wERRS_OOM, wERRA_RETURN);
|
|
return hdc;
|
|
}
|
|
|
|
/*
|
|
* AbortPrintDlg() printing dialog proc (has a cancle button on it)
|
|
*
|
|
* Procedure:
|
|
*
|
|
* globals used:
|
|
* fAbortPrint -- sets this when the user hits cancel.
|
|
* hdlgPrint -- set to NULL when dialog has been ended.
|
|
*/
|
|
|
|
BOOL EXPORT AbortPrintDlg(HWND hwndDlg, UINT wMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
switch (wMsg) {
|
|
|
|
case WM_COMMAND:
|
|
EnableWindows();
|
|
DestroyWindow(hwndDlg);
|
|
break;
|
|
|
|
case WM_DESTROY:
|
|
hdlgPrint = NULL;
|
|
fAbortPrint = TRUE;
|
|
break;
|
|
|
|
case WM_INITDIALOG:
|
|
ChangeDlgFont(hwndDlg);
|
|
break;
|
|
|
|
default:
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*
|
|
* AbortProc() printing abort procedure
|
|
*
|
|
* globals used:
|
|
* fAbortPrint -- indicates the user hit CANCEL on the print dialog
|
|
* hdlgPrint -- handle of the print dialog
|
|
*
|
|
*/
|
|
|
|
int CALLBACK AbortPrint(HDC hdc, int wCode)
|
|
{
|
|
MSG msg;
|
|
|
|
while (!fAbortPrint && PeekMessage(&msg, (HWND) 0, 0, 0, PM_REMOVE)) {
|
|
if (!hdlgPrint || !IsDialogMessage(hdlgPrint, &msg)) {
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
}
|
|
return !fAbortPrint;
|
|
}
|
|
|
|
/***************
|
|
**
|
|
** void STDCALL PrintHde( hde )
|
|
**
|
|
** purpose
|
|
** Main entry point into printing. This will cause the current
|
|
** topic, passed in the hde, to be printed.
|
|
**
|
|
** arguments
|
|
** HDE hde -- handle to the current topic to be printed.
|
|
**
|
|
** return value
|
|
** none
|
|
**
|
|
** notes
|
|
** This function is not re-entrant.
|
|
**
|
|
***************/
|
|
|
|
BOOL STDCALL PrintHde(HDE hdeTopic)
|
|
{
|
|
HDE hde;
|
|
QDE qde;
|
|
char rgchDialogText[MAX_PRINTING];
|
|
RECT rct;
|
|
PT pt;
|
|
int spErr; // Spooler error
|
|
int dyTopOfPage;
|
|
TLP tlp;
|
|
DOCINFO di;
|
|
|
|
if (fQuitHelp)
|
|
return FALSE;
|
|
|
|
WaitCursor();
|
|
|
|
if (hwndNote)
|
|
SetWindowPos(hwndNote, HWND_NOTOPMOST, 0, 0, 0, 0,
|
|
SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
|
|
|
|
/***********************************************************************
|
|
*
|
|
* CAUTION: While the hourglass is up, we must not call any
|
|
* code that can yield control, or wCursor may become invalid.
|
|
* This includes Error() and PeekMessage().
|
|
*
|
|
************************************************************************/
|
|
|
|
if (fMultiPrinting) {
|
|
if ((hde = HdeCreate(NULL, hdeTopic, dePrint)) == NULL) {
|
|
spErr = 1; // The appropriate error message has already
|
|
goto PrintError; // been displayed.
|
|
}
|
|
}
|
|
else {
|
|
|
|
// Set things up for an error condition:
|
|
|
|
ASSERT(hdlgPrint == NULL);
|
|
hde = NULL;
|
|
|
|
if ((hdcPrint = HdcGetPrinter()) == NULL ||
|
|
(hde = HdeCreate(NULL, hdeTopic, dePrint)) == NULL) {
|
|
spErr = 1; // The appropriate error message has already
|
|
goto PrintError; // been displayed.
|
|
}
|
|
}
|
|
|
|
qde = QdeFromGh(hde);
|
|
qde->hdc = hdcPrint;
|
|
cxAspect = qde->wXAspectMul = GetDeviceCaps(hdcPrint, LOGPIXELSX);
|
|
cyAspect = qde->wYAspectMul = GetDeviceCaps(hdcPrint, LOGPIXELSY);
|
|
|
|
cBitCount = GetDeviceCaps(hdcPrint, BITSPIXEL);
|
|
cPlanes = GetDeviceCaps(hdcPrint, PLANES);
|
|
|
|
// Review: We copy the hwnd from hdeTopic because our current hde does
|
|
// not have one. Way down in the layout code, if the topic has an
|
|
// annotation, the hwnd will be used, (PtAnnoLim()) and therefore must
|
|
// be present. Is there a better way for PtAnnoLim to do it's job? Is this
|
|
// the right HWND to use? if not, what?
|
|
|
|
qde->hwnd = QdeFromGh(hdeTopic)->hwnd;
|
|
|
|
/*
|
|
* Review -- If hTitle is nil, then it could be because key elements
|
|
* in the DE have not yet been initized. Therefore, we will make sure
|
|
* these elements get initialized here. This may be considered a hack.
|
|
*/
|
|
|
|
if (qde->top.hTitle == NULL) {
|
|
rct.top = rct.left = 0;
|
|
rct.right = rct.bottom = 100;
|
|
SetSizeHdeQrct(hde, &rct, TRUE);
|
|
}
|
|
|
|
if (!fMultiPrinting) {
|
|
|
|
// Set up dialog for abort function
|
|
|
|
hdlgPrint = CreateDialog(hInsNow, MAKEINTRESOURCE(ABORTPRINTDLG),
|
|
ahwnd[iCurWindow].hwndParent, AbortPrintDlg);
|
|
|
|
if (hdlgPrint == NULL) {
|
|
spErr = SP_OUTOFMEMORY;
|
|
goto PrintError;
|
|
}
|
|
fAbortPrint = FALSE;
|
|
}
|
|
|
|
DisableWindows();
|
|
|
|
// Set text fields in dialog box.
|
|
|
|
{
|
|
char szTitle[MAX_TOPIC_TITLE];
|
|
|
|
/*
|
|
* The "default" dialog box text is really the template for the
|
|
* final text.
|
|
*/
|
|
|
|
GetCurrentTitleQde(qde, szTitle, sizeof(szTitle));
|
|
ASSERT(!IsEmptyString(szTitle));
|
|
wsprintf(rgchDialogText,
|
|
GetStringResource(sidPrintText), szTitle);
|
|
|
|
ASSERT(lstrlen(rgchDialogText) < sizeof(rgchDialogText));
|
|
SetDlgItemText(hdlgPrint, ABORTPRINTTEXT, rgchDialogText);
|
|
}
|
|
ShowWindow(hdlgPrint, SW_SHOW);
|
|
UpdateWindow(hdlgPrint);
|
|
|
|
/*
|
|
* Set up printing rectangle, using one inch margins (assuming we're in
|
|
* MM_TEXT mode, where 1 logical unit = 1 pixel.)
|
|
*/
|
|
|
|
Escape(qde->hdc, GETPHYSPAGESIZE, 0, NULL, (LPSTR) &pt);
|
|
ASSERT(GetMapMode(qde->hdc) == MM_TEXT);
|
|
rct.left = GetDeviceCaps(qde->hdc, LOGPIXELSX);
|
|
rct.right = pt.x - rct.left;
|
|
ASSERT(rct.right > rct.left);
|
|
rct.top = dyTopOfPage = GetDeviceCaps(qde->hdc, LOGPIXELSY);
|
|
rct.bottom = pt.y - rct.top;
|
|
ASSERT(rct.bottom > rct.top);
|
|
|
|
qde->rct = rct;
|
|
|
|
RemoveWaitCursor();
|
|
|
|
/*
|
|
* Print document. For the STARTDOC call, we need to create a unique
|
|
* string.
|
|
*/
|
|
|
|
SetAbortProc(qde->hdc, AbortPrint);
|
|
|
|
ZeroMemory(&di, sizeof(DOCINFO));
|
|
di.cbSize = sizeof(DOCINFO);
|
|
di.lpszDocName = rgchDialogText;
|
|
|
|
spErr = StartDoc(qde->hdc, &di);
|
|
fStartPage = FALSE;
|
|
|
|
// Non-scrolling region support
|
|
|
|
if (FTopicHasNSR(hde) && spErr > 0 && !fAbortPrint) {
|
|
HSGC hsgc;
|
|
|
|
/*
|
|
* HACK ALERT! Currently we have no way, given a DE, to tell which
|
|
* layout to use, other than the DE type or the value of
|
|
* qde->top.vaCurr. Because we do a jump here, we rely on the latter.
|
|
*/
|
|
|
|
GetTLPNSRStartHde(hde, &tlp);
|
|
JumpTLP(hde, tlp);
|
|
rct.top += DyPrintLayoutHde(hde, fPrintInsert, rct, dyTopOfPage, &spErr);
|
|
|
|
#if 0
|
|
/* Draw a line across bottom of NSR */
|
|
hsgc = (HSGC) HsgcFromQde(qde);
|
|
FSetPen(hsgc, 1, coBLACK, coBLACK, wOPAQUE, roCOPY, wPenSolid);
|
|
GotoXY(hsgc, rct.left, rct.top);
|
|
DrawTo(hsgc, rct.right, rct.top);
|
|
FreeHsgc(hsgc);
|
|
#else
|
|
Unreferenced(hsgc);
|
|
#endif /* 0 */
|
|
|
|
++rct.top;
|
|
SetSizeHdeQrct(hde, &rct, FALSE);
|
|
}
|
|
|
|
if (spErr > 0 && !fAbortPrint) {
|
|
if (FTopicHasSR(hde)) {
|
|
GetTLPTopicStartHde(hde, &tlp);
|
|
JumpTLP(hde, tlp);
|
|
|
|
// NOTE: DyPrintLayoutHde may modify the DE rect.
|
|
|
|
DyPrintLayoutHde(hde, fPrintRegular, rct, dyTopOfPage, &spErr);
|
|
}
|
|
else {
|
|
/*
|
|
* Special Case: There is no scrolling region, so force out
|
|
* whatever we inserted for the non-scrolling region above.
|
|
*/
|
|
|
|
ASSERT(FTopicHasNSR(hde));
|
|
spErr = EndPage(qde->hdc);
|
|
}
|
|
}
|
|
|
|
if (spErr > 0 && !fAbortPrint)
|
|
EndDoc(qde->hdc);
|
|
|
|
PrintError:
|
|
|
|
if (!fMultiPrinting) {
|
|
if (hdcPrint != NULL) {
|
|
DeleteDC(hdcPrint);
|
|
hdcPrint = NULL;
|
|
}
|
|
if (hde != NULL)
|
|
DestroyHde(hde);
|
|
if (hdlgPrint != NULL)
|
|
SendMessage(hdlgPrint, WM_COMMAND, IDCANCEL, 0L);
|
|
if (hwndNote)
|
|
SetWindowPos(hwndNote, HWND_TOPMOST, 0, 0, 0, 0,
|
|
SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
|
|
}
|
|
|
|
ASSERT(hdeTopic);
|
|
if (hdeTopic) {
|
|
cxAspect = GetDeviceCaps(QdeFromGh(hdeTopic)->hdc, LOGPIXELSX);
|
|
cyAspect = GetDeviceCaps(QdeFromGh(hdeTopic)->hdc, LOGPIXELSY);
|
|
cBitCount = GetDeviceCaps(QdeFromGh(hdeTopic)->hdc, BITSPIXEL);
|
|
cPlanes = GetDeviceCaps(QdeFromGh(hdeTopic)->hdc, PLANES);
|
|
}
|
|
|
|
// This was possibly set, if print was called by macro
|
|
|
|
ClearMacroFlag();
|
|
|
|
if (fQuitHelp)
|
|
DestroyHelp();
|
|
else {
|
|
if (fMultiPrinting && (spErr < 0 || fAbortPrint)) {
|
|
fMultiPrinting = FALSE;
|
|
EnableWindows();
|
|
if (spErr != SP_ERROR && spErr != SP_OUTOFMEMORY)
|
|
return FALSE;
|
|
}
|
|
|
|
switch (spErr) {
|
|
case SP_ERROR:
|
|
if (!fAbortPrint)
|
|
Error(wERRS_PRINT_ERROR, wERRA_RETURN);
|
|
return FALSE;
|
|
|
|
case SP_OUTOFMEMORY:
|
|
Error(wERRS_OOM, wERRA_RETURN);
|
|
return FALSE;
|
|
|
|
default:
|
|
if (fMultiPrinting)
|
|
EnableWindows();
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
static int STDCALL DyPrintLayoutHde(HDE hde, BOOL fMode, RECT rct,
|
|
int dyTopOfPage, int* qspErr)
|
|
{
|
|
QDE qde;
|
|
POINT pt;
|
|
POINT dpt;
|
|
int spErr;
|
|
int dyExtra = 0;
|
|
BOOL fHaveFullPage;
|
|
|
|
ASSERT(hde);
|
|
qde = QdeFromGh(hde);
|
|
ASSERT(qspErr);
|
|
spErr = *qspErr;
|
|
|
|
while (spErr > 0 && !fAbortPrint) {
|
|
if (!fStartPage) {
|
|
spErr = StartPage(qde->hdc);
|
|
if (spErr <= 0)
|
|
break;
|
|
fStartPage = TRUE;
|
|
}
|
|
if (fMode == fPrintInsert) {
|
|
pt.x = 0;
|
|
|
|
/*
|
|
* NOTE: For NSRs longer than one page, this may cause the
|
|
* last frame on a page to be duplicated on the next page. We
|
|
* don't expect or care about NSRs longer than one page.
|
|
*/
|
|
|
|
pt.y = min(qde->rct.bottom - qde->rct.top,
|
|
DyGetLayoutHeightHde(hde));
|
|
}
|
|
else {
|
|
pt.x = 0;
|
|
pt.y = DyCleanLayoutHeight(qde);
|
|
|
|
// Adjust pt.y if it is too small or negative
|
|
|
|
if (pt.y < (qde->rct.bottom - qde->rct.top) / 2)
|
|
pt.y = qde->rct.bottom - qde->rct.top;
|
|
}
|
|
dyExtra = pt.y;
|
|
|
|
// Draw appropriate rectangle
|
|
|
|
rct.bottom = rct.top + pt.y - 1;
|
|
|
|
/*
|
|
* fHaveFullPage handles the case where our insertion has
|
|
* completely filled one page. In this case, we need to force a new
|
|
* page.
|
|
*/
|
|
|
|
fHaveFullPage = (rct.bottom + 1 == qde->rct.bottom);
|
|
|
|
/* NOTE:
|
|
* Previously, we have been clipping our output to rct.
|
|
* Unfortunately, clipping rectangles are scaled by the printer's
|
|
* scaling factor (even though nothing else is), and trying to get
|
|
* that scaling factor was causing problems with the rest of the
|
|
* print job. Since DyCleanLayoutHeight should take care of most
|
|
* clipping problems, I have decided to blow off clipping.
|
|
*/
|
|
|
|
RefreshHde(hde, &rct);
|
|
|
|
if (fMode == fPrintRegular || fHaveFullPage) {
|
|
spErr = EndPage(qde->hdc);
|
|
fStartPage = FALSE;
|
|
if (spErr <= 0)
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* If our initial rectangle began smaller than a page height,
|
|
* (because of a previous insertion), then reset to full page height
|
|
* to prepare for next page.
|
|
*/
|
|
|
|
if (rct.top != dyTopOfPage) {
|
|
rct.top = dyTopOfPage;
|
|
SetSizeHdeQrct( hde, &rct, TRUE);
|
|
}
|
|
|
|
// Change pt.y to a negative value to scroll down.
|
|
|
|
pt.y = -pt.y;
|
|
dpt = DptScrollLayout(qde, pt);
|
|
if (dpt.y != pt.y)
|
|
break; // Reached end of topic
|
|
}
|
|
|
|
*qspErr = spErr;
|
|
return dyExtra;
|
|
}
|
|
|
|
BOOL STDCALL InitMPrint(void)
|
|
{
|
|
if (hwndNote || fHelp == POPUP_HELP)
|
|
return FALSE; // no multiple printing from a popup
|
|
|
|
if ((hdcPrint = HdcGetPrinter()) == NULL)
|
|
return FALSE;
|
|
|
|
// Set up dialog for abort function
|
|
|
|
fAbortPrint = FALSE;
|
|
fMultiPrinting = TRUE;
|
|
|
|
hdlgPrint = CreateDialog(hInsNow, MAKEINTRESOURCE(ABORTPRINTDLG),
|
|
ahwnd[MAIN_HWND].hwndParent, AbortPrintDlg);
|
|
|
|
// REVIEW: does this do any good?
|
|
|
|
SetWindowPos(hdlgPrint, HWND_TOPMOST, 0, 0, 0, 0,
|
|
SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
|
|
|
|
if (!hdlgPrint) {
|
|
EndMPrint();
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void STDCALL EndMPrint(void)
|
|
{
|
|
if (hdlgPrint)
|
|
SendMessage(hdlgPrint, WM_COMMAND, IDCANCEL, 0L);
|
|
|
|
if (hdcPrint) {
|
|
DeleteDC(hdcPrint);
|
|
hdcPrint = NULL;
|
|
}
|
|
fMultiPrinting = FALSE;
|
|
}
|
|
|
|
BOOL STDCALL MPrintHash(PCSTR pszFile, HASH hash)
|
|
{
|
|
if (!fMultiPrinting || fAbortPrint || fQuitHelp)
|
|
return FALSE;
|
|
FJumpHash(pszFile, hash);
|
|
FlushMessageQueue(0);
|
|
return PrintHde(HdeGetEnv());
|
|
}
|
|
|
|
BOOL STDCALL MPrintId(PCSTR pszFile, PCSTR pszCtx)
|
|
{
|
|
if (!fMultiPrinting || fAbortPrint || fQuitHelp)
|
|
return FALSE;
|
|
if (IsEmptyString(pszCtx)) // empty means pszFile is the topic id
|
|
FJumpId(txtZeroLength, pszFile);
|
|
else
|
|
FJumpId(pszFile, pszCtx);
|
|
|
|
FlushMessageQueue(0);
|
|
return PrintHde(HdeGetEnv());
|
|
}
|
|
|
|
#ifdef _DEBUG
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: ReportComDlgError
|
|
|
|
PURPOSE: For debug version, specify what the error constant is. For
|
|
non-debug version, report an internal error.
|
|
|
|
RETURNS:
|
|
|
|
COMMENTS:
|
|
|
|
MODIFICATION DATES:
|
|
16-Sep-1991 [ralphw]
|
|
|
|
***************************************************************************/
|
|
|
|
#include <cderr.h>
|
|
|
|
static PSTR apszCDErr[] = {
|
|
"CDERR_GENERALCODES",
|
|
"CDERR_STRUCTSIZE",
|
|
"CDERR_INITIALIZATION",
|
|
"CDERR_NOTEMPLATE",
|
|
"CDERR_NOHINSTANCE",
|
|
"CDERR_LOADSTRFAILURE",
|
|
"CDERR_FINDRESFAILURE",
|
|
"CDERR_LOADRESFAILURE",
|
|
"CDERR_LOCKRESFAILURE",
|
|
"CDERR_MEMALLOCFAILURE",
|
|
"CDERR_MEMLOCKFAILURE",
|
|
"CDERR_NOHOOK"
|
|
};
|
|
|
|
static PSTR apszFNErr[] = {
|
|
"FNERR_FILENAMECODES",
|
|
"FNERR_SUBCLASSFAILURE",
|
|
"FNERR_INVALIDFILENAME",
|
|
"FNERR_BUFFERTOOSMALL"
|
|
};
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: ReportComDlgError
|
|
|
|
PURPOSE: Display the constant name of the common dialog box error
|
|
|
|
RETURNS:
|
|
|
|
COMMENTS:
|
|
|
|
MODIFICATION DATES:
|
|
16-Sep-1991 [ralphw]
|
|
|
|
***************************************************************************/
|
|
|
|
void STDCALL ReportComDlgError(DWORD err)
|
|
{
|
|
char szMsg[100];
|
|
|
|
strcpy(szMsg, "Common Dialog Box error: ");
|
|
|
|
if (err >= CDERR_GENERALCODES && err <= PDERR_PRINTERCODES)
|
|
strcat(szMsg, apszCDErr[err]);
|
|
else if (err >= FNERR_FILENAMECODES && err <= FRERR_FINDREPLACECODES)
|
|
strcat(szMsg, apszFNErr[err - FNERR_FILENAMECODES]);
|
|
else
|
|
wsprintf(szMsg + strlen(szMsg), "%lu", err);
|
|
|
|
AuthorMsg(szMsg, NULL);
|
|
return;
|
|
}
|
|
|
|
#endif
|
|
|
|
BOOL STDCALL InitPrintDialogStruct(HWND hwnd)
|
|
{
|
|
HLIBMOD hmodule;
|
|
|
|
if (!ppd) {
|
|
ppd = (PRINTDLG*) lcCalloc(sizeof(PRINTDLG));
|
|
if (!ppd) {
|
|
Error(wERRS_OOM, wERRA_RETURN);
|
|
return FALSE;
|
|
}
|
|
ppd->lStructSize = sizeof(PRINTDLG);
|
|
ppd->hInstance = hInsNow;
|
|
}
|
|
|
|
ppd->hwndOwner = hwnd;
|
|
|
|
/*
|
|
* Check if we have picked up a DEVNAMES structure previously from
|
|
* commdlg during print setup (or here).
|
|
*/
|
|
|
|
if (!ppd->hDevMode) {
|
|
if (!pPrintDlg) {
|
|
if ((hmodule = HFindDLL(txtCommDlg, FALSE))) {
|
|
pPrintDlg = (DLGPRINTPROC) GetProcAddress(hmodule,
|
|
txtPrintDlg);
|
|
pCommDlgExtendedError =
|
|
(COMMDLGEXTENDEDERROR) GetProcAddress(hmodule,
|
|
txtCommDlgError);
|
|
}
|
|
else {
|
|
Error(wERRS_MISSINGCOMMDLG, wERRA_RETURN);
|
|
return NULL;
|
|
}
|
|
|
|
if (!pPrintDlg || !pCommDlgExtendedError) {
|
|
Error(wERRS_CORRUPTCOMMDLG, wERRA_RETURN);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
ppd->Flags = PD_RETURNDEFAULT | PD_PRINTSETUP;
|
|
|
|
pPrintDlg(ppd);
|
|
|
|
if (!ppd->hDevNames) {
|
|
Error(wERRS_NOPRINTSETUP, wERRA_RETURN);
|
|
return FALSE;
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: PrintDlgFailed
|
|
|
|
PURPOSE: Determins cause of PrintDlg returning 0
|
|
|
|
PARAMETERS:
|
|
void
|
|
|
|
RETURNS: TRUE to call the dialog again
|
|
|
|
COMMENTS:
|
|
|
|
MODIFICATION DATES:
|
|
29-Sep-1994 [ralphw]
|
|
|
|
***************************************************************************/
|
|
|
|
BOOL STDCALL PrintDlgFailed(void)
|
|
{
|
|
DWORD errno = pCommDlgExtendedError();
|
|
|
|
if (errno) {
|
|
/*
|
|
* There are quite a number of extended errors from commdlg
|
|
* and it's not clear what all will come back from Printer Setup.
|
|
* Many of them have to do with commdlg encountering resource
|
|
* limits. We punt on these and report a Print Setup error msg.
|
|
* These two have to do with someone changing the printer
|
|
* settings on us while we're running. The error handling here
|
|
* was drawn from the win 3.1 notepad.exe sources.
|
|
*/
|
|
|
|
if (errno == PDERR_PRINTERNOTFOUND || errno == PDERR_DNDMMISMATCH) {
|
|
if (ppd->hDevMode) {
|
|
GlobalFree(ppd->hDevMode);
|
|
ppd->hDevMode = NULL;
|
|
}
|
|
if (ppd->hDevNames) {
|
|
GlobalFree(ppd->hDevNames);
|
|
ppd->hDevNames = NULL;
|
|
}
|
|
return TRUE;
|
|
}
|
|
Error(wERRS_NOPRINTSETUP, wERRA_RETURN);
|
|
}
|
|
return FALSE;
|
|
}
|