text.c
上传用户:yuandong
上传日期:2022-08-08
资源大小:954k
文件大小:22k
源码类别:

Delphi控件源码

开发平台:

C++ Builder

  1. /*++
  2. Copyright (c) 1990-1999  Microsoft Corporation
  3. All Rights Reserved
  4. Abstract:
  5.     Routines to facilitate printing of text jobs.
  6. --*/
  7. #include "local.h"
  8. #define FLAG_CR_STATE         0x1
  9. #define FLAG_TAB_STATE        0x2
  10. #define FLAG_DBCS_SPLIT       0x8
  11. #define FLAG_FF               0x10
  12. #define FLAG_LF               0x20
  13. #define FLAG_CR               0x40
  14. #define FLAG_TRANSLATE_LF     0x80
  15. #define FLAG_TRANSLATE_CR     0x100
  16. const WCHAR gszNoTranslateCRLF[] = L"Winprint_TextNoTranslation";
  17. const WCHAR gszNoTranslateCR[] = L"Winprint_TextNoCRTranslation";
  18. /** Prototypes for functions in this file **/
  19. PBYTE
  20. GetTabbedLineFromBuffer(
  21.     IN      PBYTE   pSrcBuffer,
  22.     IN      PBYTE   pSrcBufferEnd,
  23.     IN      PBYTE   pDestBuffer,
  24.     IN      ULONG   CharsPerLine,
  25.     IN      ULONG   TabExpansionSize,
  26.     IN      ULONG   Encoding,
  27.     IN OUT  PULONG  pLength,
  28.     IN OUT  PULONG  pTabBase,
  29.     IN OUT  PDWORD  pfdwFlags
  30.     );
  31. /*++
  32. *******************************************************************
  33.     P r i n t T e x t J o b
  34.     Routine Description:
  35.         Prints a text data job.
  36.     Arguments:
  37.         pData           => Data structure for this job
  38.         pDocumentName   => Name of this document
  39.     Return Value:
  40.         TRUE  if successful
  41.         FALSE if failed - GetLastError() will return reason.
  42. *******************************************************************
  43. --*/
  44. BOOL
  45. PrintTextJob(
  46.     IN PPRINTPROCESSORDATA pData,
  47.     IN LPWSTR pDocumentName)
  48. {
  49.     DOCINFO     DocInfo;
  50.     LOGFONT     LogFont;
  51.     CHARSETINFO CharSetInfo;
  52.     HFONT       hOldFont, hFont;
  53.     DWORD       Copies;
  54.     BOOL        rc;
  55.     DWORD       NoRead;
  56.     DWORD       CurrentLine;
  57.     DWORD       CurrentCol;
  58.     HANDLE      hPrinter = NULL;
  59.     BYTE        pReadBufferStart[READ_BUFFER_SIZE];
  60.     PBYTE       pLineBuffer = NULL;
  61.     PBYTE       pReadBuffer = NULL;
  62.     PBYTE       pReadBufferEnd = NULL;
  63.     ULONG       CharHeight, CharWidth, CharsPerLine, LinesPerPage;
  64.     ULONG       PageWidth, PageHeight;
  65.     ULONG       Length, TabBase;
  66.     BOOL        ReadAll;
  67.     TEXTMETRIC  tm;
  68.     DWORD       fdwFlags;
  69.     DWORD       Encoding;
  70.     DWORD       SplitSize;
  71.     BOOL        ReturnValue = FALSE;
  72.     BOOL        bAbortDoc   = FALSE;
  73.     DWORD       dwNeeded;
  74.     DWORD       dwNoTranslate;
  75.     DWORD       dwNoTranslateCR;
  76.     DocInfo.lpszDocName = pData->pDocument;  /* Document name */
  77.     DocInfo.lpszOutput  = NULL;              /* Output file */
  78.     DocInfo.lpszDatatype = NULL;             /* Datatype */
  79.     DocInfo.cbSize = sizeof(DOCINFO);        /* Size of the structure */
  80.     //
  81.     // Go figure out the size of the form on the printer.  We do this
  82.     // by calling GetTextMetrics, which gives us the font size of the
  83.     // printer font, then getting the form size and calculating the
  84.     // number of characters that will fit. In other cases we treat it as ANSI text.
  85.     // Currently the codepage context is fixed to the system default codepage.
  86.     //
  87.     Encoding = GetACP();
  88.     //
  89.     // Create FIXED PITCH font and select
  90.     //
  91.     hOldFont = 0;
  92.     ZeroMemory(&CharSetInfo, sizeof(CHARSETINFO));
  93.     if (TranslateCharsetInfo((PDWORD)Encoding, &CharSetInfo, TCI_SRCCODEPAGE))
  94.     {
  95.         ZeroMemory(&LogFont, sizeof(LOGFONT));
  96.         LogFont.lfWeight = 400;
  97.         LogFont.lfCharSet = (BYTE)CharSetInfo.ciCharset;
  98.         LogFont.lfPitchAndFamily = FIXED_PITCH;
  99.         hFont = CreateFontIndirect(&LogFont);
  100.         hOldFont = SelectObject(pData->hDC, hFont);
  101.     }
  102.     if (!GetTextMetrics(pData->hDC, &tm)) {
  103.         // Essential text processing computation failed
  104.         goto Done;
  105.     }
  106.     CharHeight = tm.tmHeight + tm.tmExternalLeading;
  107.     CharWidth  = tm.tmAveCharWidth;
  108.     if (!CharWidth || !CharHeight) {
  109.         // Essential text processing computation failed
  110.         goto Done;
  111.     }
  112.     //
  113.     // Calculate most fittable characters' number to one line.
  114.     //
  115.     PageWidth = GetDeviceCaps(pData->hDC, DESKTOPHORZRES);
  116.     PageHeight = GetDeviceCaps(pData->hDC, DESKTOPVERTRES);
  117.     CharsPerLine = PageWidth / CharWidth;
  118.     LinesPerPage = PageHeight / CharHeight;
  119.     if (!CharsPerLine || !LinesPerPage) {
  120.         // Essential text processing computation failed
  121.         goto Done;
  122.     }
  123.     /** Allocate a buffer for one line of text **/
  124.     pLineBuffer = AllocSplMem(CharsPerLine + 5);
  125.     if (!pLineBuffer) {
  126.         return FALSE;
  127.     }
  128.     /** Let the printer know we are starting a new document **/
  129.     if (!StartDoc(pData->hDC, (LPDOCINFO)&DocInfo)) {
  130.         goto Done;
  131.     }
  132.     /** Print the data pData->Copies times **/
  133.     Copies = pData->Copies;
  134.     while (Copies--) {
  135.         /**
  136.             Loop, getting data and sending it to the printer.  This also
  137.             takes care of pausing and cancelling print jobs by checking
  138.             the processor's status flags while printing.  The way we do
  139.             this is to read in some data from the printer.  We will then
  140.             pull data, one tabbed line at a time from there and print
  141.             it.  If the last bit of data in the buffer does not make up
  142.             a whole line, we call GetTabbedLineFromBuffer() with a non-
  143.             zero Length, which indicates that there are chars left
  144.             from the previous read.
  145.         **/
  146.         TabBase = 0;
  147.         Length = 0;
  148.         fdwFlags = FLAG_TRANSLATE_CR | FLAG_TRANSLATE_LF;
  149.         CurrentLine = 0;
  150.         CurrentCol = 0;
  151.         /**
  152.             Open the printer.  If it fails, return.  This also sets up the
  153.             pointer for the ReadPrinter calls.
  154.         **/
  155.         if (!OpenPrinter(pDocumentName, &hPrinter, NULL)) {
  156.             hPrinter = NULL;
  157.             bAbortDoc = TRUE;
  158.             goto Done;
  159.         }
  160.         //
  161.         // Call GetPrinterData to see if the queue wants no LF/CR processing.
  162.         //
  163.         if( GetPrinterData( hPrinter,
  164.                             (LPWSTR)gszNoTranslateCRLF,
  165.                             NULL,
  166.                             (PBYTE)&dwNoTranslate,
  167.                             sizeof( dwNoTranslate ),
  168.                             &dwNeeded ) == ERROR_SUCCESS ){
  169.             if( dwNoTranslate ){
  170.                 fdwFlags &= ~( FLAG_TRANSLATE_CR | FLAG_TRANSLATE_LF );
  171.             }
  172.         }
  173.         //
  174.         // Call GetPrinterData to see if the queue wants no CR processing.
  175.         //
  176.         if( GetPrinterData( hPrinter,
  177.                             (LPWSTR)gszNoTranslateCR,
  178.                             NULL,
  179.                             (PBYTE)&dwNoTranslateCR,
  180.                             sizeof( dwNoTranslateCR ),
  181.                             &dwNeeded ) == ERROR_SUCCESS ){
  182.             if( dwNoTranslateCR ){
  183.                 fdwFlags &= ~FLAG_TRANSLATE_CR;                
  184.             }
  185.         }
  186.         if (StartPage(pData->hDC) == SP_ERROR) {
  187.             bAbortDoc = TRUE;
  188.             goto Done;
  189.         }
  190.         /** ReadAll indicates if we are on the last line of the file **/
  191.         ReadAll = FALSE;
  192.         /**
  193.             This next do loop continues until we have read all of the
  194.             data for the print job.
  195.         **/
  196.         do {
  197.             if (fdwFlags & FLAG_DBCS_SPLIT) {
  198.                 SplitSize = (DWORD)(pReadBufferEnd - pReadBuffer);
  199.                 memcpy(pReadBufferStart, pReadBuffer, SplitSize);
  200.                 fdwFlags &= ~FLAG_DBCS_SPLIT;
  201.             }
  202.             else {
  203.                 SplitSize = 0;
  204.             }
  205.             rc = ReadPrinter(hPrinter,
  206.                              (pReadBufferStart + SplitSize),
  207.                              (READ_BUFFER_SIZE - SplitSize),
  208.                              &NoRead);
  209.             if (!rc || !NoRead) {
  210.                 ReadAll = TRUE;
  211.             } else {
  212.                 /** Pick up a pointer to the end of the data **/
  213.                 pReadBuffer    = pReadBufferStart;
  214.                 pReadBufferEnd = pReadBufferStart + SplitSize + NoRead;
  215.             }
  216.             /**
  217.                 This loop will process all the data that we have
  218.                 just read from the printer.
  219.             **/
  220.             do {
  221.                 if (!ReadAll) {
  222.                     /**
  223.                         Length on entry holds the length of any
  224.                         residual chars from the last line that we couldn't
  225.                         print out because we ran out of characters on
  226.                         the ReadPrinter buffer.
  227.                     **/
  228.                     pReadBuffer = GetTabbedLineFromBuffer(
  229.                                       pReadBuffer,
  230.                                       pReadBufferEnd,
  231.                                       pLineBuffer,
  232.                                       CharsPerLine - CurrentCol,
  233.                                       pData->TabSize,
  234.                                       Encoding,
  235.                                       &Length,
  236.                                       &TabBase,
  237.                                       &fdwFlags );
  238.                     /**
  239.                         If pReadBuffer == NULL, then we have
  240.                         exhausted the read buffer and we need to ReadPrinter
  241.                         again and save the last line chars.  Length holds
  242.                         the number of characters on this partial line,
  243.                         so the next time we call ReadPrinter we will
  244.                         pickup where we left off.
  245.                         The only time we'll get residual chars is if:
  246.                         1. The last line ends w/o ff/lf/cr ("HelloEOF")
  247.                            In this case we should TextOutA the last line
  248.                            and then quit.
  249.                            (In this case, don't break here; go ahead and
  250.                            print, then we'll break out below in the do..while.)
  251.                         2. The ReadPrinter last byte is in the middle of a line.
  252.                            Here we should read the next chunk and add the
  253.                            new characters at the end of the chars we just read.
  254.                            (In this case, we should break and leave Length
  255.                            as it is so we will read again and append to the
  256.                            buffer, beginning at Length.)
  257.                     **/
  258.                     if (!pReadBuffer || (fdwFlags & FLAG_DBCS_SPLIT))
  259.                         break;
  260.                 }
  261.                 /** If the print processor is paused, wait for it to be resumed **/
  262.                 if (pData->fsStatus & PRINTPROCESSOR_PAUSED) {
  263.                     WaitForSingleObject(pData->semPaused, INFINITE);
  264.                 }
  265.                 /** If the job has been aborted, clean up and leave **/
  266.                 if (pData->fsStatus & PRINTPROCESSOR_ABORTED) {
  267.                     ReturnValue = TRUE;
  268.                     bAbortDoc = TRUE;
  269.                     goto Done;
  270.                 }
  271.                 /** Write the data to the printer **/
  272.                 /** Make sure Length is not zero  **/
  273.                 /** TextOut will fail if Length == 0 **/
  274.                 if (Length) {
  275.                     /**
  276.                         We may have a number of newlines pending, that
  277.                         may push us to the next page (or even next-next
  278.                         page).
  279.                     **/
  280.                     while (CurrentLine >= LinesPerPage) {
  281.                         /**
  282.                             We need a new page; always defer this to the
  283.                             last second to prevent extra pages from coming out.
  284.                         **/
  285.                         if (EndPage(pData->hDC) == SP_ERROR ||
  286.                             StartPage(pData->hDC) == SP_ERROR) {
  287.                             bAbortDoc = TRUE;
  288.                             goto Done;
  289.                         }
  290.                         CurrentLine -= LinesPerPage;
  291.                     }
  292.                     if (TextOutA(pData->hDC,
  293.                                  CurrentCol * CharWidth,
  294.                                  CurrentLine * CharHeight,
  295.                                  pLineBuffer,
  296.                                  Length) == FALSE) {
  297.                         ODS(("TextOut() failedn"));
  298.                         bAbortDoc = TRUE;
  299.                         goto Done;
  300.                     }
  301.                     CurrentCol += Length;
  302.                 }
  303.                 /**
  304.                     Even if the length is zero, increment the line.
  305.                     Should happen when the character is only 0x0D or 0x0A.
  306.                 **/
  307.                 if (fdwFlags & FLAG_CR) {
  308.                     CurrentCol=0;
  309.                     fdwFlags &= ~FLAG_CR;
  310.                 }
  311.                 if (fdwFlags & FLAG_LF) {
  312.                     CurrentLine++;
  313.                     fdwFlags &= ~FLAG_LF;
  314.                 }
  315.                 /**
  316.                     We need a new page.  Set the current line to the
  317.                     end of the page.  We could do a End/StartPage
  318.                     sequence, but this may cause a blank page to get
  319.                     ejected.
  320.                     Note: this code will avoid printing out pages that
  321.                     consist of formfeeds only (if you have a page with a
  322.                     space in it, that counts as text).
  323.                 **/
  324.                 if (fdwFlags & FLAG_FF) {
  325.                     CurrentLine = LinesPerPage;
  326.                     CurrentCol = 0;
  327.                     fdwFlags &= ~FLAG_FF;
  328.                 }
  329.                 /**
  330.                     We have done the text out, so these characters have
  331.                     been successfully printed.  Zero out Length
  332.                     so these characters won't be printed again
  333.                 **/
  334.                 Length = 0;
  335.                 /**
  336.                     We only terminate this loop if we run out of chars
  337.                     or we run out of read buffer.
  338.                 **/
  339.             } while (pReadBuffer && pReadBuffer != pReadBufferEnd);
  340.             /** Keep going until we get the last line **/
  341.         } while (!ReadAll);
  342.         if (EndPage(pData->hDC) == SP_ERROR) {
  343.             bAbortDoc = TRUE;
  344.             goto Done;
  345.         }
  346.         /**
  347.             Close the printer - we open/close the printer for each
  348.             copy so the data pointer will rewind.
  349.         **/
  350.         ClosePrinter(hPrinter);
  351.         hPrinter = NULL;
  352.     } /* While copies to print */
  353.     /** Let the printer know that we are done printing **/
  354.     EndDoc(pData->hDC);
  355.     ReturnValue = TRUE;
  356. Done:
  357.     if (hPrinter)
  358.         ClosePrinter(hPrinter);
  359.     if (bAbortDoc)
  360.         AbortDoc(pData->hDC);
  361.     if (pLineBuffer)
  362.         FreeSplMem(pLineBuffer);
  363.     if (hOldFont)
  364.     {
  365.         SelectObject(pData->hDC, hOldFont);
  366.         DeleteObject(hFont);
  367.     }
  368.     return ReturnValue;
  369. }
  370. /*++
  371. *******************************************************************
  372.     G e t T a b b e d L i n e F r o m B u f f e r
  373.     Routine Description:
  374.         This routine, given a buffer of text, will pull out a
  375.         line of tab-expanded text.  This is used for tab
  376.         expansion of text data jobs.
  377.     Arguments:
  378.         pSrcBuffer      => Start of source buffer.
  379.         pSrcBufferEnd   => End of source buffer
  380.         pDestBuffer     => Start of destination buffer
  381.         CharsPerLine    => Number of characters on a line
  382.         TabExpansionSize=> Number of spaces in a tab
  383.         Encoding        => Code page
  384.         pLength         => Length of chars from prev line, rets current
  385.         pTabBase        => New 0 offset for tabbing
  386.         pfdwFlags       => State
  387.     Return Value:
  388.         PBYTE => Place left off in the source buffer.  This should
  389.                  be passed in on the next call.  If we ran out of
  390.                  data in the source, this will be unchanged.
  391. *******************************************************************
  392. --*/
  393. PBYTE
  394. GetTabbedLineFromBuffer(
  395.     IN      PBYTE   pSrcBuffer,
  396.     IN      PBYTE   pSrcBufferEnd,
  397.     IN      PBYTE   pDestBuffer,
  398.     IN      ULONG   CharsPerLine,
  399.     IN      ULONG   TabExpansionSize,
  400.     IN      ULONG   Encoding,
  401.     IN OUT  PULONG  pLength,
  402.     IN OUT  PULONG  pTabBase,
  403.     IN OUT  PDWORD  pfdwFlags
  404.     )
  405. {
  406.     ULONG   current_pos;
  407.     ULONG   expand, i;
  408.     ULONG   TabBase = *pTabBase;
  409.     ULONG   TabBaseLeft = TabExpansionSize-TabBase;
  410.     PBYTE   pDestBufferEnd = pDestBuffer + CharsPerLine;
  411.     /**
  412.         If the tab pushed us past the end of the last line, then we need to
  413.         add it back to the next one.
  414.     **/
  415.     if (TabBase && ( *pfdwFlags & FLAG_TAB_STATE )) {
  416.         current_pos = 0;
  417.         i=TabBase;
  418.         while (i-- && (pDestBuffer < pDestBufferEnd)) {
  419.             *pDestBuffer++ = ' ';
  420.             current_pos++;
  421.         }
  422.         /**
  423.             If we ran out of room again, return.  This means that
  424.             the tab expansion size is greater than we can fit on
  425.             one line.
  426.         **/
  427.         if (pDestBuffer >= pDestBufferEnd) {
  428.             *pLength = current_pos;
  429.             pTabBase -= CharsPerLine;
  430.             //
  431.             // We need to move to the next line.
  432.             //
  433.             *pfdwFlags |= FLAG_LF | FLAG_CR;
  434.             return pSrcBuffer;
  435.         }
  436.         *pfdwFlags &= ~FLAG_TAB_STATE;
  437.     } else {
  438.         /** We may have some chars from the previous ReadPrinter **/
  439.         current_pos = *pLength;
  440.         pDestBuffer += current_pos;
  441.     }
  442.     while (pSrcBuffer < pSrcBufferEnd) {
  443.         /** Now process other chars **/
  444.         switch (*pSrcBuffer) {
  445.         case 0x0C:
  446.             /** Found a FF.  Quit and indicate we need to start a new page **/
  447.             *pTabBase = 0;
  448.             *pfdwFlags |= FLAG_FF;
  449.             *pfdwFlags &= ~FLAG_CR_STATE;
  450.             pSrcBuffer++;
  451.             break;
  452.         case 't':
  453.             *pfdwFlags &= ~FLAG_CR_STATE;
  454.             /**
  455.                 Handle TAB case.  If we are really out of buffer,
  456.                 then defer now so that the tab will be saved for
  457.                 the next line.
  458.             **/
  459.             if (pDestBuffer >= pDestBufferEnd) {
  460.                 goto ShiftTab;
  461.             }
  462.             pSrcBuffer++;
  463.             /** Figure out how far to expand the tabs **/
  464.             expand = TabExpansionSize -
  465.                      (current_pos + TabBaseLeft) % TabExpansionSize;
  466.             /** Expand the tabs **/
  467.             for (i = 0; (i < expand) && (pDestBuffer < pDestBufferEnd); i++) {
  468.                 *pDestBuffer++ = ' ';
  469.             }
  470.             /**
  471.                 If we reached the end of our dest buffer,
  472.                 return and set the number of spaces we have left.
  473.             **/
  474.             if (pDestBuffer >= pDestBufferEnd) {
  475.                 *pfdwFlags |= FLAG_TAB_STATE;
  476.                 goto ShiftTab;
  477.             }
  478.             /** Update our position counter **/
  479.             current_pos += expand;
  480.             continue;
  481.         case 0x0A:
  482.             pSrcBuffer++;
  483.             /** If the last char was a CR, ignore this guy **/
  484.             if (*pfdwFlags & FLAG_CR_STATE) {
  485.                 *pfdwFlags &= ~FLAG_CR_STATE;
  486.                 //
  487.                 // We are translating CRLF, so if we saw a CR
  488.                 // immediately before this, then don't do anything.
  489.                 //
  490.                 continue;
  491.             }
  492.             if( *pfdwFlags & FLAG_TRANSLATE_LF ){
  493.            
  494.                 //
  495.                 // If we are translating, then treat a LF as a CRLF pair.
  496.                 //
  497.                 *pfdwFlags |= FLAG_LF | FLAG_CR;
  498.                 /** Found a linefeed.  That's it for this line. **/
  499.                 *pTabBase = 0;
  500.             } else {
  501.                 *pfdwFlags |= FLAG_LF;
  502.             }
  503.             break;
  504.         case 0x0D:
  505.             /** Found a carriage return.  That's it for this line. **/
  506.             *pTabBase = 0;
  507.             pSrcBuffer++;
  508.             if (*pfdwFlags & FLAG_TRANSLATE_CR) {
  509.                 //
  510.                 // If we are translating CRLF, then make the newline
  511.                 // occur now.  This handles the case where we have a
  512.                 // CR all by itself.  Also set the CR flag so if there
  513.                 // happens to be a LF immediately after this, we don't
  514.                 // move down another line.
  515.                 //
  516.                 *pfdwFlags |= FLAG_CR_STATE | FLAG_LF | FLAG_CR;
  517.             } else {
  518.                 
  519.                 *pfdwFlags |= FLAG_CR;
  520.             }
  521.             break;
  522.         default:
  523.             /** Not tab or carriage return, must be simply data **/
  524.             *pfdwFlags &= ~FLAG_CR_STATE;
  525.             //
  526.             // We always check before we are adding a character
  527.             // (instead of after) since we may be at the end of a line,
  528.             // but we can still process chars like 0x0d 0x0a.
  529.             // This happens in MS-DOS printscreen.
  530.             //
  531.             if (pDestBuffer >= pDestBufferEnd ||
  532.                     (pDestBuffer + 1 >= pDestBufferEnd) &&
  533.                     IsDBCSLeadByteEx(Encoding, *pSrcBuffer)) {
  534. ShiftTab:
  535.                 //
  536.                 // We must shift the tab over since we are on the
  537.                 // same line.
  538.                 //
  539.                 *pTabBase = (*pTabBase + TabExpansionSize -
  540.                             (CharsPerLine % TabExpansionSize))
  541.                                 % TabExpansionSize;
  542.                 *pfdwFlags |= FLAG_LF | FLAG_CR;
  543.                 break;
  544.             }
  545.             if (IsDBCSLeadByteEx(Encoding, *pSrcBuffer)) {
  546.                 // Check if we have trail byte also.
  547.                 if (pSrcBuffer + 1 >= pSrcBufferEnd) {
  548.                     *pfdwFlags |= FLAG_DBCS_SPLIT;
  549.                     break;
  550.                 }
  551.                 // Advance source pointer (for lead byte).
  552.                 *pDestBuffer++ = *pSrcBuffer++;
  553.                 current_pos++;
  554.             }
  555.             *pDestBuffer++ = *pSrcBuffer++;
  556.             current_pos++;
  557.             continue;
  558.         }
  559.         *pLength = current_pos;
  560.         return pSrcBuffer;
  561.     }
  562.     /** We ran out of source buffer before getting to the EOL **/
  563.     *pLength = current_pos;
  564.     return NULL;
  565. }