home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Windoware
/
WINDOWARE_1_6.iso
/
winutil
/
adg_4_6
/
printstp.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-02-21
|
22KB
|
592 lines
/****************************************************************************
Module name: PrintStp.C
Programmer : Jeffrey M. Richter.
*****************************************************************************/
#include "..\nowindws.h"
#undef NOCTLMGR
#undef NOGDI
#undef NOKERNEL
#undef NOLSTRING
#undef NOMB
#undef NOMEMMGR
#undef NOMINMAX
#undef NOMSG
#undef NOSHOWWINDOW
#undef NOUSER
#undef NOWH
#undef NOWINMESSAGES
#undef NOWINOFFSETS
#undef NOWINSTYLES
#include <windows.h>
#include <drivinit.h>
#include <string.h>
#include "dialog.h"
#include "printstp.h"
extern HANDLE _hInstance;
char _szPSSTRUCTProp[] = "PSSTRUCT";
char _szPSModeProp[] = "PSMode";
// User-defined messages for the PrinterSetupProc dialog box function.
#define PSM_FILLPRINTERBOX (WM_USER + 500)
#define PSM_SETDEFAULTPRINTER (WM_USER + 501)
// DRIVINIT.H doesn't define types for use with the old DeviceMode
// function so we have to.
typedef void FAR PASCAL FNDEVICEMODE (HWND, HANDLE, LPSTR, LPSTR);
typedef FNDEVICEMODE FAR *LPFNDEVICEMODE;
// Possible return values from the SetupNewPrinter function.
#define SNP_SUCCESS (0)
#define SNP_NODRIVER (1)
#define SNP_INVALIDDRIVER (2)
#define SNP_NOMEMORY (3)
int NEAR PASCAL SetupNewPrinter (GLOBALHANDLE FAR *hPSOld, HWND hWnd, LPSTR szPrintInfo);
BOOL FAR PASCAL PrinterSetupProc (HWND hDlg, WORD wMsg, WORD wParam, LONG lParam);
// Function called from application to present "Printer setup" box.
// Returns handle to PSSTRUCT block for new printer or NULL if no change.
GLOBALHANDLE FAR PASCAL PrinterSetup (HWND hWnd, GLOBALHANDLE hMem, WORD wMode) {
GLOBALHANDLE hNewMem; FARPROC fpProc;
fpProc = MakeProcInstance(PrinterSetupProc, _hInstance);
hNewMem = DialogBoxParam(_hInstance, "PrinterSetup", hWnd,
fpProc, MAKELONG(wMode, hMem));
FreeProcInstance(fpProc);
return(hNewMem);
}
// Dialog function for use by "Printer setup" box.
// EndDialog returns handle of new PSSTRUCT block or NULL if no change.
BOOL FAR PASCAL PrinterSetupProc (HWND hDlg, WORD wMsg, WORD wParam, LONG lParam) {
HWND hWndList;
RECT rc;
char szNullPort[MAXPORTLEN], szAllPrinters[5 * MAXPRINTINFOLEN];
char szPrintInfo[MAXPRINTINFOLEN], szBuf[2 * MAXPRINTINFOLEN];
char szPrintInfoDef[MAXPRINTINFOLEN], szDriverDef[MAXDRIVERLEN];
char szDeviceDef[MAXDEVICELEN], szPortDef[MAXPORTLEN];
char szDevice[MAXDEVICELEN], szDriver[MAXDRIVERLEN], szPort[MAXPORTLEN];
BOOL fProcessed = TRUE;
GLOBALHANDLE hMem;
LPPSSTRUCT lpPSOrig, lpPS;
WORD wMode;
LPSTR lpszCrntPort, lpszTemp, lpszPrinter, lpszError;
int nDefPrint, nNumPrinters, nSNPError, x, nDefID;
switch (wMsg) {
case WM_INITDIALOG:
// lParam: LOWORD = wMode, HIWORD = GLOBALHANDLE to PSSTRUCT
if (HIWORD(lParam) != NULL) { // A printer has been setup.
// Create 2nd memory block same size as first.
hMem = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT,
GlobalSize(HIWORD(lParam)));
} else {
// No printer has been setup.
hMem = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, sizeof(PSSTRUCT));
}
if (hMem == NULL) { // Not enough memory.
MessageBox(hDlg, "Insufficient memory.", NULL,
MB_OK | MB_ICONEXCLAMATION);
// Terminate dialog box notify caller of no change in printer.
EndDialog(hDlg, NULL);
break;
}
if (HIWORD(lParam) != NULL) { // A Printer has been setup.
// Copy original printer information into new block so that
// we do not alter the original block in any way.
lpPSOrig = (LPPSSTRUCT) GlobalLock(HIWORD(lParam));
lpPS = (LPPSSTRUCT) GlobalLock(hMem);
_fmemcpy(lpPS, lpPSOrig, (WORD) GlobalSize(hMem));
GlobalUnlock(hMem);
GlobalUnlock(HIWORD(lParam));
}
// Set TABSTOP in listbox to right-edge of its window.
hWndList = GetDlgItem(hDlg, ID_PRINTERBOX);
GetClientRect(hWndList, &rc);
x = (rc.right * LOWORD(GetDialogBaseUnits())) / 4;
SendMessage(hWndList, LB_SETTABSTOPS, 1, (LONG) (int FAR *) &x);
// Save the PSSTRUCT block as a window property.
SetProp(hDlg, _szPSSTRUCTProp, hMem);
// Save the dialog box's mode settings as a window property.
SetProp(hDlg, _szPSModeProp, LOWORD(lParam));
// Fill the list box with the installed printer information.
SendMessage(hDlg, PSM_FILLPRINTERBOX, 0, 0l);
break;
case WM_DESTROY:
// Remove the two properties from the window.
RemoveProp(hDlg, _szPSSTRUCTProp);
RemoveProp(hDlg, _szPSModeProp);
break;
case WM_WININICHANGE:
// Check if user changed the list of printers from another
// application (most likely - Control Panel).
if (lstrcmpi((LPSTR) lParam, "devices") != 0 && lParam != NULL)
break;
// If printers have changes, refill the list box.
SendMessage(hDlg, PSM_FILLPRINTERBOX, 0, 0l);
break;
case PSM_FILLPRINTERBOX:
// Retrieve mode value from window property.
wMode = GetProp(hDlg, _szPSModeProp);
// Get list of all printers installed by user.
x = GetProfileString("devices", NULL, "", szAllPrinters,
sizeof(szAllPrinters));
if (x == sizeof(szAllPrinters) - 2) { // Buffer too small.
MessageBox(hDlg,
"Too many printers installed.\tList truncated.", NULL,
MB_OK | MB_ICONEXCLAMATION);
lpszPrinter = szAllPrinters + sizeof(szAllPrinters) - 3;
while (lpszPrinter > szAllPrinters && *lpszPrinter != 0)
*lpszPrinter-- = 0;
}
// Retrieve the name of the NullPort (usually "None").
GetProfileString("windows", "NullPort", "",
szNullPort, sizeof(szNullPort));
hWndList = GetDlgItem(hDlg, ID_PRINTERBOX);
// Tell the listbox NOT to update its display & empty it.
SendMessage(hWndList, WM_SETREDRAW, FALSE, 0);
SendMessage(hWndList, LB_RESETCONTENT, 0, 0L);
// Fill the LISTBOX with printers from [devices] section of WIN.INI.
lpszPrinter = szAllPrinters;
for (; *lpszPrinter != 0; lpszPrinter = _fstrchr(lpszPrinter, 0) + 1) {
// Get the driver name and port for the printer.
GetProfileString("devices", lpszPrinter, "", szPrintInfo, sizeof(szPrintInfo));
// lpszPrinter = "IBM Graphics"
// szPrintInfo = "IBMGRX,LPT1:,COM2:"
lpszCrntPort = _fstrchr(szPrintInfo, ','); *lpszCrntPort++ = 0;
// szPrintInfo = "IBMGRX"
// lpszCrntPort = "LPT1:,COM2:"
while (lpszCrntPort != NULL) {
// If another port exists, terminate the string at the comma.
lpszTemp = _fstrchr(lpszCrntPort, ',');
if (lpszTemp != NULL) *lpszTemp = 0;
// lpszCrntPort = "LPT1:"
// If active only && printer NOT active, don't add to listbox.
if ((wMode & PSMODE_ACTIVEONLY) &&
lstrcmpi(lpszCrntPort, szNullPort) == 0) {
; // Do nothing.
} else {
// Build string that has the following form:
// "(device) ON (port)\t(device)=(driver),(port)"
// Example: "IBM Graphics on LPT1:\tIBM Graphics=IBMGRX,LPT1:"
wsprintf(szBuf, "%s on %s\t%s=%s,%s",
(LPSTR) lpszPrinter, (LPSTR) lpszCrntPort,
(LPSTR) lpszPrinter, (LPSTR) szPrintInfo,
(LPSTR) lpszCrntPort);
// Add string to listbox. Note, the listbox sorts the printers
// in alpha-order because LBS_SORT style used in dlg template.
SendMessage(hWndList, LB_ADDSTRING, 0, (LONG) (LPSTR) szBuf);
}
// Find next port if it exists.
lpszCrntPort = lpszTemp;
if (lpszCrntPort != NULL) lpszCrntPort++;
// lpszCrntPort = "COM2:"
}
}
nNumPrinters = (int) SendMessage(hWndList, LB_GETCOUNT, 0, 0);
if (nNumPrinters == 0) {
MessageBox(hDlg, "No printers installed.", NULL,
MB_OK | MB_ICONEXCLAMATION);
// Sending the WM_COMMAND w/IDCANCEL to terminate the dialog box
// will free the memory allocated during the processing
// of WM_INITDIALOG message.
SendMessage(hDlg, WM_COMMAND, IDCANCEL,
MAKELONG(GetDlgItem(hDlg, IDCANCEL), BN_CLICKED));
break;
}
// Listbox is filled, determine which printer to select initially.
SendMessage(hDlg, PSM_SETDEFAULTPRINTER, 0, 0);
// Tell the listbox that it is now OK to update its display.
SendMessage(hWndList, WM_SETREDRAW, TRUE, 0);
// Force the listbox to be completely redrawn.
InvalidateRect(hWndList, NULL, TRUE);
break;
case PSM_SETDEFAULTPRINTER:
// Set up the default selection in the listbox.
hWndList = GetDlgItem(hDlg, ID_PRINTERBOX);
// Retrieve handle to printer memory block from window property.
hMem = GetProp(hDlg, _szPSSTRUCTProp);
// Get the information for the default printer selected by the user.
GetProfileString("windows", "device", "",
szPrintInfoDef, sizeof(szPrintInfoDef));
if (*szPrintInfoDef != 0) {
ParsePrintInfo(szPrintInfoDef, FALSE, szDriverDef,
szDeviceDef, szPortDef);
} else { *szDeviceDef = *szDriverDef = *szPortDef = 0; }
nDefPrint = -1;
nNumPrinters = (int) SendMessage(hWndList, LB_GETCOUNT, 0, 0);
// Cannot be zero because of check in PSM_FILLPRINTERBOX message.
lpPS = (LPPSSTRUCT) GlobalLock(hMem);
for (x = 0; x < nNumPrinters; x++) {
// Get line 'x' from the listbox.
SendMessage(hWndList, LB_GETTEXT, x, (LONG) (LPSTR) szPrintInfo);
// PrintInfo string is after the TAB ('\t') character.
ParsePrintInfo(_fstrchr(szPrintInfo, '\t') + 1, FALSE,
szDriver, szDevice, szPort);
// Remember index in listbox where the "default printer" is located.
if (lstrcmpi(szDevice, szDeviceDef) == 0 &&
lstrcmpi(szPort, szPortDef) == 0) nDefPrint = x;
// If device and port of listbox entry & printer in PSSTRUCT block
// match, set that printer as the default and stop the "for" loop.
if (lstrcmpi(szDevice, lpPS->DevMode.dmDeviceName) == 0 &&
lstrcmpi(szPort, lpPS->szPort) == 0) {
SendMessage(hWndList, LB_SETCURSEL, x, 0);
break;
}
}
GlobalUnlock(hMem);
if (x == nNumPrinters) {
// Printer in memory block didn't match any printer in listbox.
// Set selection to "default printer" if it was found.
SendMessage(hWndList, LB_SETCURSEL,
(nDefPrint == -1) ? 0 : nDefPrint, 0);
}
break;
case WM_COMMAND:
switch (wParam) {
case ID_PRINTERBOX:
if (HIWORD(lParam) != LBN_DBLCLK) break;
// Get the ID of the default pushbutton. Note, assume that the
// HIWORD from sending DM_GETDEFID is DC_HASDEFID.
nDefID = LOWORD(SendMessage(hDlg, DM_GETDEFID, 0, 0));
// Simulate the user selecting the default pushbutton.
SendMessage(hDlg, WM_COMMAND, nDefID,
MAKELONG(GetDlgItem(hDlg, nDefID), BN_CLICKED));
break;
case ID_SETUP:
case IDOK:
if (HIWORD(lParam) != BN_CLICKED) break;
hWndList = GetDlgItem(hDlg, ID_PRINTERBOX);
// Get information about currently selected printer.
x = (int) SendMessage(hWndList, LB_GETCURSEL, 0, 0L);
SendMessage(hWndList, LB_GETTEXT, x, (LONG) (LPSTR) szPrintInfo);
// szPrintInfo = "Generic / Text Only on FILE:\tGeneric / Text Only=TTY,FILE:"
// Get memory handle of current selected printer.
hMem = GetProp(hDlg, _szPSSTRUCTProp);
// If OK button pressed, do setup without displaying the printer's
// settings dialog box.
nSNPError = SetupNewPrinter(&hMem,
(wParam == IDOK) ? NULL : hDlg,
_fstrchr(szPrintInfo, '\t') + 1);
// New printer setup block returned, save it in the window property.
if (nSNPError == SNP_SUCCESS)
SetProp(hDlg, _szPSSTRUCTProp, hMem);
else {
switch (nSNPError) {
case SNP_NODRIVER:
lpszError = "Cannot find printer driver."; break;
case SNP_INVALIDDRIVER:
lpszError = "Invalid printer driver."; break;
case SNP_NOMEMORY:
lpszError = "Insufficient memory."; break;
}
MessageBox(hDlg, lpszError, NULL, MB_OK | MB_ICONEXCLAMATION);
}
if (wParam == IDOK) {
// Terminate the dialog box & return handle to new printer setup.
EndDialog(hDlg, hMem);
} else {
// Set the "Ok" button back to the default button.
SendMessage(hDlg, DM_SETDEFID, IDOK, 0);
SendDlgItemMessage(hDlg, ID_SETUP, BM_SETSTYLE, (int) BS_PUSHBUTTON, TRUE);
SendDlgItemMessage(hDlg, IDOK, BM_SETSTYLE, (int) BS_DEFPUSHBUTTON, TRUE);
// Set the focus back to the listbox.
SetFocus(GetDlgItem(hDlg, ID_PRINTERBOX));
}
break;
case IDCANCEL:
// Free memory block allocated by WM_INITDIALOG message.
GlobalFree(GetProp(hDlg, _szPSSTRUCTProp));
// Return NULL to caller stating that no change to selected printer.
EndDialog(hDlg, NULL);
break;
}
break;
default: fProcessed = FALSE; break;
}
return(fProcessed);
}
// Function accepts string in a PrintInfo format. This format is:
// (device name)[= | ,](driver name),(port)
// It then fills the buffers passed-in with parsed fields.
// If fAppendDriverExt is TRUE, ".DRV" is appended to the driver's name.
void FAR PASCAL ParsePrintInfo (LPSTR szPrintInfo,
BOOL fAppendDriverExt, LPSTR szDriver, LPSTR szDevice, LPSTR szPort) {
LPSTR p;
while (('=' != *szPrintInfo) && (',' != *szPrintInfo))
*szDevice++ = *szPrintInfo++;
*szDevice = 0;
szPrintInfo++;
p = szDriver;
while (*szPrintInfo != ',') *szDriver++ = *szPrintInfo++;
*szDriver = 0;
if (_fstrchr(p, '.') == NULL && fAppendDriverExt)
lstrcpy(szDriver, ".DRV");
szPrintInfo++;
while (*szPrintInfo != 0) *szPort++ = *szPrintInfo++;
*szPort = 0;
}
// Function is called when user selects "Ok" or "Setup..." button from
// "Printer setup" dialog box. This function prepares a new PSSTRUCT
// memory block with information about the selected printer. If hWnd
// is NOT NULL, the user is presented the printer's settings dialog box
// to change any settings. The hWnd parameter is NULL when the user
// selects the "Ok" button from the "Printer setup" dialog box.
int NEAR PASCAL SetupNewPrinter (GLOBALHANDLE FAR *hPSOld, HWND hWnd, LPSTR szPrintInfo) {
char szDriver[MAXDRIVERLEN], szDevice[MAXDEVICELEN], szPort[MAXPORTLEN];
int nDevModeSize, nEnvSize, nDlgBoxResult;
LPPSSTRUCT lpPSOld, lpPSNew;
GLOBALHANDLE hPSNew;
HANDLE hDriver;
LPFNDEVMODE ExtDeviceMode;
LPFNDEVICEMODE DeviceMode;
ParsePrintInfo(szPrintInfo, TRUE, szDriver, szDevice, szPort);
hDriver = LoadLibrary(szDriver);
if (hDriver < 32) return(SNP_NODRIVER);
ExtDeviceMode = (LPFNDEVMODE) GetProcAddress(hDriver, PROC_EXTDEVICEMODE);
DeviceMode = (LPFNDEVICEMODE) GetProcAddress(hDriver, PROC_OLDDEVICEMODE);
if (ExtDeviceMode == NULL && DeviceMode == NULL) {
FreeLibrary(hDriver);
return(SNP_INVALIDDRIVER);
}
lpPSOld = (LPPSSTRUCT) GlobalLock(*hPSOld);
if (ExtDeviceMode != NULL) {
// Get size of complete DEVMODE structure.
nDevModeSize = ExtDeviceMode(hWnd, hDriver, NULL, szDevice,
szPort, NULL, NULL, 0);
hPSNew = GlobalAlloc(GMEM_MOVEABLE, PSOVERHEAD + nDevModeSize);
if (hPSNew == NULL) {
FreeLibrary(hDriver);
return(SNP_NOMEMORY);
}
lpPSNew = (LPPSSTRUCT) GlobalLock(hPSNew);
// Copy over our port and driver names to new memory block.
lstrcpy(lpPSNew->szPort, szPort);
lstrcpy(lpPSNew->szDriver, szDriver);
lpPSNew->PSStat = PSSTAT_EXTDEVMODE;
lpPSNew->nEnvSize = 0;
if (lpPSOld->PSStat == PSSTAT_EXTDEVMODE) {
if (lstrcmpi(lpPSOld->szDriver, szDriver)) {
// Setting-up a different printer.
// Reset device-specific & driver-specific fields in DEVMODE.
lstrcpy(lpPSOld->DevMode.dmDeviceName, szDevice);
lpPSOld->DevMode.dmDriverVersion = 0;
lpPSOld->DevMode.dmDriverExtra = 0;
}
// Return value is IDOK if successful.
nDlgBoxResult = ExtDeviceMode(hWnd, hDriver, &lpPSNew->DevMode,
szDevice, szPort, &lpPSOld->DevMode, NULL,
DM_MODIFY | ((hWnd == NULL) ? 0 : DM_PROMPT) | DM_COPY);
} else {
// Return value is IDOK if successful.
nDlgBoxResult = ExtDeviceMode(hWnd, hDriver, &lpPSNew->DevMode,
szDevice, szPort, NULL, NULL,
((hWnd == NULL) ? 0 : DM_PROMPT) | DM_COPY);
}
} else {
// For all other cases, the DeviceMode function must be called.
// If the old PSSTRUCT has a valid Printer Environment,
// set the printer environment.
if (lpPSOld->nEnvSize > 0) {
SetEnvironment(szPort, (LPSTR) &lpPSOld->DevMode, lpPSOld->nEnvSize);
}
if (hWnd != NULL)
DeviceMode(hWnd, hDriver, szDevice, szPort);
// A valid return value is NOT guaranteed from the DeviceMode function
// so we will assume that it is IDOK.
nDlgBoxResult = IDOK;
// nEnvSize is the size of the Printer Environment.
nEnvSize = GetEnvironment(szPort, NULL, 0);
// Allocate a PSSTRUCT large enough to contain the Printer Environment.
hPSNew = GlobalAlloc(GMEM_MOVEABLE,
(nEnvSize == 0) ? sizeof(PSSTRUCT) : nEnvSize + PSOVERHEAD);
if (hPSNew == NULL) {
FreeLibrary(hDriver);
return(SNP_NOMEMORY);
}
lpPSNew = (LPPSSTRUCT) GlobalLock(hPSNew);
// Copy over our port and driver names to new memory block.
lstrcpy(lpPSNew->szPort, szPort);
lstrcpy(lpPSNew->szDriver, szDriver);
lpPSNew->PSStat = PSSTAT_DEVMODEONLY;
lpPSNew->nEnvSize = nEnvSize;
if (nEnvSize > 0) {
// If a Printer Environment exists, save it.
GetEnvironment(szPort, (LPSTR) &lpPSNew->DevMode, nEnvSize);
} else {
lstrcpy(lpPSNew->DevMode.dmDeviceName, szDevice);
}
}
GlobalUnlock(*hPSOld);
FreeLibrary(hDriver);
GlobalUnlock(hPSNew);
// nDlgBoxResult == IDOK if ExtDeviceMode or DeviceMode are successful.
if (nDlgBoxResult == IDOK) {
GlobalFree(*hPSOld);
*hPSOld = hPSNew;
} else
GlobalFree(hPSNew);
return(SNP_SUCCESS);
}
// This function accepts a PSSTRUCT and creates a device context for the
// printer described in the structure. If fUseDefaultSettings is TRUE,
// the default settings are used for the DC and not any settings that may
// exist in the PSSTRUCT set by a call to PrinterSetup.
HDC FAR PASCAL CreatePrinterDC (GLOBALHANDLE hMem) {
LPPSSTRUCT lpPS;
HDC hDC;
LPSTR p;
LPDEVMODE lpDM = NULL;
lpPS = (LPPSSTRUCT) GlobalLock(hMem);
if (lpPS->PSStat == PSSTAT_EXTDEVMODE) {
// Set lpDM to point to valid DEVMODE structure.
lpDM = &lpPS->DevMode;
} else {
// lpPS->PSStat must be PSSTAT_DEVMODEONLY or PSSTAT_UNKNOWN.
if (lpPS->nEnvSize > 0) {
// If a printer environment exists for this printer use it.
lpDM = &lpPS->DevMode;
}
}
// Remove extension from driver file name if it exists.
p = _fstrchr(lpPS->szDriver, '.');
if (p != NULL) *p = 0;
// Create the device context.
hDC = CreateDC(lpPS->szDriver, lpPS->DevMode.dmDeviceName,
lpPS->szPort, (LPSTR) lpDM);
// Restore the driver's extension if it was removed.
if (p != NULL) *p = '.';
GlobalUnlock(hMem);
return(hDC);
}
// This function is called when an application initializes so that the
// information about the default printer is loaded into a PSSTRUCT.
// Returns handle to PSSTRUCT block or NULL if insufficient memory.
GLOBALHANDLE FAR PASCAL SetupDefPrinter (void) {
GLOBALHANDLE hMem = NULL; LPPSSTRUCT lpPS;
char szPrintInfo[MAXPRINTINFOLEN];
char szDriver[MAXDRIVERLEN], szDevice[MAXDEVICELEN], szPort[MAXPORTLEN];
GetProfileString("windows", "device", "", szPrintInfo, sizeof(szPrintInfo));
if (*szPrintInfo == 0) return(hMem); // No default printer selected.
// szPrintInfo="Generic / Text Only,TTY,FILE:"
ParsePrintInfo(szPrintInfo, FALSE, szDriver, szDevice, szPort);
hMem = GlobalAlloc(GMEM_MOVEABLE, sizeof(PSSTRUCT));
if (hMem == NULL) return(hMem);
lpPS = (LPPSSTRUCT) GlobalLock(hMem);
lstrcpy(lpPS->szPort, szPort);
lstrcpy(lpPS->szDriver, szDriver);
lstrcpy(lpPS->DevMode.dmDeviceName, szDevice);
lpPS->PSStat = PSSTAT_UNKNOWN;
lpPS->nEnvSize = 0;
GlobalUnlock(hMem);
return(hMem);
}