/* File: D:\WACKER\tdll\print.c (Created: 14-Jan-1994) * * Copyright 1994 by Hilgraeve Inc. -- Monroe, MI * All rights reserved * * $Revision: 9 $ * $Date: 7/08/02 6:44p $ */ #include #pragma hdrstop //#define DEBUGSTR #include #include "stdtyp.h" #include "mc.h" #include "misc.h" #include "assert.h" #include "globals.h" #include "session.h" #include "print.h" #include "print.hh" #include "errorbox.h" #include "tdll.h" #include "term.h" #include "htchar.h" /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- * FUNCTION: * * DESCRIPTION: * * ARGUMENTS: * * RETURNS: * */ void printTellError(const HSESSION hSession, const HPRINT hPrint, const INT iStatus) { if (iStatus < 0) { if (iStatus & SP_NOTREPORTED) { TCHAR achBuf[256]; TCHAR achTitle[256]; achBuf[0] = TEXT('\0'); achTitle[0] = TEXT('\0'); LoadString(glblQueryDllHinst(), IDS_PRINT_TITLE, achTitle, sizeof(achTitle) / sizeof(TCHAR)); switch (iStatus) { case SP_OUTOFDISK: LoadString(glblQueryDllHinst(), IDS_PRINT_NOMEM, achBuf, sizeof(achBuf) / sizeof(TCHAR)); break; case SP_OUTOFMEMORY: LoadString(glblQueryDllHinst(), IDS_PRINT_CANCEL, achBuf, sizeof(achBuf) / sizeof(TCHAR)); break; case SP_USERABORT: break; default: { const HHPRINT hhPrint = (HHPRINT)hPrint; if (hhPrint == 0 || !hhPrint->fUserAbort) { LoadString(glblQueryDllHinst(), IDS_PRINT_ERROR, achBuf, sizeof(achBuf) / sizeof(TCHAR)); } } break; } if (achBuf[0] != TEXT('\0')) { TimedMessageBox(sessQueryHwnd(hSession), achBuf, achTitle, MB_ICONEXCLAMATION | MB_OK, 0); } } } return; } //*jcm #if 0 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- * FUNCTION: * PrintKillJob * * DESCRIPTION: * Kills a print job. Called when session is closing and stuff is * printing. * * ARGUMENTS: * HSESSION hSession - external session handle. * * RETURNS: * VOID * */ VOID PrintKillJob(HSESSION hSession) { HHPRINT hPr; INT iStatus = 0; HGLOBAL hMem; assert(hSession); // It is possible that the print job ended by the time we got // here so if the handle is 0, return quietly. hPr = (HHPRINT)mGetPrintHdl(hSession); if (hPr == (HHPRINT)0) return; /* -------------- Kill this print job ------------- */ TimerDestroy(&hPr->hTimer); DbgOutStr("\r\nTimer Destroy in PrintKillJob\r\n", 0, 0, 0, 0, 0); if (hPr->hDC) { // Check if we issued an EndPage() for this page yet. if (hPr->nLines > 0) { if (HA5G.fIsWin30) iStatus = Escape(hPr->hDC, NEWFRAME, 0, NULL, NULL); else iStatus = EndPage(hPr->hDC); DbgOutStr("EndPage = %d\r\n", iStatus, 0, 0, 0, 0); PrintTellError(hSession, (HPRINT)hPr, iStatus); } if (iStatus >= 0) { if (HA5G.fIsWin30) iStatus = Escape(hPr->hDC, ENDDOC, 0, (LPTSTR)0, NULL); else iStatus = EndDoc(hPr->hDC); DbgOutStr("EndDoc = %d\r\n", iStatus, 0, 0, 0, 0); PrintTellError(hSession, (HPRINT)hPr, iStatus); } if (IsWindow(hPr->hwndPrintAbortDlg)) DestroyWindow(hPr->hwndPrintAbortDlg); FreeProcInstance((FARPROC)hPr->lpfnPrintAbortDlg); FreeProcInstance((FARPROC)hPr->lpfnPrintAbortProc); DeleteDC(hPr->hDC); } else { nb_close(hPr->hPrn); } FreeProcInstance(hPr->lpfnTimerCallback); hMem = (HANDLE)GlobalHandle(HIWORD(hPr->pach)); GlobalUnlock(hMem); GlobalFree(hMem); free(hPr); hPr = NULL; mSetPrintHdl(hSession, (HPRINT)0); return; } #endif /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- * FUNCTION: * printAbortProc * * DESCRIPTION: * Enables print-manager to unspool stuff when system is low on disk * space. Is also called whenever EndPage() is called. * * ARGUMENTS: * HDC hdcPrn - DC of printer * INT - nCode * * RETURNS: * Stuff * */ BOOL CALLBACK printAbortProc(HDC hDC, INT nCode) { MSG msg; //cost HHPRINT hhPrint = printCtrlLookupDC(hDC); //*HCLOOP hCLoop = sessQueryCLoopHdl(hhPrint->hSession); DbgOutStr("\r\nprintAbortProc : %d\r\n", nCode, 0, 0, 0, 0); //*if (hCLoop == 0) //* { //* assert(FALSE); //* return FALSE; //* } // Need to quit processing characters to the emulator at this // point or a recursion condition occurs which results in a // run-away condtion. //*CLoopRcvControl(hCLoop, CLOOP_SUSPEND, CLOOP_RB_PRINTING); //*CLoopSndControl(hCLoop, CLOOP_SUSPEND, CLOOP_SB_PRINTING); while (PeekMessage((LPMSG)&msg, (HWND)0, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } //*CLoopRcvControl(hCLoop, CLOOP_RESUME, CLOOP_RB_PRINTING); //*CLoopSndControl(hCLoop, CLOOP_RESUME, CLOOP_SB_PRINTING); DbgOutStr("Exiting printAbortProc", 0, 0, 0, 0, 0); return TRUE; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- * FUNCTION: * printString * * DESCRIPTION: * Workhorse print-echo function. Takes care of counting lines and * paginating. Also calls printOpenDC() if necessary to get a printer * DC. * * ARGUMENTS: * HHPRINT hhPrint - The Internal printer handle * LPCTSTR pachStr - A pointer to the string to print. * int iLen - The length of the string to print. * * RETURNS: * TRUE = OK, FALSE = error * */ int printString(const HHPRINT hhPrint, LPCTSTR pachStr, int iLen) { int nCharCount; int nIdx; int iPrintableWidth; SIZE stStringSize; LPCTSTR pszTemp; TCHAR achBuf[512]; RECT stRect; // // get a device context if we do not already have one // if (hhPrint->hDC == 0) { if (printOpenDC(hhPrint) == FALSE) { printEchoClose((HPRINT)hhPrint); return FALSE; } } for (nCharCount = nIdx = 0, pszTemp = pachStr ; nIdx < iLen ; ++nCharCount, ++nIdx, pszTemp = StrCharNext(pszTemp)) { if (IsDBCSLeadByte((BYTE)*pszTemp)) nCharCount++; switch (*pszTemp) { case TEXT('\r'): if ( nCharCount ) MemCopy(achBuf, pachStr, nCharCount); achBuf[nCharCount] = TEXT('\0'); GetTextExtentPoint(hhPrint->hDC, achBuf, StrCharGetByteCount(achBuf), &stStringSize); if ( nCharCount > 1 ) { // // calculate a print rect for the current margins // iPrintableWidth = GetDeviceCaps( hhPrint->hDC, HORZRES ); iPrintableWidth -= hhPrint->marginsDC.right; stRect.left = hhPrint->cx; stRect.right = iPrintableWidth; stRect.top = hhPrint->cy; stRect.bottom = hhPrint->cy + stStringSize.cy; ExtTextOut( hhPrint->hDC, hhPrint->cx, hhPrint->cy, ETO_CLIPPED, &stRect, achBuf, StrCharGetByteCount(achBuf), NULL ); } TCHAR_Fill(achBuf, TEXT('\0'), sizeof(achBuf)/sizeof(TCHAR)); hhPrint->cx = hhPrint->marginsDC.left; pachStr = StrCharNext(pszTemp); nCharCount = 0; break; case TEXT('\f'): hhPrint->nLinesPrinted = hhPrint->nLinesPerPage; /* --- Fall thru to case '\n' --- */ case TEXT('\n'): if (nCharCount) MemCopy(achBuf, pachStr,nCharCount); achBuf[nCharCount] = TEXT('\0'); GetTextExtentPoint(hhPrint->hDC, achBuf, StrCharGetByteCount(achBuf), &stStringSize); if ( nCharCount > 1 ) { iPrintableWidth = GetDeviceCaps( hhPrint->hDC, HORZRES ); iPrintableWidth -= hhPrint->marginsDC.right; stRect.left = hhPrint->cx; stRect.right = iPrintableWidth; stRect.top = hhPrint->cy; stRect.bottom = hhPrint->cy + stStringSize.cy; ExtTextOut( hhPrint->hDC, hhPrint->cx, hhPrint->cy, ETO_CLIPPED, &stRect, achBuf, StrCharGetByteCount(achBuf), NULL ); } hhPrint->cy += stStringSize.cy; pachStr = StrCharNext(pszTemp); nCharCount = 0; // // check if we need a new page // hhPrint->nLinesPrinted += 1; if (hhPrint->nLinesPrinted > hhPrint->nLinesPerPage) { if (hhPrint->nFlags & PRNECHO_BY_PAGE) { printEchoClose((HPRINT)hhPrint); hhPrint->nFlags |= PRNECHO_IS_ON; return TRUE; } hhPrint->nStatus = EndPage(hhPrint->hDC); if (hhPrint->nStatus < 0) { printEchoClose((HPRINT)hhPrint); return FALSE; } hhPrint->nStatus = StartPage(hhPrint->hDC); printSetFont( hhPrint ); if (hhPrint->nStatus <= 0) { printEchoClose((HPRINT)hhPrint); return FALSE; } hhPrint->nLinesPrinted = 0; hhPrint->cx = hhPrint->marginsDC.left; hhPrint->cy = hhPrint->marginsDC.top; } break; default: break; } } /* -------------- Left over portion of a line? ------------- */ if ((nCharCount > 0) && (*pachStr != TEXT('\0'))) { DbgOutStr("o", 0, 0, 0, 0, 0); MemCopy(achBuf, pachStr,nCharCount); achBuf[nCharCount] = TEXT('\0'); GetTextExtentPoint(hhPrint->hDC, achBuf, StrCharGetByteCount(achBuf), &stStringSize); iPrintableWidth = GetDeviceCaps( hhPrint->hDC, HORZRES ); iPrintableWidth -= hhPrint->marginsDC.right; stRect.left = hhPrint->cx; stRect.right = iPrintableWidth; stRect.top = hhPrint->cy; stRect.bottom = hhPrint->cy + stStringSize.cy; ExtTextOut( hhPrint->hDC, hhPrint->cx, hhPrint->cy, ETO_CLIPPED, &stRect, achBuf, StrCharGetByteCount(achBuf), NULL ); // TextOut(hhPrint->hDC, // hhPrint->cx, // hhPrint->cy, // achBuf, StrCharGetByteCount(achBuf)); TCHAR_Fill(achBuf, TEXT('\0'), sizeof(achBuf)/sizeof(TCHAR)); hhPrint->cx += stStringSize.cx; } return TRUE; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- * FUNCTION: * printQueryStatus * * DESCRIPTION: This function is used to determine if printing has been * turned on for the supplied print handle. * * ARGUMENTS: hPrint - The external printer handle. * * RETURNS: TRUE - If printing is on. * FALSE - If printing is off. * */ int printQueryStatus(const HPRINT hPrint) { const HHPRINT hhPrint = (HHPRINT)hPrint; if (hPrint == 0) assert(FALSE); return (bittest(hhPrint->nFlags, PRNECHO_IS_ON)); } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- * FUNCTION: * printStatusToggle * * DESCRIPTION: * Toggles the status (on/off) of the supplied print handle. * * ARGUMENTS: hPrint - The external printer handle. * * RETURNS: nothing * */ void printStatusToggle(const HPRINT hPrint) { const HHPRINT hhPrint = (HHPRINT)hPrint; if (hPrint == 0) assert(FALSE); if (bittest(hhPrint->nFlags, PRNECHO_IS_ON)) { bitclear(hhPrint->nFlags, PRNECHO_IS_ON); } else { bitset(hhPrint->nFlags, PRNECHO_IS_ON); } return; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- * FUNCTION: * printSetStatus * * DESCRIPTION: * Turns priniting on or off for the supplied handle. * * ARGUMENTS: hPrint - The external printer handle. * fSetting - True or False to turn printing on/off. * * RETURNS: nothing * * */ void printSetStatus(const HPRINT hPrint, const int fSetting) { const HHPRINT hhPrint = (HHPRINT)hPrint; if (hPrint == 0) assert(FALSE); if (fSetting) bitset(hhPrint->nFlags, PRNECHO_IS_ON); else bitclear(hhPrint->nFlags, PRNECHO_IS_ON); return; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- * FUNCTION: * printQueryPrinterInfo * * DESCRIPTION: * This function copies five pieces of information (pszPrinter, pDevNames, * pDevMode, lf, and margins ) from the Session HHPRINT handle, to the supplied * HHPRINT handle. The objective is to copy the contents of the Session's * HPRINT handle to another HPRINT handle (from the emulators). Remember that * the Session's HPRINT handle is the one that contains the stored printer name and * setup information. * * ARGUMENTS: * * RETURNS: * */ void printQueryPrinterInfo( const HHPRINT hhSessPrint, HHPRINT hhPrint ) { TCHAR *pTemp; DWORD dwSize; if (hhPrint == NULL || hhSessPrint == NULL) { return; } // Copy the printer name. // StrCharCopyN(hhPrint->achPrinterName, hhSessPrint->achPrinterName, PRINTER_NAME_LEN); // Copy the DEVNAMES structure. // if (hhSessPrint->pstDevNames) { if (hhPrint->pstDevNames) { free(hhPrint->pstDevNames); hhPrint->pstDevNames = NULL; } pTemp = (TCHAR *)hhSessPrint->pstDevNames; pTemp += hhSessPrint->pstDevNames->wOutputOffset; pTemp += StrCharGetByteCount(pTemp) + 1; dwSize = (DWORD)(pTemp - (TCHAR*)hhSessPrint->pstDevNames); hhPrint->pstDevNames = malloc(dwSize); if (hhPrint->pstDevNames == 0) { assert(FALSE); return; } if (dwSize) MemCopy(hhPrint->pstDevNames, hhSessPrint->pstDevNames, dwSize); } // Copy the DEVMODE structure. // if (hhSessPrint->pstDevMode) { if (hhPrint->pstDevMode) { free(hhPrint->pstDevMode); hhPrint->pstDevMode = NULL; } dwSize = hhSessPrint->pstDevMode->dmSize + hhSessPrint->pstDevMode->dmDriverExtra; hhPrint->pstDevMode = malloc(dwSize); if (hhPrint->pstDevMode == 0) { assert(FALSE); return; } if (dwSize) MemCopy(hhPrint->pstDevMode, hhSessPrint->pstDevMode, dwSize); } // Copy the font and margin information // MemCopy( &hhPrint->margins, &hhSessPrint->margins, sizeof(RECT) ); MemCopy( &hhPrint->lf, &hhSessPrint->lf, sizeof(LOGFONT) ); hhPrint->iFontPointSize = hhSessPrint->iFontPointSize; return; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- * FUNCTION: * printVerifyPrinter * * DESCRIPTION: * This routine is used to determine if a printer (any printer) is * installed. * * ARGUMENTS: * hPrint - An external print handle. * * RETURNS: * 0 if successful, otherwise -1. * */ int printVerifyPrinter(const HPRINT hPrint) { const HHPRINT hhPrint = (HHPRINT)hPrint; TCHAR achTitle[256]; TCHAR achBuf[256]; TCHAR *pszString; HANDLE hPrinter = NULL; BOOL fRet; if (hhPrint == NULL) { return(-1); } // Check to see if the printer that has been saved with the // session information is still available. If it is, simply // return a zero, indicating everything is OK. // fRet = OpenPrinter((LPTSTR)hhPrint->achPrinterName, &hPrinter, NULL); if (fRet) { ClosePrinter(hPrinter); return(0); } // If we're here, it's time to locate the default printer, whatever // it is. If the default printer is selected here, the print handle's // name is initialized to that value. // if (GetProfileString("Windows", "Device", ",,,", achBuf, sizeof(achBuf)) && (pszString = strtok(achBuf, ","))) { StrCharCopyN(hhPrint->achPrinterName, pszString, PRINTER_NAME_LEN); return (0); } // A printer is NOT available. Display the text for telling the // user how to install one. It should be the same as the text that // appears in the printDlg call when this happens. // LoadString(glblQueryDllHinst(), IDS_PRINT_NO_PRINTER, achBuf, sizeof(achBuf) / sizeof(TCHAR)); mscMessageBeep(MB_ICONEXCLAMATION); achTitle[0] = TEXT('\0'); LoadString(glblQueryDllHinst(), IDS_PRINT_TITLE, achTitle, sizeof(achTitle) / sizeof(TCHAR)); TimedMessageBox(sessQueryHwnd(hhPrint->hSession), achBuf, achTitle, MB_ICONEXCLAMATION | MB_OK, 0); return -1; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- * FUNCTION: * printSetFont * * DESCRIPTION: * Sets the terminal font to the given font. If hFont is zero, * termSetFont() trys to create a default font. * * ARGUMENTS: * hhTerm - internal term handle. * plf - pointer to logfont * * RETURNS: * BOOL * */ BOOL printSetFont(const HHPRINT hhPrint) { LOGFONT lf; lf = hhPrint->lf; lf.lfHeight = hhPrint->iFontPointSize; printCreatePointFont( &lf, hhPrint ); SelectObject( hhPrint->hDC, hhPrint->hFont ); return TRUE; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- * FUNCTION: * printCreatePointFont * * DESCRIPTION: * Creates a hFont based on the log font structure given. This function assumes * the height member of the log font structure to be in 1/10 of a point * increments. A 12 point font would be represented as 120. The hFont is stored * in the print handle provided. * * ARGUMENTS: * pLogFont - A pointer to a log font structure. * hhPrint - A print handle to store the HFONT into. * * RETURNS: * void * */ void printCreatePointFont( LOGFONT * pLogFont, HHPRINT hhPrint ) { POINT pt; POINT ptOrg = { 0, 0 }; if (hhPrint->hFont) { DeleteObject(hhPrint->hFont); } pt.y = GetDeviceCaps(hhPrint->hDC, LOGPIXELSY) * pLogFont->lfHeight; pt.y /= 720; DPtoLP(hhPrint->hDC, &pt, 1); DPtoLP(hhPrint->hDC, &ptOrg, 1); pLogFont->lfHeight = -abs(pt.y - ptOrg.y); hhPrint->hFont = CreateFontIndirect( pLogFont ); return; } /******************************************************************************* * FUNCTION: * printSetMargins * * DESCRIPTION: * Sets the margins for the print handle, by converting from the values * returned by the page setup dialog. * * ARGUMENTS: * aMargins - A RECT structure that contains the margins in inches. * * Return: * void * * Author: dmn:02/19/97 * */ void printSetMargins( HHPRINT hhPrint ) { int iPixelsPerInchX; int iPixelsPerInchY; int iPhysicalOffsetX; int iPhysicalOffsetY; if ( hhPrint->hDC ) { hhPrint->marginsDC = hhPrint->margins; // // convert the margins to pixels // iPixelsPerInchX = GetDeviceCaps( hhPrint->hDC, LOGPIXELSX ); iPixelsPerInchY = GetDeviceCaps( hhPrint->hDC, LOGPIXELSY ); hhPrint->marginsDC.left = ( hhPrint->marginsDC.left * iPixelsPerInchX ) / 1000; hhPrint->marginsDC.right = ( hhPrint->margins.right * iPixelsPerInchX ) / 1000; hhPrint->marginsDC.top = ( hhPrint->marginsDC.top * iPixelsPerInchY ) / 1000; hhPrint->marginsDC.bottom = ( hhPrint->marginsDC.bottom * iPixelsPerInchY ) / 1000; iPhysicalOffsetX = GetDeviceCaps( hhPrint->hDC ,PHYSICALOFFSETX ); iPhysicalOffsetY = GetDeviceCaps( hhPrint->hDC, PHYSICALOFFSETY ); hhPrint->marginsDC.left = max( 0, hhPrint->marginsDC.left - iPhysicalOffsetX ); hhPrint->marginsDC.right = max( 0, hhPrint->marginsDC.right - iPhysicalOffsetX ); hhPrint->marginsDC.top = max( 0, hhPrint->marginsDC.top - iPhysicalOffsetY ); hhPrint->marginsDC.bottom = max( 0, hhPrint->marginsDC.bottom - iPhysicalOffsetY ); } return; }