/* FILE: spool.c */ #include "spool.h" #include #include #include // Play with this number #define BUFSIZE 2048 // Convenient structure for use with PASSTHROUGH escape typedef struct { WORD wSize; BYTE bData[2]; // placeholder } PASSTHROUGHSTRUCT, FAR *LPPTS; BOOL bAbort; // Global printing abort flag //************************************************************* // // _PrintFile() // // Purpose: // Reads a file and copies it to a printer using the // PASSTHROUGH escape. // // Parameters: // LPSTR szFile - Pointer to path/filename to print // HDC hPrnDC - Handle to printer DC or NULL // HGLOBAL hDevNames - Handle to DEVNAMES struct or NULL // HGLOBAL hDevMode - Handle to DEVMODE struct or NULL // // Return: // Returns nonzero for success or zero for failure. // // Comments: // hDevNames and hDevMode are only used if hPrnDC is NULL. // If both hPrnDC and hDevNames are NULL, the default // printer is used. // // History: Date Author Comment // 6/03/93 JMS Created // //************************************************************* BOOL FAR PASCAL __export _PrintFile ( LPSTR szFile, HDC hPrnDC, HGLOBAL hDevNames, HGLOBAL hDevMode ) { int iEsc; BOOL bLocalDC = TRUE; // Assume we must create a DC (hPrnDC == NULL) bAbort = FALSE; // Haven't aborted yet // Make sure we have a printer DC if (!hPrnDC) hPrnDC = GetPrinterDC(hDevNames, hDevMode); else bLocalDC = FALSE; // Use passed in hPrnDC if (!hPrnDC) return FALSE; // PASSTHROUGH is required. If driver doesn't support it, bail out. iEsc = PASSTHROUGH; if (!Escape(hPrnDC, QUERYESCSUPPORT, sizeof(int), (LPSTR)&iEsc, NULL)) { bAbort = TRUE; goto MSFCleanUp; } // If we created the DC, install an abort procedure. We don't have // a Cancel dialog box, but the abort proc enables multitasking. // (Use __export and compile with -GA or -GD so we don't need // a MakeProcInstance.) if (bLocalDC) Escape (hPrnDC, SETABORTPROC, 0, (LPSTR) PrintAbortProc, NULL); // Call EPSPRINTING if it is supported (that is, if we're on a // PostScript printer) to suppress downloading the pscript header. iEsc = EPSPRINTING; if (Escape(hPrnDC, QUERYESCSUPPORT, sizeof(int), (LPSTR)&iEsc, NULL)) { iEsc = 1; // 1 == enable PASSTHROUGH (disable pscript header) Escape(hPrnDC, EPSPRINTING, sizeof(int), (LPSTR)&iEsc, NULL); } SendFile(hPrnDC, szFile); // Send file to printer (could do multiple // files) MSFCleanUp: // Done if (bLocalDC) // Only delete DC if we created it DeleteDC(hPrnDC); return !bAbort; } /* _PrintFile() */ BOOL FAR PASCAL __export PrintFile(LPSTR szFile) { return _PrintFile(szFile, NULL, NULL, NULL); } VOID SendFile(HDC hPrnDC, LPSTR szFile) { HGLOBAL HMem; LPPTS lpPTS; // Pointer to PASSTHROUGHSTRUCT OFSTRUCT ofs; HFILE hFile; HMem = GlobalAlloc(GPTR, sizeof(WORD) + BUFSIZE); if (HMem == NULL) { bAbort = TRUE; return; } lpPTS = (LPPTS)GlobalLock(HMem); if (lpPTS == NULL) { bAbort = TRUE; GlobalFree(HMem); return; } hFile = OpenFile((LPSTR) szFile, &ofs, OF_READ); if (hFile == HFILE_ERROR) { bAbort = TRUE; // Can't open file| GlobalUnlock(HMem); GlobalFree(HMem); return; } Escape (hPrnDC, STARTDOC, 0, "", NULL); // Loop through the file, reading a chunk at a time and passing // it to the printer. QueryAbort calls the abort procedure, which // processes messages so we don't tie up the whole system. // We could skip the QueryAbort, in which case we wouldn't need // to set an abort proc at all. do { if ((lpPTS->wSize=_lread(hFile, lpPTS->bData, BUFSIZE)) == HFILE_ERROR) { bAbort = TRUE; // error reading file break; } Escape(hPrnDC, PASSTHROUGH, NULL, (LPSTR)lpPTS, NULL); } while ((lpPTS->wSize == BUFSIZE) && QueryAbort(hPrnDC, 0)); if (!bAbort) Escape(hPrnDC, ENDDOC, NULL, NULL, NULL); _lclose(hFile); GlobalUnlock(HMem); GlobalFree(HMem); } /* SendFile() */ HDC FAR PASCAL __export GetPrinterDC(HGLOBAL hDevNames, HGLOBAL hDevMode) { HDC hdc; int iEsc; char szPrinter[64]; LPSTR szDevice=NULL, szDriver=NULL, szOutput=NULL; LPDEVMODE lpdm; if (hDevNames) { LPDEVNAMES lpdn = (LPDEVNAMES) GlobalLock(hDevNames); szDriver = (LPSTR) lpdn + lpdn->wDriverOffset; szDevice = (LPSTR) lpdn + lpdn->wDeviceOffset; szOutput = (LPSTR) lpdn + lpdn->wOutputOffset; if (hDevMode) lpdm = (LPDEVMODE) GlobalLock(hDevMode); } else { // Get default printer info GetProfileString ("windows", "device", "", szPrinter, 64); if (!((szDevice = strtok (szPrinter, "," )) && (szDriver = strtok (NULL, ", ")) && (szOutput = strtok (NULL, ", ")))) return NULL; // No default printer lpdm = NULL; // Don't use DEVMODE with default printer } hdc = CreateDC(szDriver, szDevice, szOutput, lpdm); // PASSTHROUGH is required. If driver doesn't support it, try to use raw.drv. iEsc = PASSTHROUGH; if (!Escape(hdc, QUERYESCSUPPORT, sizeof(int), (LPSTR)&iEsc, NULL)) { DeleteDC(hdc); // RAW.DRV can be either in current directory, WINDOWS directory or WINDOWS\SYSTEM directory hdc = CreateDC( "RAW", NULL, szOutput, lpdm); } // hdc = CreateDC("RAW", NULL, szOutput, lpdm); if (hDevMode && lpdm) GlobalUnlock(hDevMode); if (hDevNames) GlobalUnlock(hDevNames); return hdc; } /* GetPrinterDC() */ BOOL CALLBACK __export PrintAbortProc(HDC hdc, int code) { MSG msg; while (!bAbort && PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } return (!bAbort); } /* PrintAbortProc() */ // The function that prints one line without formfeed BOOL FAR PASCAL __export _SpoolRow( LPSTR pData, WORD cbBytes, HDC hPrnDC, HGLOBAL hDevNames, HGLOBAL hDevMode ) { int iEsc; BOOL bLocalDC = TRUE; // Assume we must create a DC (hPrnDC == NULL) HGLOBAL HMem; char * pOutput; HMem = GlobalAlloc(GPTR, sizeof(WORD) + cbBytes); if (HMem == NULL) return FALSE; pOutput = (char *)GlobalLock(HMem); if (pOutput == NULL) { GlobalFree(HMem); return FALSE; } bAbort = FALSE; // Haven't aborted yet // Make sure we have a printer DC if (!hPrnDC) hPrnDC = GetPrinterDC(hDevNames, hDevMode); else bLocalDC = FALSE; // Use passed in hPrnDC if (!hPrnDC) return FALSE; if (bLocalDC) Escape (hPrnDC, SETABORTPROC, 0, (LPSTR) PrintAbortProc, NULL); // PASSTHROUGH is required. If driver doesn't support it, bail out. bAbort = FALSE; iEsc = PASSTHROUGH; if (!Escape(hPrnDC, QUERYESCSUPPORT, sizeof(int), (LPSTR)&iEsc, NULL)) { bAbort = TRUE; goto MPLCleanUp; } // Call EPSPRINTING if it is supported (that is, if we're on a // PostScript printer) to suppress downloading the pscript header. iEsc = EPSPRINTING; if (Escape(hPrnDC, QUERYESCSUPPORT, sizeof(int), (LPSTR)&iEsc, NULL)) { iEsc = 1; // 1 == enable PASSTHROUGH (disable pscript header) Escape(hPrnDC, EPSPRINTING, sizeof(int), (LPSTR)&iEsc, NULL); } // Start a Document Escape (hPrnDC, STARTDOC, 0, "", NULL); // Put data in the buffer and send to the printer *(WORD *)pOutput = cbBytes; memcpy( &(pOutput[sizeof(WORD)]), pData, cbBytes ); if( Escape( hPrnDC, PASSTHROUGH, 0, pOutput, NULL ) <= 0 ) bAbort = TRUE; // End the Document if (!bAbort) Escape(hPrnDC, ENDDOC, NULL, NULL, NULL); MPLCleanUp: // Done // Clean up if (bLocalDC) DeleteDC( hPrnDC ); GlobalUnlock(HMem); GlobalFree(HMem); return !bAbort; } BOOL FAR PASCAL __export SpoolRow( char *pData, WORD cbBytes ) { return _SpoolRow(pData, cbBytes, NULL, NULL, NULL); } /*** EOF: spool.c ***/