windows-nt/Source/XPSP1/NT/shell/osshell/accesory/calendar/calprint.c
2020-09-26 16:20:57 +08:00

1179 lines
31 KiB
C

/*
* Windows Calendar
* Copyright (c) 1985 by Microsoft Corporation, all rights reserved.
* Written by Mark L. Chamberlin, consultant to Microsoft.
*
*/
/*
*****
***** calprint.c
*****
*/
#include "cal.h"
#include <string.h>
#include <ctype.h>
#include <time.h>
int TranslateString(CHAR *);
CHAR * APIENTRY PFileInPath(CHAR *sz);
VOID APIENTRY DestroyAbortWnd(VOID);
/* We'll dynamically allocate this */
HANDLE hHeadFoot=NULL;
LPSTR szHeadFoot;
SHORT xCharPage, dyHeadFoot;
int dyTop,dyBottom,dxLeft ,dxRight;
int CharPrintWidth, CharPrintHeight;
HDC vhDCPrint;
BOOL vfAbortPrint;
HWND vhwndAbortPrint;
INT vcyPrintLineToLine;
INT xPrintRes, yPrintRes, xPixInch, yPixInch;
INT hChars;
INT vclnPage;
INT nSpace;
INT vclnPrinted;
INT vclnDate;
INT vlnFooter; /* footer line */
INT vlnBottom; /* last line of calendar text */
INT vlnTop; /* first line of calendar text */
BOOL vfPrint;
CHAR szCurDateBuf[9]; /* buffer containing date string for header/footer */
CHAR *szcurDptr = szCurDateBuf;
INT iCurDateLength ;
DOSDATE CurDD;
CHAR *vpchPrintBuf;
#define CLNHEADING 1
#define CLNAFTERHEADING 1
#define CLNAFTERAPPOINTMENTS 1
#define CLNBETWEENDATES 2
/* 1 - blank or asterisk for alarm
1 - blank
CCHTIMESZ - appointment time (includes 0 terminator, which is used
to hold a blank here)
CCHQDMAX - room for a maximum length appointment description
1 - room for the 0 terminator
The print buffer is also used for outputting the heading, so it
must be long enough for that too. To make sure this is the case,
add in CCHDATEDISP.
*/
#define CCHPRINTBUF (1 + 1 + CCHTIMESZ + CCHQDMAX + 1 + CCHDATEDISP)
/* Format of a printed date:
if not at top of page, CLNBETWEENDATES blank lines
Heading (e.g., Thursday, July 11, 1985)
CLNAFTERHEADING blank lines
Appointments (e.g., * 10:00 Call Tandy to report progress (asterisk
indicates alarm set)
CLNAFTERAPPOINTMENTS blank lines
notes
*/
/**** FnPrint ****/
INT_PTR CALLBACK FnPrint (
HWND hwnd,
UINT message,
WPARAM wParam,
LPARAM lParam)
{
CHAR szFromDate [CCHDASHDATE];
switch (message)
{
case WM_INITDIALOG:
/* Remember the window handle of the dialog for AlertBox. */
vhwndDialog = hwnd;
GetDashDateSel (szFromDate);
SetDlgItemText (hwnd, IDCN_FROMDATE, szFromDate);
return (TRUE);
case WM_COMMAND:
switch (GET_WM_COMMAND_ID(wParam, lParam)) {
case IDOK:
GetRangeOfDates (hwnd);
/* line added to fix keyboard hanging when Calendar
is run under ver3.0 rel 1.11 */
CalSetFocus (GetDlgItem(hwnd, IDCN_FROMDATE));
break;
case IDCANCEL:
EndDialog (hwnd, FALSE);
break;
}
return (TRUE);
}
/* Tell Windows we did not process the message. */
return (FALSE);
}
/**** Print */
VOID FAR APIENTRY Print ()
{
TEXTMETRIC Metrics;
WORD idrFree;
INT itdd;
DD *pdd;
DT dt;
DL dl;
WORD idr;
CHAR rgchPrintBuf [CCHPRINTBUF];
INT iDateLen;
INT iHeight;
INT iWidth;
/* Note - there is no need to force edits to be recorded here.
We got here after the Print dialog, which took over the focus
and therefore has recorded the edits. We are not going to
modify the current DR, so we do not need to set the focus
to NULL (as we sometimes do to prevent recording data into
the wrong DR).
*/
if (BeginPrint () < 0)
{
/* Unable to get print DC - display error and give up. */
CalPrintAlert(SP_ERROR);
return;
}
/* Determine the number of lines per page. */
GetTextMetrics (vhDCPrint, &Metrics);
CharPrintHeight = Metrics.tmHeight + Metrics.tmExternalLeading;
CharPrintWidth = (Metrics.tmAveCharWidth + Metrics.tmMaxCharWidth)/2; /* character width */
xPrintRes = GetDeviceCaps(vhDCPrint, HORZRES);
yPrintRes = GetDeviceCaps(vhDCPrint, VERTRES);
xPixInch = GetDeviceCaps(vhDCPrint, LOGPIXELSX);
yPixInch = GetDeviceCaps(vhDCPrint, LOGPIXELSY);
dyHeadFoot = yPixInch / 2; /* 1/2 an inch */
dyTop = atopix(chPageText[4], yPixInch);
dyBottom = atopix(chPageText[5], yPixInch);
dxLeft = atopix(chPageText[2], xPixInch);
dxRight = atopix(chPageText[3], xPixInch);
/* There's some recalculating here entirely unneeded. The call to
GetDeviceCaps for hChars isn't needed since xPrintRes already has
that value. CharPrintHeight already has the value desired for
vcyPrintLineToLine. (I'd pull one of them out entirely, but that
requres a lot of code review without the time.) The call to
GetDeviceCaps for vlnFooter isn't needed since yPrintRes already
has that value. 21 Sept 1989 Clark Cyr */
#if 0
hChars=GetDeviceCaps(vhDCPrint, HORZRES)/Metrics.tmAveCharWidth;
vcyPrintLineToLine = Metrics.tmHeight + Metrics.tmExternalLeading;
vlnFooter = GetDeviceCaps(vhDCPrint, VERTRES) / vcyPrintLineToLine - 1;
#endif
hChars = xPrintRes / Metrics.tmAveCharWidth;
vlnFooter = yPrintRes / (vcyPrintLineToLine = CharPrintHeight) - 1;
MGetTextExtent(vhDCPrint, " ", 1, &iHeight, &iWidth);
nSpace = iWidth;
viLeftMarginLen =dxLeft/nSpace;
viRightMarginLen=dxRight/nSpace;
viTopMarginLen =dyTop/vcyPrintLineToLine;
viBotMarginLen =dyBottom/vcyPrintLineToLine;
/* Number of characters between margins */
xCharPage=(xPrintRes/CharPrintWidth)-viLeftMarginLen-viRightMarginLen;
/* Allocate memory for the header.footer string. Will allow any size
* of paper and still have enough for the string.
*/
hHeadFoot=GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, (DWORD)xCharPage+2);
if (!hHeadFoot)
{
/* Tell user that there's not memory to do this... */
CalPrintAlert(SP_OUTOFMEMORY);
return;
}
/* Change 2 to 3. Leave room for footer itself. 21 Sept 1989 Clark Cyr */
vclnPage = vlnFooter - 3;
vlnTop = viTopMarginLen;
vlnBottom = vclnPage - viBotMarginLen;
CurDD.dayofweek = 0xff;
CurDD.year = vd3Cur.wYear + 1980;
CurDD.month = vd3Cur.wMonth + 1;
CurDD.day = vd3Cur.wDay + 1;
iDateLen = GetDateString(&CurDD, szCurDateBuf, GDS_LONG|GDS_DAYOFWEEK);
*(szcurDptr + iDateLen) = '\0';
/* Find a free DR in case we need to read from the disk. */
idrFree = IdrFree ();
/* Say we are at the top of the page. */
/* vclnPrinted = 0; */
/* print out header string */
viCurrentPage = 1;
vpchPrintBuf = rgchPrintBuf;
PrintHeaderFooter(TRUE);
vclnPrinted = vlnTop;
for (itdd = vitddFirst; !vfAbortPrint && itdd < vitddMax; itdd++)
{
pdd = TddLock () + itdd;
dt = pdd -> dt;
dl = pdd -> dl;
idr = pdd -> idr;
TddUnlock ();
if (idr == IDRNIL)
{
/* The date is not in memory, see if it's on disk. */
if (dl == DLNIL)
{
/*
Not on disk either - this is an empty DD. Skip
over this date.
*/
continue;
}
/* Read the date from disk into the free DR. */
ReadTempDr (idr = idrFree, dl);
}
/* Calculate how many lines are needed to print this date. */
if (!PrintDate (idr, dt, FALSE))
return;
if (vclnDate == 0)
{
/* There's nothing to print in this date (must just
be special times without alarms or text and no notes).
*/
continue;
}
/* Change 0 to vlnTop + 2. 21 Sept 1989 Clark Cyr */
if (vclnPrinted > vlnTop + 2)
{
/* Not at top of page - see if this entire date will fit
on the remainder of this page. If it won't fit, start
a new page.
*/
/* print out the footer if bottom of page is reached */
if (vclnPrinted + vclnDate > vlnBottom ){
PrintHeaderFooter( FALSE );
if (!NewPage ())
return;
viCurrentPage++;
/* print out the header on top of new page */
PrintHeaderFooter( TRUE );
vclnPrinted = vlnTop;
}
}
/* Print the schedule for the date. */
if (!PrintDate (idr, dt, TRUE))
return;
}
/* print out the footer if bottom of page is reached */
if (vclnPrinted < vlnFooter - 3)
PrintHeaderFooter(FALSE);
if (NewPage ())
EndPrint ();
GlobalFree(hHeadFoot);
hHeadFoot=NULL;
}
/*
* convert floating point strings (like 2.75 1.5 2) into number of pixels
* given the number of pixels per inch
*/
INT atopix(CHAR *ptr, INT pix_per_in)
{
CHAR *dot_ptr;
CHAR sz[20];
INT decimal;
lstrcpy(sz, ptr);
dot_ptr = strchr(sz, szDec[0]);
if (dot_ptr)
{
*dot_ptr++ = 0; /* terminate the inches */
if (*(dot_ptr + 1) == 0)
{
*(dot_ptr + 1) = '0'; /* convert decimal part to hundredths */
*(dot_ptr + 2) = 0;
}
decimal = ((INT)atol(dot_ptr) * pix_per_in) / 100; /* first part */
}
else
decimal = 0; /* there is not fraction part */
return ((INT)atol(sz) * pix_per_in) + decimal; /* second part */
}
/**** PrintDate - Print the specified date. If fPrint == FALSE then
don't actually print - just set up vclnDate with the number of
lines required to print the date.
*/
BOOL APIENTRY PrintDate (
INT idr,
DT dt,
BOOL fPrint)
{
CHAR rgchPrintBuf [CCHPRINTBUF];
CHAR szTemp[CCHPRINTBUF];
DR *pdr;
register PQR pqr;
PQR pqrMax;
CHAR *pchTemp;
register CHAR *pchSrc;
CHAR *pchDest;
CHAR c;
BOOL fSameLine;
INT cchTime, i, nx;
BOOL fFirstLine;
BOOL fFirstPM;
/* Set up global print flag for routines to be called. */
vfPrint = fPrint;
/* Set up a global pointer to the print buffer. */
vpchPrintBuf = rgchPrintBuf;
/* Initialize the count of lines required to print this date. */
vclnDate = 0;
pdr = PdrLock (idr);
fFirstLine = TRUE;
fFirstPM = TRUE;
for (pqrMax = (PQR)((BYTE UNALIGNED*)(pqr = (PQR)PbTqrFromPdr(pdr)) +
pdr->cbTqr); pqr<pqrMax; pqr = (PQR)((BYTE UNALIGNED*)pqr + pqr->cb))
{
/* Don't print special times that don't have an alarm
or an appointment description.
*/
if (pqr -> fAlarm || pqr -> cb != CBQRHEAD)
{
if (!PrintHeading (dt))
goto error0;
FillBuf (vpchPrintBuf, CCHPRINTBUF, ' ');
if (pqr -> fAlarm)
*(vpchPrintBuf+viLeftMarginLen) = '*';
cchTime = GetTimeSz (pqr -> tm, vpchPrintBuf + viLeftMarginLen + 2);
/* Print am/pm strings only for first line printed and noon */
if (!(fFirstLine || ((fFirstPM && pqr->tm >= TMNOON))))
FillBuf (vpchPrintBuf+viLeftMarginLen+5+2, cchTime-5, ' ');
FillBuf (vpchPrintBuf, viLeftMarginLen, ' '); /* pad margin space
with blanks */
pchTemp = vpchPrintBuf + viLeftMarginLen + cchTime+2;
*pchTemp++ = ' ';
*pchTemp = '\0';
if (pqr -> cb > CBQRHEAD)
lstrcpy (pchTemp, (CHAR *)((BYTE *)pqr + CBQRHEAD));
CheckMarg:
if (lstrlen(vpchPrintBuf) > (hChars-viRightMarginLen))
{
lstrcpy(szTemp, vpchPrintBuf+hChars-viRightMarginLen);
vpchPrintBuf[hChars-viRightMarginLen]=0;
if (!PrintLine ())
goto error0;
/* CHeck for one space at the beginning and strip if needed */
nx=0;
if (szTemp[0]==' ' && szTemp[1]!=' ')
nx=1;
/* Note that 11 = strlen[* + Time + AM/PM + Space] */
FillBuf (vpchPrintBuf, viLeftMarginLen+11-nx, ' ');
vpchPrintBuf[viLeftMarginLen+11-nx]=0;
lstrcat(vpchPrintBuf, szTemp);
goto CheckMarg;
}
if (!PrintLine ())
goto error0;
fFirstLine = FALSE;
if (pqr->tm >= TMNOON)
fFirstPM = FALSE;
}
}
if (pdr -> cbNotes != 0)
{
if (vclnDate != 0)
{
if (!PrintBlankLn (CLNAFTERAPPOINTMENTS))
goto error0;
}
else
if (!PrintHeading (dt))
goto error0;
/* The notes are split into lines as follows:
'\0' terminates a line and terminates the notes.
<CR,LF> is a hard line break (user typed Enter key).
<CR,CR,LF> is a soft line break (caused by word wrap).
In order to do something reasonable no matter what is seen,
this code skips an abitrary number of CRs followed by an
arbitrary number of LFs.
*/
pchSrc = (CHAR *)((BYTE *)pdr + CBDRHEAD);
while (*pchSrc != '\0')
{
pchDest = rgchPrintBuf;
fSameLine = TRUE;
i=0; /* fill margin space with blanks */
while (i<viLeftMarginLen)
{
*pchDest++ = ' ';
i++;
}
while (fSameLine)
{
c=*pchSrc;
#ifdef DBCS
if( IsDBCSLeadByte(*pchSrc) )
*pchDest++ = *pchSrc++;
*pchDest++ = *pchSrc++;
#else
*pchDest++ = *pchSrc++;
#endif
if (c=='\r')
{
/* Eat multiple CRs if present. */
while (*pchSrc == '\r')
pchSrc++;
/* Eat line feeds following carriage return if
there are any.
*/
while (*pchSrc == '\n')
*pchSrc++;
/* Terminate the line. */
*(pchDest - 1) = 0;
fSameLine = FALSE;
}
else
{
if (c=='\0')
{
/* Backup to point to the 0 so the outer
loop terminates. */
pchSrc--;
fSameLine = FALSE;
}
}
i++;
if ( i >= (hChars - viRightMarginLen))
fSameLine = FALSE;
}
while (*(vpchPrintBuf+viLeftMarginLen)==' ')
vpchPrintBuf++;
if (!PrintLine ())
goto error0;
vpchPrintBuf=rgchPrintBuf;
}
}
DrUnlock (idr);
return TRUE;
error0:
DrUnlock(idr);
return FALSE;
}
/**** PrintHeading - print the heading if it hasn't been printed yet. */
BOOL APIENTRY PrintHeading (DT dt)
{
D3 d3;
if (vclnDate == 0)
{
/* The heading has not yet been printed - print it out
now since we now know that the date is not empty.
*/
/* First put out the lines between dates if this date is
not being printed at the top of a page.
*/
vclnPrinted++;
/* Convert the date into an ASCII string. */
GetD3FromDt (dt, &d3);
FillBuf (vpchPrintBuf, viLeftMarginLen, ' '); /* pad margin space
with blanks */
GetDateDisp (&d3, vpchPrintBuf + viLeftMarginLen);
if (!PrintLine ())
return FALSE;
if (!PrintBlankLn (CLNAFTERHEADING))
return FALSE;
}
return TRUE;
}
/**** PrintBlankLn */
INT APIENTRY PrintBlankLn (INT cln)
{
*vpchPrintBuf = '\0';
while (cln--)
if (!PrintLine ())
return FALSE;
return TRUE;
}
/**** PrintLine */
BOOL APIENTRY PrintLine ()
{
if (vfPrint)
{
/* print footer if bottom of page is reached */
if (vclnPrinted >= vclnPage)
{
PrintHeaderFooter(FALSE);
if (!NewPage ())
return FALSE;
viCurrentPage++;
PrintHeaderFooter(TRUE); /* print header */
vclnPrinted = vlnTop;
}
TextOut (vhDCPrint, 0, vclnPrinted * vcyPrintLineToLine,
vpchPrintBuf, lstrlen (vpchPrintBuf));
vclnPrinted++;
}
vclnDate++;
return TRUE;
}
/****************************************************************************
*
* BOOL PASCAL PrintHeaderFooter ( hdr )
*
* function : generates and formats the header/footer strings and copies
* them to the print buffer
*
* params : IN hdr : boolean indicating if header(TRUE) or footer(FALSE)
* is to be generated
*
* called by: Print(), PrintLine()
*
* returns : none
*
***************************************************************************/
BOOL APIENTRY PrintHeaderFooter(BOOL bHeader)
{
CHAR buf[80];
int len;
/* 1-bHeader gives 0 for header, 1 for footer. */
lstrcpy(buf, chPageText[1-bHeader]);
szHeadFoot=GlobalLock(hHeadFoot);
len=TranslateString(buf);
if (*szHeadFoot)
{
if (bHeader)
TextOut(vhDCPrint, dxLeft, dyHeadFoot - CharPrintHeight, szHeadFoot, len);
else
TextOut(vhDCPrint, dxLeft, yPrintRes-CharPrintHeight-dyHeadFoot, szHeadFoot, len);
}
GlobalUnlock(hHeadFoot);
return TRUE;
}
/***************************************************************************
* int TranslateString(char *src)
*
* purpose:
* translate a header/footer strings
*
* supports the following:
*
* && insert a & char
* &f current file name or (untitiled)
* &d date in Day Month Year
* &t time
* &p page number
* &p+num set first page number to num
*
* params:
* IN/OUT src this is the string to translate, gets filled with
* translate string. limited by len chars
* IN len # chars src pts to
*
* used by:
* Header Footer stuff
*
* uses:
* lots of c lib stuff
*
* restrictions:
* this function uses the following global data
*
* iPageNum
* text from main window caption
*
***************************************************************************/
int TranslateString(CHAR *src)
{
CHAR letters[15];
CHAR chBuff[3][80], buf[80];
CHAR *ptr, *dst=buf, *save_src=src;
INT page;
int nAlign=1, foo, nx,
nIndex[3];
struct tm *newtime;
time_t long_time;
nIndex[0]=0;
nIndex[1]=0;
nIndex[2]=0;
/* Get the time we need in case we use &t. */
time(&long_time);
newtime=localtime(&long_time);
LoadString(vhInstance, IDS_LETTERS, letters, 15);
while (*src) /* look at all of source */
{
while (*src && *src != '&')
{
chBuff[nAlign][nIndex[nAlign]]=*src++;
nIndex[nAlign] += 1;
}
if (*src == '&') /* is it the escape char? */
{
src++;
if (*src == letters[0] || *src == letters[1])
{ /* &f file name (no path) */
/* a bit of sleez... get the caption from
* the main window. search for the '-' and
* look two chars beyond, there is the
* file name or (untitiled) (cute hu?)
*/
GetWindowText(vhwnd0, buf, 80);
ptr=strchr(buf, '-') + 2;
/* Copy to the currently aligned string. */
lstrcpy((chBuff[nAlign]+nIndex[nAlign]), ptr);
/* Update insertion position. */
nIndex[nAlign] += lstrlen(ptr);
}
else
if (*src == letters[2] || *src == letters[3])
{ /* &P or &P+num page */
src++;
page = 0;
if (*src == '+') /* &p+num case */
{
src++;
while (isdigit(*src))
{
/* Convert to int on-the-fly*/
page = (10*page)+(UCHAR)(*src)-48;
src++;
}
}
_itoa(viCurrentPage+page, buf, 10);
lstrcpy((chBuff[nAlign]+nIndex[nAlign]), buf);
nIndex[nAlign] += lstrlen(buf);
src--;
}
else
if (*src == letters[4] || *src == letters[5])
{ /* &t time */
ptr = asctime(newtime);
/* extract time */
strncpy(chBuff[nAlign]+nIndex[nAlign], ptr+11, 8);
nIndex[nAlign] += 8;
}
else
if (*src == letters[6] || *src == letters[7])
{ /* &d date */
ptr = asctime(newtime);
/* extract day month day */
strncpy(chBuff[nAlign]+nIndex[nAlign], ptr, 11);
nIndex[nAlign] += 11;
/* extract year */
strncpy(chBuff[nAlign]+nIndex[nAlign], ptr+20, 4);
nIndex[nAlign] += 4;
}
else
if (*src == '&')
{ /* quote a single & */
chBuff[nAlign][nIndex[nAlign]]='&';
nIndex[nAlign] += 1;
}
else
/* Set the alignment for whichever has last occured. */
if (*src == letters[8] || *src == letters[9])
/* &c center */
nAlign=1;
else
if (*src == letters[10] || *src == letters[11])
/* &r right */
nAlign=2;
else
if (*src == letters[12] || *src == letters[13])
/* &d date */
nAlign=0;
src++;
}
}
/* Make sure all strings are null-terminated. */
for (nAlign=0; nAlign<3; nAlign++)
chBuff[nAlign][nIndex[nAlign]]=0;
/* Initialize Header/Footer string */
for (nx=0; nx<xCharPage; nx++)
*(szHeadFoot+nx)=32;
/* Copy Left aligned text. */
for (nx=0; nx < nIndex[0]; nx++)
*(szHeadFoot+nx)=chBuff[0][nx];
/* Calculate where the centered text should go. */
foo=(xCharPage-nIndex[1])/2;
for (nx=0; nx<nIndex[1]; nx++)
*(szHeadFoot+foo+nx)=(CHAR)chBuff[1][nx];
/* Calculate where the right aligned text should go. */
foo=xCharPage-nIndex[2];
for (nx=0; nx<nIndex[2]; nx++)
*(szHeadFoot+foo+nx)=(CHAR)chBuff[2][nx];
return lstrlen(szHeadFoot);
}
/**** NewPage */
BOOL APIENTRY NewPage ()
{
INT iErr;
if ((iErr = Escape(vhDCPrint, NEWFRAME, 0, NULL, 0)) < 0) {
EndPrint();
CalPrintAlert(iErr);
return FALSE;
}
vclnPrinted = 0;
return TRUE;
}
/**** BeginPrint - code taken from Cardfile - inprint.c - modified
as necessary. Returns 0 if successful, SP_errorcode (which is
< 0 for error.
*/
INT APIENTRY BeginPrint ()
{
CHAR rgchWindowText [CCHSZWINDOWTEXTMAX];
INT iErr;
/* If can't create print DC, return FALSE to indicate can't print. */
if (!(vhDCPrint = GetPrinterDC()))
return (SP_ERROR);
/* Show the hour glass cursor. */
HourGlassOn ();
vfAbortPrint = FALSE;
SetAbortProc(vhDCPrint, FnProcAbortPrint);
GetWindowText (vhwnd0, rgchWindowText, CCHSZWINDOWTEXTMAX);
/* Gotta disable the window before doing the start doc so that the user
* can't quickly do multiple prints.
*/
EnableWindow (vhwnd0, FALSE);
if ((iErr = Escape(vhDCPrint, STARTDOC, lstrlen((LPSTR)rgchWindowText),
(LPSTR)rgchWindowText, (LPSTR)0)) < 0) {
EnableWindow (vhwnd0, TRUE);
DeleteDC(vhDCPrint);
HourGlassOff();
return iErr;
}
vhwndAbortPrint = CreateDialog(vhInstance, MAKEINTRESOURCE(IDD_ABORTPRINT),
vhwnd0,FnDlgAbortPrint);
return (0);
}
/**** EndPrint - code taken from Cardfile - inprint.c - modified
as necessary.
*/
VOID APIENTRY EndPrint ()
{
if (!vfAbortPrint)
Escape(vhDCPrint, ENDDOC, 0, (LPSTR)0, (LPSTR)0);
/* The previous Escape could have changed the value of vfAbortPrint;
* So, this has to be tested again;
* Fix for Bug #6029 --SANKAR-- 11-9-89
*/
if(!vfAbortPrint)
DestroyAbortWnd();
DeleteDC (vhDCPrint);
/* The waiting is over. */
HourGlassOff ();
}
/**** FnProcAbortPrint - code taken from Cardfile - inprint.c - modified
as necessary.
*/
INT APIENTRY FnProcAbortPrint (
HDC hDC,
INT iReserved)
{
MSG msg;
while (!vfAbortPrint && PeekMessage(&msg, NULL, 0L, 0L, TRUE))
if (vhwndAbortPrint == NULL || !IsDialogMessage(vhwndAbortPrint, &msg))
{
TranslateMessage (&msg);
DispatchMessage (&msg);
}
return (!vfAbortPrint);
}
/**** FnDlgAbortPrint - code taken from Cardfile - inprint.c - modified
as necessary.
*/
INT_PTR CALLBACK FnDlgAbortPrint (
HWND hwnd,
UINT msg,
WPARAM wParam,
LPARAM lParam)
{
static HMENU hMenuSys;
switch (msg)
{
case WM_COMMAND:
vfAbortPrint = TRUE;
DestroyAbortWnd();
vhwndAbortPrint = NULL;
return (TRUE);
case WM_INITDIALOG:
hMenuSys = GetSystemMenu (hwnd, FALSE);
SetDlgItemText (hwnd, IDCN_PATH,
(LPSTR)PFileInPath (vszFileSpec));
CalSetFocus (hwnd);
return (TRUE);
case WM_INITMENU:
EnableMenuItem (hMenuSys, SC_CLOSE, MF_GRAYED);
return(TRUE);
}
return(FALSE);
}
/**** Enable Tiled window, THEN destroy dialog window. */
VOID DestroyAbortWnd()
{
EnableWindow (vhwnd0, TRUE);
DestroyWindow (vhwndAbortPrint);
vhwndAbortPrint = NULL;
}
/**** Post printing error message box */
VOID APIENTRY CalPrintAlert(INT iErr)
{
INT iszErr;
/* Map error code to string index */
if (iErr == SP_OUTOFDISK)
iszErr = IDS_NEDSTP;
else if (iErr == SP_OUTOFMEMORY)
iszErr = IDS_NEMTP;
else iszErr = IDS_CANNOTPRINT;
AlertBox (vrgsz[iszErr], PFileInPath (vszFileSpec),
MB_APPLMODAL | MB_OK | MB_ICONEXCLAMATION);
}
/* ** GetPrinterDc()
Get Dc for current device on current output port according to
info in win.ini.
returns
DC if success
NULL if failure
*/
HDC APIENTRY GetPrinterDC()
{
extern BOOL bPrinterSetupDone;
LPDEVMODE lpDevMode;
LPDEVNAMES lpDevNames;
if(!bPrinterSetupDone){ /* Retrieve default printer if none selected. */
vPD.Flags = PD_RETURNDEFAULT|PD_PRINTSETUP;
vPD.hDevNames = NULL;
vPD.hDevMode = NULL;
PrintDlg(&vPD);
}
if(!vPD.hDevNames)
return NULL;
lpDevNames = (LPDEVNAMES)GlobalLock(vPD.hDevNames);
if(vPD.hDevMode)
lpDevMode = (LPDEVMODE)GlobalLock(vPD.hDevMode);
else
lpDevMode = NULL;
/* For pre 3.0 Drivers,hDevMode will be null from Commdlg so lpDevMode
* will be NULL after GlobalLock()
*/
vPD.hDC = CreateDC((LPSTR)lpDevNames+lpDevNames->wDriverOffset,
(LPSTR)lpDevNames+lpDevNames->wDeviceOffset,
(LPSTR)lpDevNames+lpDevNames->wOutputOffset,
lpDevMode);
GlobalUnlock(vPD.hDevNames);
if (vPD.hDevMode)
GlobalUnlock(vPD.hDevMode);
return vPD.hDC;
}
/****************************************************************************
** IsDefaultPrinterStillValid()
** The user might setup the app for a particular printer and a port
** using the Printer Setup available in the application command menu;
** But later, he might go to control panel and delete that printer
** driver altogether or he might connect it to a different port;
** So, the application must process the WININICHANGE message and at that
** time, it must check whether the printer setup is still valid or not!
** This function is used to make that check;
** The input parameter is a string containing the printer name, driver,
** port selected by the printer setup; This function checks if the printer
** name is still present under the [Devices] section of Win.INI and if so,
** it will check if the port selected is listed among the ports to which
** this printer is connected; If not, it will automatically select the
** first port listed as the default port and modify the input "lpszPrinter"
** string accordingly;
** If the default printer is not listed in WIN.INI at all, then this
** function return FALSE;
** Fix for Bug #5607 -- SANKAR -- 10-30-89
**
****************************************************************************/
BOOL FAR APIENTRY IsDefaultPrinterStillValid(LPSTR lpszPrinter)
{
CHAR PrinterBuff[128];
CHAR DeviceBuff[128];
LPSTR lpPort; /* Default port name */
LPSTR lpFirstPort = NULL;
LPSTR lpch;
LPSTR lpListedPorts;
/* lpszPrinter contains "PrinterName,DriverName,Port" */
lstrcpy(PrinterBuff, lpszPrinter); /* Make a local copy of the default printer name */
/* Search for the end of printer name */
for(lpch = PrinterBuff; (*lpch)&&(*lpch != ','); lpch = AnsiNext(lpch))
;
if(*lpch)
*lpch++ = '\0';
/* Skip the Driver name; We do not need it! */
while(*lpch && *lpch <= ' ') /* Skip the blanks preceeding the driver name */
lpch = AnsiNext(lpch);
while(*lpch && *lpch != ',' && *lpch > ' ') /* Search for ',' following driver name */
lpch = AnsiNext(lpch);
while (*lpch && (*lpch <= ' ' || *lpch == ',')) /* Search for begining of port name */
lpch = AnsiNext(lpch);
lpPort = lpch; /* Default port name */
/* Search for the printer name among the [devices] section */
if (!GetProfileString("devices", PrinterBuff, "", DeviceBuff, 128))
return(FALSE); /* Default printer no longer exists */
lpch = DeviceBuff;
/* Skip the Driver filename */
while(*lpch && *lpch != ',')
lpch = AnsiNext(lpch);
while(*lpch)
{
/* Skip all blanks */
while(*lpch && (*lpch <= ' ' || *lpch == ','))
lpch = AnsiNext(lpch);
lpListedPorts = lpch;
if(!lpFirstPort)
lpFirstPort = lpch; /* Save the first port in the list */
/* Search for the end of the Port name */
while(*lpch && *lpch != ',' && *lpch > ' ')
lpch = AnsiNext(lpch);
if(*lpch)
*lpch++ = '\0';
/* Check if the port names are the same */
if(lstrcmp(lpPort, lpListedPorts) == 0)
return(TRUE); /* Default port exists among the listed ones */
}
/* The default port does not exist among the listed ports; So, change
* the default port to the first port in the list;
*/
if(*lpFirstPort)
{
/* Search for the end of the printer name */
for (lpch = szPrinter; (*lpch)&&(*lpch != ','); lpch = AnsiNext(lpch))
;
/* Skip the driver file name */
if(*lpch)
lpch++;
while(*lpch && *lpch != ',')
lpch = AnsiNext(lpch);
if(*lpch)
lpch++;
lstrcpy(lpch, lpFirstPort);
return(TRUE);
}
return(FALSE);
}