860 lines
26 KiB
C
860 lines
26 KiB
C
|
/************************************************************/
|
|||
|
/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
|
|||
|
/************************************************************/
|
|||
|
|
|||
|
/* This routine sets up the screen position used by Word relative to the
|
|||
|
current device. */
|
|||
|
|
|||
|
#define NOGDICAPMASKS
|
|||
|
#define NOVIRTUALKEYCODES
|
|||
|
#define NOWINSTYLES
|
|||
|
#define NOCLIPBOARD
|
|||
|
#define NOCTLMGR
|
|||
|
#define NOMENUS
|
|||
|
#define NOICON
|
|||
|
#define NOKEYSTATE
|
|||
|
#define NOSYSCOMMANDS
|
|||
|
#define NOSHOWWINDOW
|
|||
|
#define NOATOM
|
|||
|
#define NODRAWTEXT
|
|||
|
#define NOMSG
|
|||
|
#define NOOPENFILE
|
|||
|
#define NOSCROLL
|
|||
|
#define NOSOUND
|
|||
|
/*#define NOTEXTMETRIC*/
|
|||
|
#define NOWH
|
|||
|
#define NOWINOFFSETS
|
|||
|
#define NOCOMM
|
|||
|
#include <windows.h>
|
|||
|
|
|||
|
#include "mw.h"
|
|||
|
#include "ch.h"
|
|||
|
#include "cmddefs.h"
|
|||
|
#include "scrndefs.h"
|
|||
|
#include "dispdefs.h"
|
|||
|
#include "wwdefs.h"
|
|||
|
#include "printdef.h"
|
|||
|
#include "str.h"
|
|||
|
#include "docdefs.h"
|
|||
|
#include "propdefs.h"
|
|||
|
#include "machdefs.h"
|
|||
|
#include "fontdefs.h"
|
|||
|
#include "commdlg.h"
|
|||
|
|
|||
|
#ifdef DBCS
|
|||
|
#include "kanji.h"
|
|||
|
#endif
|
|||
|
|
|||
|
unsigned dxaPrOffset;
|
|||
|
unsigned dyaPrOffset;
|
|||
|
extern HCURSOR vhcIBeam;
|
|||
|
|
|||
|
|
|||
|
BOOL FSetWindowColors()
|
|||
|
{
|
|||
|
/* This routine sets up the global variables rgbBkgrnd, rgbText, hbrBkgrnd,
|
|||
|
and ropErase, depending on what the current system colors are. hWnd is a
|
|||
|
handle to a window on top. */
|
|||
|
|
|||
|
extern long ropErase;
|
|||
|
extern long rgbBkgrnd;
|
|||
|
extern long rgbText;
|
|||
|
extern HBRUSH hbrBkgrnd;
|
|||
|
|
|||
|
long rgbWindow;
|
|||
|
long rgbWindowText;
|
|||
|
HDC hDC;
|
|||
|
|
|||
|
/* Get the color of the background and the text. */
|
|||
|
rgbWindow = GetSysColor(COLOR_WINDOW);
|
|||
|
rgbWindowText = GetSysColor(COLOR_WINDOWTEXT);
|
|||
|
|
|||
|
/* If the colors haven't changed, then there is nothing to do. */
|
|||
|
if (rgbWindow == rgbBkgrnd && rgbWindowText == rgbText)
|
|||
|
{
|
|||
|
return (FALSE);
|
|||
|
}
|
|||
|
|
|||
|
/* Convert the window colors into "pure" colors. */
|
|||
|
if ((hDC = GetDC(NULL)) == NULL)
|
|||
|
{
|
|||
|
return (FALSE);
|
|||
|
}
|
|||
|
rgbBkgrnd = GetNearestColor(hDC, rgbWindow);
|
|||
|
rgbText = GetNearestColor(hDC, rgbWindowText);
|
|||
|
ReleaseDC(NULL, hDC);
|
|||
|
Assert((rgbBkgrnd & 0xFF000000) == 0 && (rgbText & 0xFF000000) == 0);
|
|||
|
|
|||
|
/* Set up the brush for the background. */
|
|||
|
if ((hbrBkgrnd = CreateSolidBrush(rgbBkgrnd)) == NULL)
|
|||
|
{
|
|||
|
/* Can't make the background brush; use the white brush. */
|
|||
|
hbrBkgrnd = GetStockObject(WHITE_BRUSH);
|
|||
|
rgbBkgrnd = RGB(0xff, 0xff, 0xff);
|
|||
|
}
|
|||
|
|
|||
|
/* Compute the raster op to erase the screen. */
|
|||
|
if (rgbBkgrnd == RGB(0xff, 0xff, 0xff))
|
|||
|
{
|
|||
|
/* WHITENESS is faster than copying a white brush. */
|
|||
|
ropErase = WHITENESS;
|
|||
|
}
|
|||
|
else if (rgbBkgrnd == RGB(0, 0, 0))
|
|||
|
{
|
|||
|
/* BLACKNESS is faster than copying a black brush. */
|
|||
|
ropErase = BLACKNESS;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
/* For everything else, we have to copy the brush. */
|
|||
|
ropErase = PATCOPY;
|
|||
|
}
|
|||
|
return (TRUE);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
int FSetScreenConstants()
|
|||
|
{
|
|||
|
/* This routine sets the value of a variety of global variables that used to
|
|||
|
be constants in Mac Word, but are now varibles because screen resolution can
|
|||
|
only be determined at run time. */
|
|||
|
|
|||
|
extern HWND hParentWw;
|
|||
|
extern HDC vhDCPrinter;
|
|||
|
extern HBITMAP hbmNull;
|
|||
|
extern int dxpLogInch;
|
|||
|
extern int dypLogInch;
|
|||
|
extern int dxpLogCm;
|
|||
|
extern int dypLogCm;
|
|||
|
extern int dypMax;
|
|||
|
extern int xpRightMax;
|
|||
|
extern int xpSelBar;
|
|||
|
extern int xpMinScroll;
|
|||
|
extern int xpRightLim;
|
|||
|
extern int dxpInfoSize;
|
|||
|
extern int ypMaxWwInit;
|
|||
|
extern int ypMaxAll;
|
|||
|
extern int dypMax;
|
|||
|
extern int dypAveInit;
|
|||
|
extern int dypWwInit;
|
|||
|
extern int dypBand;
|
|||
|
extern int ypSubSuper;
|
|||
|
#ifdef KINTL
|
|||
|
extern int dxaAdjustPerCm;
|
|||
|
#endif /* ifdef KINTL */
|
|||
|
|
|||
|
HDC hDC;
|
|||
|
#ifdef KINTL
|
|||
|
int xaIn16CmFromA, xaIn16CmFromP;
|
|||
|
#endif /* ifdef KINTL */
|
|||
|
|
|||
|
|
|||
|
/* First, let's create and save an empty bitmap. */
|
|||
|
if ((hbmNull = CreateBitmap(1, 1, 1, 1, (LPSTR)NULL)) == NULL)
|
|||
|
{
|
|||
|
return (FALSE);
|
|||
|
}
|
|||
|
|
|||
|
/* Get the DC of the parent window to play with. */
|
|||
|
if ((hDC = GetDC(hParentWw)) == NULL)
|
|||
|
{
|
|||
|
return (FALSE);
|
|||
|
}
|
|||
|
|
|||
|
/* Save away the height of the screen. */
|
|||
|
dypMax = GetDeviceCaps(hDC, VERTRES);
|
|||
|
|
|||
|
/* determine screen pixel dimensions */
|
|||
|
dxpLogInch = GetDeviceCaps(hDC, LOGPIXELSX);
|
|||
|
dypLogInch = GetDeviceCaps(hDC, LOGPIXELSY);
|
|||
|
|
|||
|
/* convert above to centimeters */
|
|||
|
dxpLogCm = MultDiv(dxpLogInch, czaCm, czaInch);
|
|||
|
dypLogCm = MultDiv(dypLogInch, czaCm, czaInch);
|
|||
|
|
|||
|
#ifdef KINTL
|
|||
|
/* Now, calculate the kick back amount of xa per cm. */
|
|||
|
xaIn16CmFromA = 16 * czaCm;
|
|||
|
xaIn16CmFromP = MultDiv(16 * dxpLogCm, czaInch, dxpLogInch);
|
|||
|
dxaAdjustPerCm = (xaIn16CmFromP - xaIn16CmFromA) / 16;
|
|||
|
#endif /* ifdef KINTL */
|
|||
|
|
|||
|
#ifdef SYSENDMARK
|
|||
|
{
|
|||
|
extern HFONT vhfSystem;
|
|||
|
extern struct FMI vfmiSysScreen;
|
|||
|
extern int vrgdxpSysScreen[];
|
|||
|
TEXTMETRIC tm;
|
|||
|
|
|||
|
/* The use of height below is OK, because we are
|
|||
|
just trying to get the reference height. */
|
|||
|
GetTextMetrics(hDC, (LPTEXTMETRIC) &tm);
|
|||
|
|
|||
|
/* Set up the fields in vfmiSysScreen for the later use. */
|
|||
|
vfmiSysScreen.dxpOverhang = tm.tmOverhang;
|
|||
|
#if defined(KOREA)
|
|||
|
if ((tm.tmPitchAndFamily & 1) == 0)
|
|||
|
vfmiSysScreen.dxpSpace = tm.tmAveCharWidth;
|
|||
|
else
|
|||
|
#endif
|
|||
|
vfmiSysScreen.dxpSpace = LOWORD(GetTextExtent(hDC,
|
|||
|
(LPSTR)" ", 1)) - tm.tmOverhang;
|
|||
|
vfmiSysScreen.dypAscent = tm.tmAscent;
|
|||
|
vfmiSysScreen.dypDescent = tm.tmDescent;
|
|||
|
vfmiSysScreen.dypBaseline = tm.tmAscent;
|
|||
|
vfmiSysScreen.dypLeading = tm.tmExternalLeading;
|
|||
|
|
|||
|
#ifdef DBCS /* KenjiK '90-10-29 */
|
|||
|
/* We must setup appended members of structure. */
|
|||
|
vfmiSysScreen.dxpDBCS = dxpNil;
|
|||
|
#endif /* DBCS */
|
|||
|
|
|||
|
bltc(vrgdxpSysScreen, dxpNil, chFmiMax - chFmiMin);
|
|||
|
vfmiSysScreen.mpchdxp = vrgdxpSysScreen - chFmiMin;
|
|||
|
|
|||
|
/* This is as good a place to get a handle to the system font as
|
|||
|
any other for LoadFont().....? */
|
|||
|
/* Throw away the old one first, if applicable. */
|
|||
|
if (vhfSystem != NULL) {
|
|||
|
DeleteObject((HANDLE) vhfSystem);
|
|||
|
}
|
|||
|
vhfSystem = GetStockObject(SYSTEM_FONT);
|
|||
|
Assert(vhfSystem != NULL);
|
|||
|
}
|
|||
|
#endif /* SYSENDMARK */
|
|||
|
|
|||
|
/* We don't need the DC any more. */
|
|||
|
ReleaseDC(hParentWw, hDC);
|
|||
|
|
|||
|
/* Calculate the positions. */
|
|||
|
xpSelBar = MultDiv(xaSelBar, dxpLogInch, czaInch);
|
|||
|
xpRightMax = MultDiv(xaRightMax, dxpLogInch, czaInch);
|
|||
|
xpRightLim = xpRightMax - (GetSystemMetrics(SM_CXFULLSCREEN) - xpSelBar -
|
|||
|
GetSystemMetrics(SM_CXVSCROLL) + GetSystemMetrics(SM_CXBORDER));
|
|||
|
xpMinScroll = ((MultDiv(xaMinScroll, dxpLogInch, czaInch)+7)/8)*8;
|
|||
|
dxpInfoSize = MultDiv(dxaInfoSize, dxpLogInch, czaInch);
|
|||
|
ypMaxWwInit = MultDiv(yaMaxWwInit, dypLogInch, czaInch);
|
|||
|
ypMaxAll = MultDiv(yaMaxAll, dypLogInch, czaInch);
|
|||
|
dypWwInit = MultDiv(dyaWwInit, dypLogInch, czaInch);
|
|||
|
dypBand = MultDiv(dyaBand, dypLogInch, czaInch);
|
|||
|
ypSubSuper = MultDiv(yaSubSuper, dypLogInch, czaInch);
|
|||
|
|
|||
|
/* dypAveInit is a very rough guess as to the height + leading of a 12 point
|
|||
|
font. */
|
|||
|
dypAveInit = MultDiv(cya12pt, dypLogInch, czaInch);
|
|||
|
|
|||
|
/* Time to search the user profile to find a printer. */
|
|||
|
if (!FGetPrinterFromProfile())
|
|||
|
{
|
|||
|
return (FALSE);
|
|||
|
}
|
|||
|
GetPrinterDC(FALSE);
|
|||
|
|
|||
|
return (TRUE);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
BOOL FGetPrinterFromProfile()
|
|||
|
{
|
|||
|
/* This routine searches the user profile for the name of a printer to use
|
|||
|
and records the name in the printer heap strings. FALSE is returned iff a
|
|||
|
memory error is encountered. */
|
|||
|
|
|||
|
extern HWND hParentWw;
|
|||
|
extern CHAR szWindows[];
|
|||
|
extern CHAR szDevice[];
|
|||
|
extern CHAR szDevices[];
|
|||
|
extern BOOL vfPrDefault;
|
|||
|
extern CHAR (**hszPrinter)[];
|
|||
|
extern CHAR (**hszPrDriver)[];
|
|||
|
extern CHAR (**hszPrPort)[];
|
|||
|
|
|||
|
CHAR *index(CHAR *, int);
|
|||
|
CHAR *bltbyte(CHAR *, CHAR *, int);
|
|||
|
|
|||
|
CHAR szPrinter[cchMaxProfileSz];
|
|||
|
CHAR szDevSpec[cchMaxProfileSz];
|
|||
|
CHAR chNull = '\0';
|
|||
|
CHAR *pch;
|
|||
|
CHAR *pchDriver;
|
|||
|
CHAR *pchPort;
|
|||
|
int cwsz;
|
|||
|
|
|||
|
if (!vfPrDefault && hszPrinter != NULL && hszPrPort != NULL)
|
|||
|
{
|
|||
|
/* If the user has selected a printer, then look for that printer in the
|
|||
|
user profile. */
|
|||
|
|
|||
|
int cPort;
|
|||
|
int iPort;
|
|||
|
|
|||
|
bltsz(&(**hszPrinter)[0], szPrinter);
|
|||
|
GetProfileString((LPSTR)szDevices, (LPSTR)szPrinter, (LPSTR)&chNull,
|
|||
|
(LPSTR)szDevSpec, cchMaxProfileSz);
|
|||
|
cPort = ParseDeviceSz(szDevSpec, &pchPort, &pchDriver);
|
|||
|
|
|||
|
/* See if we can find the old port in the list. */
|
|||
|
for (iPort = 0, pch = pchPort; iPort < cPort; iPort++)
|
|||
|
{
|
|||
|
if (WCompSz(&(**hszPrPort)[0], pch) == 0)
|
|||
|
{
|
|||
|
pchPort = pch;
|
|||
|
goto GotPrinter;
|
|||
|
}
|
|||
|
pch += CchSz(pch);
|
|||
|
}
|
|||
|
|
|||
|
/* If the port for the current printer has changed, then it must have
|
|||
|
been done by the control panel and we haven't the foggiest idea what
|
|||
|
it is, so grab the first port. */
|
|||
|
goto UnknownPort;
|
|||
|
}
|
|||
|
|
|||
|
/* Is there a default Windows printer? */
|
|||
|
GetProfileString((LPSTR)szWindows, (LPSTR)szDevice, (LPSTR)&chNull,
|
|||
|
(LPSTR)szPrinter, cchMaxProfileSz);
|
|||
|
|
|||
|
#ifdef WIN30
|
|||
|
/* Don't make the assumption like Write 2 did and just grab ANY printer.
|
|||
|
I know, I know -- there's unnecessary code left down below but didn't
|
|||
|
want to mess any special case code up ..pault */
|
|||
|
if ((pch = index(szPrinter, ',')) == 0)
|
|||
|
goto BailOut;
|
|||
|
#endif
|
|||
|
|
|||
|
/* Does this entry contain the port and driver information. */
|
|||
|
if ((pch = index(szPrinter, ',')) != 0)
|
|||
|
{
|
|||
|
/* Remove any trailing spaces from the printer name. */
|
|||
|
CHAR *pchT;
|
|||
|
|
|||
|
for (pchT = pch; *pchT == ' ' && pchT > &szPrinter[0]; pchT--);
|
|||
|
*pchT = '\0';
|
|||
|
|
|||
|
/* Parse out the port and the driver names. */
|
|||
|
ParseDeviceSz(pch + 1, &pchPort, &pchDriver);
|
|||
|
}
|
|||
|
|
|||
|
else
|
|||
|
{
|
|||
|
if (szPrinter[0] == '\0')
|
|||
|
{
|
|||
|
/* No default printer; grab the first one in the list. */
|
|||
|
GetProfileString((LPSTR)szDevices, (LPSTR)NULL, (LPSTR)&chNull,
|
|||
|
(LPSTR)szPrinter, cchMaxProfileSz);
|
|||
|
|
|||
|
if (szPrinter[0] == '\0')
|
|||
|
{
|
|||
|
BailOut:
|
|||
|
hszPrinter = hszPrDriver = hszPrPort = NULL;
|
|||
|
return (TRUE);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
UnknownPort:
|
|||
|
/* Find the device driver and the port of the printer. */
|
|||
|
GetProfileString((LPSTR)szDevices, (LPSTR)szPrinter, (LPSTR)&chNull,
|
|||
|
(LPSTR)szDevSpec, cchMaxProfileSz);
|
|||
|
if (szPrinter[0] == '\0')
|
|||
|
{
|
|||
|
goto BailOut;
|
|||
|
}
|
|||
|
ParseDeviceSz(szDevSpec, &pchPort, &pchDriver);
|
|||
|
}
|
|||
|
|
|||
|
GotPrinter:
|
|||
|
/* Save the names of the printer, printer driver, and the port. */
|
|||
|
if (FNoHeap(hszPrinter = (CHAR (**)[])HAllocate(cwsz =
|
|||
|
CwFromCch(CchSz(szPrinter)))))
|
|||
|
{
|
|||
|
goto NoHszPrinter;
|
|||
|
}
|
|||
|
blt(szPrinter, &(**hszPrinter)[0], cwsz);
|
|||
|
if (FNoHeap(hszPrDriver = (CHAR (**)[])HAllocate(cwsz =
|
|||
|
CwFromCch(CchSz(pchDriver)))))
|
|||
|
{
|
|||
|
goto NoHszPrDriver;
|
|||
|
}
|
|||
|
blt(pchDriver, &(**hszPrDriver)[0], cwsz);
|
|||
|
if (FNoHeap(hszPrPort = (CHAR (**)[])HAllocate(cwsz =
|
|||
|
CwFromCch(CchSz(pchPort)))))
|
|||
|
{
|
|||
|
FreeH(hszPrDriver);
|
|||
|
NoHszPrDriver:
|
|||
|
FreeH(hszPrinter);
|
|||
|
NoHszPrinter:
|
|||
|
hszPrinter = hszPrDriver = hszPrPort = NULL;
|
|||
|
return (FALSE);
|
|||
|
}
|
|||
|
blt(pchPort, &(**hszPrPort)[0], cwsz);
|
|||
|
|
|||
|
return (TRUE);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
int ParseDeviceSz(sz, ppchPort, ppchDriver)
|
|||
|
CHAR sz[];
|
|||
|
CHAR **ppchPort;
|
|||
|
CHAR **ppchDriver;
|
|||
|
{
|
|||
|
/* This routine takes a string that came from the "device" entry in the user
|
|||
|
profile and returns in *ppchPort and *ppchDriver pointers to the port and
|
|||
|
driver sutible for a CreateDC() call. If no port is found in the string,
|
|||
|
*ppchPort will point to a string containing the name of the null device.
|
|||
|
This routine returns the number of ports for this printer (separated by null
|
|||
|
characters in the string pointed at by *ppchPort). NOTE: sz may be modified
|
|||
|
by this routine, and the string at *ppchPort may not be a substring of sz
|
|||
|
and should not be modified by the caller. */
|
|||
|
|
|||
|
extern CHAR stBuf[];
|
|||
|
extern CHAR szNul[];
|
|||
|
CHAR *index(CHAR *, int);
|
|||
|
CHAR *bltbyte(CHAR *, CHAR *, int);
|
|||
|
|
|||
|
register CHAR *pch;
|
|||
|
int cPort = 0;
|
|||
|
|
|||
|
/* Remove any leading spaces from the string. */
|
|||
|
for (pch = &sz[0]; *pch == ' '; pch++);
|
|||
|
|
|||
|
/* The string starts with the driver name. */
|
|||
|
*ppchDriver = pch;
|
|||
|
|
|||
|
/* The next space or comma terminates the driver name. */
|
|||
|
for ( ; *pch != ' ' && *pch != ',' && *pch != '\0'; pch++);
|
|||
|
|
|||
|
/* If the string does not have a port associated with it, then the port
|
|||
|
must be the null device. */
|
|||
|
if (*pch == '\0')
|
|||
|
{
|
|||
|
/* Set the port name to "None". */
|
|||
|
*ppchPort = &szNul[0];
|
|||
|
cPort = 1;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
/* As far as we can tell, the port name is valid; parse it from the
|
|||
|
driver name. */
|
|||
|
if (*pch == ',')
|
|||
|
{
|
|||
|
*pch++ = '\0';
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
/* Find that comma separating the driver and the port. */
|
|||
|
*pch++ = '\0';
|
|||
|
for ( ; *pch != ',' && *pch != '\0'; pch++);
|
|||
|
if (*pch == ',')
|
|||
|
{
|
|||
|
pch++;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* Remove any leading spaces from the port name. */
|
|||
|
for ( ; *pch == ' '; pch++);
|
|||
|
|
|||
|
/* Check to see if there is really a port name. */
|
|||
|
if (*pch == '\0')
|
|||
|
{
|
|||
|
/* Set the port name to "None". */
|
|||
|
*ppchPort = &szNul[0];
|
|||
|
cPort = 1;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
/* Set the pointer to the port name. */
|
|||
|
*ppchPort = pch;
|
|||
|
|
|||
|
while (*pch != '\0')
|
|||
|
{
|
|||
|
register CHAR *pchT = pch;
|
|||
|
|
|||
|
/* Increment the number of ports found for this printer. */
|
|||
|
cPort++;
|
|||
|
|
|||
|
/* Remove any trailing spaces from the port name. */
|
|||
|
for ( ; *pchT != ' ' && *pchT != ','; pchT++)
|
|||
|
{
|
|||
|
if (*pchT == '\0')
|
|||
|
{
|
|||
|
goto EndFound;
|
|||
|
}
|
|||
|
}
|
|||
|
*pchT++ = '\0';
|
|||
|
pch = pchT;
|
|||
|
|
|||
|
/* Remove any leading spaces in the next port name. */
|
|||
|
for ( ; *pchT == ' '; pchT++);
|
|||
|
|
|||
|
/* Throw out the leading spaces. */
|
|||
|
bltbyte(pchT, pch, CchSz(pchT));
|
|||
|
}
|
|||
|
EndFound:;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* Parse the ".drv" out of the driver. */
|
|||
|
{
|
|||
|
extern CHAR szExtDrv[];
|
|||
|
if ((pch = index(*ppchDriver, '.')) != 0
|
|||
|
&& FRgchSame(pch, szExtDrv, CchSz (szExtDrv) - 1))
|
|||
|
{
|
|||
|
*pch = '\0';
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return (cPort);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
SetPrintConstants()
|
|||
|
{
|
|||
|
/* This routine sets the scaling/aspect constants for the printer described
|
|||
|
in vhDCPrinter. */
|
|||
|
|
|||
|
extern HDC vhDCPrinter;
|
|||
|
extern BOOL vfPrinterValid;
|
|||
|
extern int dxpPrPage;
|
|||
|
extern int dypPrPage;
|
|||
|
extern int dxaPrPage;
|
|||
|
extern int dyaPrPage;
|
|||
|
extern int dxpLogInch;
|
|||
|
extern int dypLogInch;
|
|||
|
extern int ypSubSuperPr;
|
|||
|
|
|||
|
if (vfPrinterValid && vhDCPrinter != NULL)
|
|||
|
{
|
|||
|
POINT rgpt[2];
|
|||
|
|
|||
|
/* Get the dimensions of the printer in pixels. */
|
|||
|
dxpPrPage = rgpt[1].x = GetDeviceCaps(vhDCPrinter, HORZRES);
|
|||
|
dypPrPage = rgpt[1].y = GetDeviceCaps(vhDCPrinter, VERTRES);
|
|||
|
|
|||
|
/* Put the printer in twips mode to find the dimensions in twips. */
|
|||
|
SetMapMode(vhDCPrinter, MM_TWIPS);
|
|||
|
rgpt[0].x = rgpt[0].y = 0;
|
|||
|
DPtoLP(vhDCPrinter, (LPPOINT)rgpt, 2);
|
|||
|
|
|||
|
#if WINVER >= 0x300
|
|||
|
/* Weird Win bug that we can't decide on the corrective action -- sometimes
|
|||
|
DPtoLP returns x8000 here! What's that mean? Well it's SUPPOSED to be
|
|||
|
a large negative number ..pault */
|
|||
|
|
|||
|
if (rgpt[1].x == 0x8000)
|
|||
|
rgpt[1].x = -(0x7fff);
|
|||
|
if (rgpt[1].y == 0x8000)
|
|||
|
rgpt[1].y = -(0x7fff);
|
|||
|
#endif
|
|||
|
|
|||
|
if ((dxaPrPage = rgpt[1].x - rgpt[0].x) < 0)
|
|||
|
{
|
|||
|
dxaPrPage = -dxaPrPage;
|
|||
|
}
|
|||
|
if ((dyaPrPage = rgpt[0].y - rgpt[1].y) < 0)
|
|||
|
{
|
|||
|
dyaPrPage = -dyaPrPage;
|
|||
|
}
|
|||
|
SetMapMode(vhDCPrinter, MM_TEXT);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
/* Pretend the printer is just like the screen. */
|
|||
|
dxaPrPage = dyaPrPage = czaInch;
|
|||
|
dxpPrPage = dxpLogInch;
|
|||
|
dypPrPage = dypLogInch;
|
|||
|
}
|
|||
|
|
|||
|
/* ypSubSuperPr is the offset for subscript and supercript font on the
|
|||
|
printer. */
|
|||
|
ypSubSuperPr = MultDiv(yaSubSuper, dypPrPage, dyaPrPage);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
GetPrinterDC(fDC)
|
|||
|
BOOL fDC;
|
|||
|
{
|
|||
|
/* This routine sets vhDCPrinter to a new printer DC or IC. If fDC is TRUE,
|
|||
|
a new DC is created; otherwise, a new IC is created. In addition, all
|
|||
|
global variables dependent on the printer DC are changed. */
|
|||
|
|
|||
|
extern HDC vhDCPrinter;
|
|||
|
extern BOOL vfPrinterValid;
|
|||
|
extern CHAR (**hszPrinter)[];
|
|||
|
extern CHAR (**hszPrDriver)[];
|
|||
|
extern CHAR (**hszPrPort)[];
|
|||
|
extern HWND hParentWw;
|
|||
|
extern int docCur;
|
|||
|
extern struct DOD (**hpdocdod)[];
|
|||
|
extern BOOL vfWarnMargins;
|
|||
|
extern BOOL vfInitializing;
|
|||
|
extern PRINTDLG PD;
|
|||
|
|
|||
|
BOOL fCreateError = FALSE;
|
|||
|
|
|||
|
|
|||
|
/* We now pass the local PrinterSetup settings to CreateDC/CreateIC
|
|||
|
since Write's settings can differ from the global ones ..pault */
|
|||
|
LPSTR lpDevmodeData=NULL;
|
|||
|
|
|||
|
Assert(vhDCPrinter == NULL);
|
|||
|
|
|||
|
/* Get a new printer DC. */
|
|||
|
#ifdef WIN30
|
|||
|
if (hszPrinter != NULL && hszPrDriver != NULL && hszPrPort != NULL)
|
|||
|
/* We used to only do this check if vfPrinterValid -- don't
|
|||
|
now because otherwise one has no way to get Write to believe
|
|||
|
it has a valid printer! ..pt */
|
|||
|
#else
|
|||
|
if (vfPrinterValid && hszPrinter != NULL && hszPrDriver != NULL &&
|
|||
|
hszPrPort != NULL)
|
|||
|
#endif
|
|||
|
{
|
|||
|
HDC (far PASCAL *fnCreate)() = fDC ? CreateDC : CreateIC;
|
|||
|
|
|||
|
StartLongOp();
|
|||
|
|
|||
|
if (PD.hDevMode == NULL)
|
|||
|
fnPrGetDevmode(); // get PD.hDevMode
|
|||
|
|
|||
|
lpDevmodeData = MAKELP(PD.hDevMode,0);
|
|||
|
|
|||
|
if ((vhDCPrinter = (*fnCreate)((LPSTR)&(**hszPrDriver)[0],
|
|||
|
(LPSTR)&(**hszPrinter)[0], (LPSTR)&(**hszPrPort)[0], lpDevmodeData)) !=
|
|||
|
NULL)
|
|||
|
{
|
|||
|
EndLongOp(vhcIBeam);
|
|||
|
vfPrinterValid = TRUE;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
/* If we thought the DC was valid, then we better tell the user it
|
|||
|
is not. */
|
|||
|
EndLongOp(vhcIBeam);
|
|||
|
fCreateError = TRUE;
|
|||
|
goto NoDC;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
NoDC:
|
|||
|
/* We don't have a printer DC, so use the DC for the screen. */
|
|||
|
vhDCPrinter = GetDC(hParentWw);
|
|||
|
vfPrinterValid = FALSE;
|
|||
|
|
|||
|
/* Warn the user if necessary. This is done after creating the printer
|
|||
|
DC because Error() may force the DC to be created if we had not already
|
|||
|
done so. */
|
|||
|
if (fCreateError)
|
|||
|
{
|
|||
|
BOOL fInit = vfInitializing;
|
|||
|
|
|||
|
vfInitializing = FALSE;
|
|||
|
#ifdef DBCS /* was in JAPAN */
|
|||
|
/* We have to answer to WM_WININICHANGE immidiately to ReleaseDC with
|
|||
|
** 'dispatch' printer driver.
|
|||
|
** So It's possible for us opening MessageBox deep in SendMessage
|
|||
|
** call. This code avoid that.. Yutakan.
|
|||
|
*/
|
|||
|
if( !InSendMessage() )
|
|||
|
#endif
|
|||
|
Error(IDPMTCantPrint);
|
|||
|
vfInitializing = fInit;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* Set new values for the "constants" used by this printer. */
|
|||
|
SetPrintConstants();
|
|||
|
|
|||
|
/* Set the size of the paper for this printer. */
|
|||
|
SetPageSize();
|
|||
|
vfWarnMargins = FALSE;
|
|||
|
|
|||
|
/* The printer may have changed in such a way that it's fonts have changed
|
|||
|
(i.e. portrait to landscape). We must re-initialize our list of fonts. */
|
|||
|
ResetDefaultFonts(TRUE);
|
|||
|
if (hpdocdod != NULL)
|
|||
|
{
|
|||
|
Assert((**hpdocdod)[docCur].hffntb != NULL);
|
|||
|
(*(**hpdocdod)[docCur].hffntb)->fFontMenuValid = FALSE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
SetPageSize()
|
|||
|
{
|
|||
|
/* Change the size of the paper to the printer described by vhDCPrinter. */
|
|||
|
|
|||
|
extern HDC vhDCPrinter;
|
|||
|
extern HWND vhWndMsgBoxParent;
|
|||
|
extern BOOL vfPrinterValid;
|
|||
|
extern typeCP cpMinHeader;
|
|||
|
extern typeCP cpMacHeader;
|
|||
|
extern typeCP cpMinFooter;
|
|||
|
extern typeCP cpMacFooter;
|
|||
|
extern int dxpPrPage;
|
|||
|
extern int dypPrPage;
|
|||
|
extern int dxaPrPage;
|
|||
|
extern int dyaPrPage;
|
|||
|
extern HWND hParentWw;
|
|||
|
extern struct SEP vsepNormal;
|
|||
|
extern struct DOD (**hpdocdod)[];
|
|||
|
extern int docMac;
|
|||
|
extern int docScrap;
|
|||
|
extern int docUndo;
|
|||
|
extern BOOL vfWarnMargins;
|
|||
|
|
|||
|
unsigned xaMac;
|
|||
|
unsigned yaMac;
|
|||
|
unsigned dxaRight;
|
|||
|
unsigned dyaBottom;
|
|||
|
unsigned dyaRH2;
|
|||
|
unsigned dxaPrRight = 0;
|
|||
|
unsigned dyaPrBottom = 0;
|
|||
|
BOOL fRH;
|
|||
|
register struct DOD *pdod;
|
|||
|
int doc;
|
|||
|
HWND hWnd;
|
|||
|
|
|||
|
if (hpdocdod == NULL || docMac == 0)
|
|||
|
{
|
|||
|
/* Nothing to do if there are no documents. */
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
Assert(vhDCPrinter);
|
|||
|
if (vfPrinterValid && vhDCPrinter != NULL)
|
|||
|
{
|
|||
|
POINT pt;
|
|||
|
|
|||
|
/* Get the page size of the printer. */
|
|||
|
if (Escape(vhDCPrinter, GETPHYSPAGESIZE, 0, (LPSTR)NULL, (LPSTR)&pt))
|
|||
|
{
|
|||
|
xaMac = MultDiv(pt.x, dxaPrPage, dxpPrPage);
|
|||
|
yaMac = MultDiv(pt.y, dyaPrPage, dypPrPage);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
/* The printer won't tell us it page size; we'll have to settle
|
|||
|
for the printable area. */
|
|||
|
xaMac = ZaFromMm(GetDeviceCaps(vhDCPrinter, HORZSIZE));
|
|||
|
yaMac = ZaFromMm(GetDeviceCaps(vhDCPrinter, VERTSIZE));
|
|||
|
}
|
|||
|
|
|||
|
/* The page size cannot be smaller than the printable area. */
|
|||
|
if (xaMac < dxaPrPage)
|
|||
|
{
|
|||
|
xaMac = dxaPrPage;
|
|||
|
}
|
|||
|
if (yaMac < dyaPrPage)
|
|||
|
{
|
|||
|
yaMac = dyaPrPage;
|
|||
|
}
|
|||
|
|
|||
|
/* Determine the offset of the printable area on the page. */
|
|||
|
if (Escape(vhDCPrinter, GETPRINTINGOFFSET, 0, (LPSTR)NULL, (LPSTR)&pt))
|
|||
|
{
|
|||
|
dxaPrOffset = MultDiv(pt.x, dxaPrPage, dxpPrPage);
|
|||
|
dyaPrOffset = MultDiv(pt.y, dyaPrPage, dypPrPage);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
/* The printer won't tell us what the offset is; assume the
|
|||
|
printable area is centered on the page. */
|
|||
|
dxaPrOffset = (xaMac - dxaPrPage) >> 1;
|
|||
|
dyaPrOffset = (yaMac - dyaPrPage) >> 1;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
/* Assume standard page size for now. */
|
|||
|
xaMac = cxaInch * 8 + cxaInch / 2;
|
|||
|
yaMac = cyaInch * 11;
|
|||
|
dxaPrOffset = dyaPrOffset = 0;
|
|||
|
}
|
|||
|
|
|||
|
/* Determine the right and bottom margins for the "normal" page. */
|
|||
|
dxaRight = vsepNormal.xaMac - vsepNormal.xaLeft - vsepNormal.dxaText;
|
|||
|
dyaBottom = vsepNormal.yaMac - vsepNormal.yaTop - vsepNormal.dyaText;
|
|||
|
dyaRH2 = vsepNormal.yaMac - vsepNormal.yaRH2;
|
|||
|
|
|||
|
/* Determine the minimum dimensions of the printed page. */
|
|||
|
if (vfPrinterValid)
|
|||
|
{
|
|||
|
dxaPrRight = imax(0, xaMac - dxaPrOffset - dxaPrPage);
|
|||
|
dyaPrBottom = imax(0, yaMac - dyaPrOffset - dyaPrPage);
|
|||
|
|
|||
|
hWnd = vhWndMsgBoxParent == NULL ? hParentWw : vhWndMsgBoxParent;
|
|||
|
|
|||
|
#ifdef BOGUS
|
|||
|
/* Check the margins of the "normal" page. */
|
|||
|
fRH = cpMacHeader - cpMacHeader > ccpEol || cpMacFooter - cpMinFooter >
|
|||
|
ccpEol;
|
|||
|
if (vfWarnMargins && (FUserZaLessThanZa(vsepNormal.xaLeft, dxaPrOffset)
|
|||
|
|| FUserZaLessThanZa(dxaRight, dxaPrRight) ||
|
|||
|
FUserZaLessThanZa(vsepNormal.yaTop, dyaPrOffset) ||
|
|||
|
FUserZaLessThanZa(dyaBottom, dyaPrBottom) || (fRH &&
|
|||
|
(FUserZaLessThanZa(vsepNormal.yaRH1, dyaPrOffset) ||
|
|||
|
FUserZaLessThanZa(dyaRH2, dyaPrBottom)))))
|
|||
|
{
|
|||
|
/* One of the margins is bad, tell the user about it. */
|
|||
|
ErrorBadMargins(hWnd, dxaPrOffset, dxaPrRight, dyaPrOffset,
|
|||
|
dyaPrBottom);
|
|||
|
vfWarnMargins = FALSE;
|
|||
|
}
|
|||
|
#endif /* BOGUS */
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
/* Reset the dimensions of the "normal" page. */
|
|||
|
vsepNormal.xaMac = xaMac;
|
|||
|
vsepNormal.dxaText = xaMac - vsepNormal.xaLeft - umax(dxaRight, dxaPrRight);
|
|||
|
vsepNormal.yaMac = yaMac;
|
|||
|
vsepNormal.dyaText = yaMac - vsepNormal.yaTop - umax(dyaBottom,
|
|||
|
dyaPrBottom);
|
|||
|
vsepNormal.yaRH2 = yaMac - umax(dyaRH2, dyaPrBottom);
|
|||
|
|
|||
|
/* Reset the page dimensions for all documents. */
|
|||
|
for (doc = 0, pdod = &(**hpdocdod)[0]; doc < docMac; doc++, pdod++)
|
|||
|
{
|
|||
|
if (pdod->hpctb != NULL && pdod->hsep != NULL)
|
|||
|
{
|
|||
|
/* Reset the existing section properties. */
|
|||
|
register struct SEP *psep = *(pdod->hsep);
|
|||
|
|
|||
|
/* Determine the right and bottom margins for this page. */
|
|||
|
dxaRight = psep->xaMac - psep->xaLeft - psep->dxaText;
|
|||
|
dyaBottom = psep->yaMac - psep->yaTop - psep->dyaText;
|
|||
|
dyaRH2 = psep->yaMac - psep->yaRH2;
|
|||
|
|
|||
|
/* Check the margins for this document. */
|
|||
|
if (vfWarnMargins && vfPrinterValid && doc != docScrap && doc !=
|
|||
|
docUndo && (FUserZaLessThanZa(psep->xaLeft, dxaPrOffset) ||
|
|||
|
FUserZaLessThanZa(dxaRight, dxaPrRight) ||
|
|||
|
FUserZaLessThanZa(psep->yaTop, dyaPrOffset) ||
|
|||
|
FUserZaLessThanZa(dyaBottom, dyaPrBottom) || (fRH &&
|
|||
|
(FUserZaLessThanZa(psep->yaRH1, dyaPrOffset) ||
|
|||
|
FUserZaLessThanZa(dyaRH2, dyaPrBottom)))))
|
|||
|
{
|
|||
|
ErrorBadMargins(hWnd, dxaPrOffset, dxaPrRight, dyaPrOffset,
|
|||
|
dyaPrBottom);
|
|||
|
vfWarnMargins = FALSE;
|
|||
|
pdod = &(**hpdocdod)[doc];
|
|||
|
psep = *(pdod->hsep);
|
|||
|
}
|
|||
|
|
|||
|
/* Set the dimensions of this page. */
|
|||
|
psep->xaMac = xaMac;
|
|||
|
psep->dxaText = xaMac - psep->xaLeft - dxaRight;
|
|||
|
psep->yaMac = yaMac;
|
|||
|
psep->dyaText = yaMac - psep->yaTop - dyaBottom;
|
|||
|
psep->yaRH2 = yaMac - dyaRH2;
|
|||
|
}
|
|||
|
|
|||
|
/* Invalidate any caches for this document. */
|
|||
|
InvalidateCaches(doc);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|