Windows程序设计-使用打印机

本文深入探讨了Windows平台上的打印程序实现细节,包括如何获取打印设备环境、实现基本打印功能、添加打印菜单项、使用对话框进行打印控制以及如何在应用程序中集成打印功能等。文章通过多个示例代码片段展示了打印过程中的关键步骤和技术要点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

打印机参数

打印机参数
RESOURCE.H

#define IDM_SCREEN                      40001
#define IDM_BASIC                       40002
#define IDM_OTHER                       40003
#define IDM_CURVE                       40004
#define IDM_LINE                        40005
#define IDM_POLY                        40006
#define IDM_TEXT                        40007

DevCaps2.rc

/
//
// Menu
//

DEVCAPS2 MENU DISCARDABLE 
BEGIN
    POPUP "&Device"
    BEGIN
        MENUITEM "&Screen",                     IDM_SCREEN, CHECKED
    END
    POPUP "&Capabilities"
    BEGIN
        MENUITEM "&Basic Information",          IDM_BASIC
        MENUITEM "&Other Information",          IDM_OTHER
        MENUITEM "&Curve Capabilities",         IDM_CURVE
        MENUITEM "&Line Capabilities",          IDM_LINE
        MENUITEM "&Polygonal Capabilities",     IDM_POLY
        MENUITEM "&Text Capabilities",          IDM_TEXT
    END
END

DEVCAPS2.C

/*------------------------------------------------------------------
   DEVCAPS2.C -- Displays Device Capability Information (Version 2)
                 (c) Charles Petzold, 1998
------------------------------------------------------------------*/

#include <windows.h>
#include "resource.h"

LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
void DoBasicInfo    (HDC, HDC, int, int) ;
void DoOtherInfo    (HDC, HDC, int, int) ;
void DoBitCodedCaps (HDC, HDC, int, int, int) ;

typedef struct
{
     int     iMask ;
     TCHAR * szDesc ;
}
BITS ;

#define IDM_DEVMODE      1000

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    PSTR szCmdLine, int iCmdShow)
{
     static TCHAR szAppName[] = TEXT ("DevCaps2") ;
     HWND         hwnd ;
     MSG          msg ;
     WNDCLASS     wndclass ;

     wndclass.style         = CS_HREDRAW | CS_VREDRAW ;
     wndclass.lpfnWndProc   = WndProc ;
     wndclass.cbClsExtra    = 0 ;
     wndclass.cbWndExtra    = 0 ;
     wndclass.hInstance     = hInstance ;
     wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION) ;
     wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
     wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
     wndclass.lpszMenuName  = szAppName ;
     wndclass.lpszClassName = szAppName ;

     if (!RegisterClass (&wndclass))
     {
          MessageBox (NULL, TEXT ("This program requires Windows NT!"),
                      szAppName, MB_ICONERROR) ;
          return 0 ;
     }

     hwnd = CreateWindow (szAppName, NULL,
                          WS_OVERLAPPEDWINDOW,
                          CW_USEDEFAULT, CW_USEDEFAULT,
                          CW_USEDEFAULT, CW_USEDEFAULT,
                          NULL, NULL, hInstance, NULL) ;

     ShowWindow (hwnd, iCmdShow) ;
     UpdateWindow (hwnd) ;

     while (GetMessage (&msg, NULL, 0, 0))
     {
          TranslateMessage (&msg) ;
          DispatchMessage (&msg) ;
     }
     return msg.wParam ;
}

LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
     static TCHAR            szDevice[32], szWindowText[64] ;
     static int              cxChar, cyChar, nCurrentDevice = IDM_SCREEN,
                                             nCurrentInfo   = IDM_BASIC ;
     static DWORD            dwNeeded, dwReturned ;
     static PRINTER_INFO_4 * pinfo4 ;
     static PRINTER_INFO_5 * pinfo5 ;
     DWORD                   i ;
     HDC                     hdc, hdcInfo ;
     HMENU                   hMenu ;
     HANDLE                  hPrint ;
     PAINTSTRUCT             ps ;
     TEXTMETRIC              tm ;

     switch (message)
     {
     case WM_CREATE :
          hdc = GetDC (hwnd) ;
          SelectObject (hdc, GetStockObject (SYSTEM_FIXED_FONT)) ;
          GetTextMetrics (hdc, &tm) ;
          cxChar = tm.tmAveCharWidth ;
          cyChar = tm.tmHeight + tm.tmExternalLeading ;
          ReleaseDC (hwnd, hdc) ;
                                           // fall through
     case WM_SETTINGCHANGE:
          hMenu = GetSubMenu (GetMenu (hwnd), 0) ;

          while (GetMenuItemCount (hMenu) > 1)
               DeleteMenu (hMenu, 1, MF_BYPOSITION) ;

               // Get a list of all local and remote printers
               // 
               // First, find out how large an array we need; this
               //   call will fail, leaving the required size in dwNeeded
               //
               // Next, allocate space for the info array and fill it
               // 
               // Put the printer names on the menu.

          if (GetVersion () & 0x80000000)         // Windows 98
          {
               EnumPrinters (PRINTER_ENUM_LOCAL, NULL, 5, NULL, 
                             0, &dwNeeded, &dwReturned) ;

               pinfo5 = malloc (dwNeeded) ;

               EnumPrinters (PRINTER_ENUM_LOCAL, NULL, 5, (PBYTE) pinfo5,
                             dwNeeded, &dwNeeded, &dwReturned) ;

               for (i = 0 ; i < dwReturned ; i++)
               {
                    AppendMenu (hMenu, (i+1) % 16 ? 0 : MF_MENUBARBREAK, i + 1, 
                                pinfo5[i].pPrinterName) ;
               }
               free (pinfo5) ;
          }
          else                                    // Windows NT
          {
               EnumPrinters (PRINTER_ENUM_LOCAL, NULL, 4, NULL, 
                             0, &dwNeeded, &dwReturned) ;

               pinfo4 = malloc (dwNeeded) ;

               EnumPrinters (PRINTER_ENUM_LOCAL, NULL, 4, (PBYTE) pinfo4,
                             dwNeeded, &dwNeeded, &dwReturned) ;

               for (i = 0 ; i < dwReturned ; i++)
               {
                    AppendMenu (hMenu, (i+1) % 16 ? 0 : MF_MENUBARBREAK, i + 1, 
                                pinfo4[i].pPrinterName) ;
               }
               free (pinfo4) ;
          }

          AppendMenu (hMenu, MF_SEPARATOR, 0, NULL) ;
          AppendMenu (hMenu, 0, IDM_DEVMODE, TEXT ("Properties")) ;

          wParam = IDM_SCREEN ; 
                                             // fall through
     case WM_COMMAND :
          hMenu = GetMenu (hwnd) ;

          if (LOWORD (wParam) == IDM_SCREEN ||         // IDM_SCREEN & Printers
              LOWORD (wParam) < IDM_DEVMODE)       
          {
               CheckMenuItem (hMenu, nCurrentDevice, MF_UNCHECKED) ;
               nCurrentDevice = LOWORD (wParam) ;
               CheckMenuItem (hMenu, nCurrentDevice, MF_CHECKED) ;
          }
          else if (LOWORD (wParam) == IDM_DEVMODE)     // Properties selection
          {
               GetMenuString (hMenu, nCurrentDevice, szDevice,
                              sizeof (szDevice) / sizeof (TCHAR), MF_BYCOMMAND);

               if (OpenPrinter (szDevice, &hPrint, NULL))
               {
                    PrinterProperties (hwnd, hPrint) ;
                    ClosePrinter (hPrint) ;
               }
          }
          else                               // info menu items
          {
               CheckMenuItem (hMenu, nCurrentInfo, MF_UNCHECKED) ;
               nCurrentInfo = LOWORD (wParam) ;
               CheckMenuItem (hMenu, nCurrentInfo, MF_CHECKED) ;
          }
          InvalidateRect (hwnd, NULL, TRUE) ;
          return 0 ;

     case WM_INITMENUPOPUP :
          if (lParam == 0)
               EnableMenuItem (GetMenu (hwnd), IDM_DEVMODE,
                    nCurrentDevice == IDM_SCREEN ? MF_GRAYED : MF_ENABLED) ;
          return 0 ;

     case WM_PAINT :
          lstrcpy (szWindowText, TEXT ("Device Capabilities: ")) ;

          if (nCurrentDevice == IDM_SCREEN)
          {
               lstrcpy (szDevice, TEXT ("DISPLAY")) ;
               hdcInfo = CreateIC (szDevice, NULL, NULL, NULL) ;
          }
          else
          {
               hMenu = GetMenu (hwnd) ;
               GetMenuString (hMenu, nCurrentDevice, szDevice,
                              sizeof (szDevice), MF_BYCOMMAND) ;
               hdcInfo = CreateIC (NULL, szDevice, NULL, NULL) ;
          }

          lstrcat (szWindowText, szDevice) ;
          SetWindowText (hwnd, szWindowText) ;

          hdc = BeginPaint (hwnd, &ps) ;
          SelectObject (hdc, GetStockObject (SYSTEM_FIXED_FONT)) ;

          if (hdcInfo)
          {
               switch (nCurrentInfo)
               {
               case IDM_BASIC :
                    DoBasicInfo (hdc, hdcInfo, cxChar, cyChar) ;
                    break ;

               case IDM_OTHER :
                    DoOtherInfo (hdc, hdcInfo, cxChar, cyChar) ;
                    break ;

               case IDM_CURVE :
               case IDM_LINE :
               case IDM_POLY :
               case IDM_TEXT :
                    DoBitCodedCaps (hdc, hdcInfo, cxChar, cyChar,
                                    nCurrentInfo - IDM_CURVE) ;
                    break ;
               }
               DeleteDC (hdcInfo) ;
          }

          EndPaint (hwnd, &ps) ;
          return 0 ;

     case WM_DESTROY :
          PostQuitMessage (0) ;
          return 0 ;
     }
     return DefWindowProc (hwnd, message, wParam, lParam) ;
}

void DoBasicInfo (HDC hdc, HDC hdcInfo, int cxChar, int cyChar)
{
     static struct
     {
          int     nIndex ;
          TCHAR * szDesc ;
     }
     info[] =
     {
          HORZSIZE,        TEXT ("HORZSIZE        Width in millimeters:"),
          VERTSIZE,        TEXT ("VERTSIZE        Height in millimeters:"),
          HORZRES,         TEXT ("HORZRES         Width in pixels:"),
          VERTRES,         TEXT ("VERTRES         Height in raster lines:"),
          BITSPIXEL,       TEXT ("BITSPIXEL       Color bits per pixel:"),
          PLANES,          TEXT ("PLANES          Number of color planes:"),
          NUMBRUSHES,      TEXT ("NUMBRUSHES      Number of device brushes:"),
          NUMPENS,         TEXT ("NUMPENS         Number of device pens:"),
          NUMMARKERS,      TEXT ("NUMMARKERS      Number of device markers:"),
          NUMFONTS,        TEXT ("NUMFONTS        Number of device fonts:"),
          NUMCOLORS,       TEXT ("NUMCOLORS       Number of device colors:"),
          PDEVICESIZE,     TEXT ("PDEVICESIZE     Size of device structure:"),
          ASPECTX,         TEXT ("ASPECTX         Relative width of pixel:"),
          ASPECTY,         TEXT ("ASPECTY         Relative height of pixel:"),
          ASPECTXY,        TEXT ("ASPECTXY        Relative diagonal of pixel:"),
          LOGPIXELSX,      TEXT ("LOGPIXELSX      Horizontal dots per inch:"),
          LOGPIXELSY,      TEXT ("LOGPIXELSY      Vertical dots per inch:"),
          SIZEPALETTE,     TEXT ("SIZEPALETTE     Number of palette entries:"),
          NUMRESERVED,     TEXT ("NUMRESERVED     Reserved palette entries:"),
          COLORRES,        TEXT ("COLORRES        Actual color resolution:"),
          PHYSICALWIDTH,   TEXT ("PHYSICALWIDTH   Printer page pixel width:"),
          PHYSICALHEIGHT,  TEXT ("PHYSICALHEIGHT  Printer page pixel height:"),
          PHYSICALOFFSETX, TEXT ("PHYSICALOFFSETX Printer page x offset:"),
          PHYSICALOFFSETY, TEXT ("PHYSICALOFFSETY Printer page y offset:") 
     } ;
     int   i ;
     TCHAR szBuffer[80] ;

     for (i = 0 ; i < sizeof (info) / sizeof (info[0]) ; i++)
          TextOut (hdc, cxChar, (i + 1) * cyChar, szBuffer,
               wsprintf (szBuffer, TEXT ("%-45s%8d"), info[i].szDesc,
                    GetDeviceCaps (hdcInfo, info[i].nIndex))) ;
}

void DoOtherInfo (HDC hdc, HDC hdcInfo, int cxChar, int cyChar)
{
     static BITS clip[] =
     {
          CP_RECTANGLE,    TEXT ("CP_RECTANGLE    Can Clip To Rectangle:")
     } ; 

     static BITS raster[] =
     {
          RC_BITBLT,       TEXT ("RC_BITBLT       Capable of simple BitBlt:"),
          RC_BANDING,      TEXT ("RC_BANDING      Requires banding support:"),
          RC_SCALING,      TEXT ("RC_SCALING      Requires scaling support:"),
          RC_BITMAP64,     TEXT ("RC_BITMAP64     Supports bitmaps >64K:"),
          RC_GDI20_OUTPUT, TEXT ("RC_GDI20_OUTPUT Has 2.0 output calls:"),
          RC_DI_BITMAP,    TEXT ("RC_DI_BITMAP    Supports DIB to memory:"),
          RC_PALETTE,      TEXT ("RC_PALETTE      Supports a palette:"),
          RC_DIBTODEV,     TEXT ("RC_DIBTODEV     Supports bitmap conversion:"),
          RC_BIGFONT,      TEXT ("RC_BIGFONT      Supports fonts >64K:"),
          RC_STRETCHBLT,   TEXT ("RC_STRETCHBLT   Supports StretchBlt:"),
          RC_FLOODFILL,    TEXT ("RC_FLOODFILL    Supports FloodFill:"),
          RC_STRETCHDIB,   TEXT ("RC_STRETCHDIB   Supports StretchDIBits:")
     } ;

     static TCHAR * szTech[] = { TEXT ("DT_PLOTTER (Vector plotter)"),
                                 TEXT ("DT_RASDISPLAY (Raster display)"),
                                 TEXT ("DT_RASPRINTER (Raster printer)"),
                                 TEXT ("DT_RASCAMERA (Raster camera)"),
                                 TEXT ("DT_CHARSTREAM (Character stream)"),
                                 TEXT ("DT_METAFILE (Metafile)"),
                                 TEXT ("DT_DISPFILE (Display file)") } ;
     int            i ;
     TCHAR          szBuffer[80] ;

     TextOut (hdc, cxChar, cyChar, szBuffer,
          wsprintf (szBuffer, TEXT ("%-24s%04XH"), TEXT ("DRIVERVERSION:"),
               GetDeviceCaps (hdcInfo, DRIVERVERSION))) ;

     TextOut (hdc, cxChar, 2 * cyChar, szBuffer,
          wsprintf (szBuffer, TEXT ("%-24s%-40s"), TEXT ("TECHNOLOGY:"), 
               szTech[GetDeviceCaps (hdcInfo, TECHNOLOGY)])) ;

     TextOut (hdc, cxChar, 4 * cyChar, szBuffer,
          wsprintf (szBuffer, TEXT ("CLIPCAPS (Clipping capabilities)"))) ;

     for (i = 0 ; i < sizeof (clip) / sizeof (clip[0]) ; i++)
          TextOut (hdc, 9 * cxChar, (i + 6) * cyChar, szBuffer,
               wsprintf (szBuffer, TEXT ("%-45s %3s"), clip[i].szDesc,
                    GetDeviceCaps (hdcInfo, CLIPCAPS) & clip[i].iMask ?
                         TEXT ("Yes") : TEXT ("No"))) ;

     TextOut (hdc, cxChar, 8 * cyChar, szBuffer,
          wsprintf (szBuffer, TEXT ("RASTERCAPS (Raster capabilities)"))) ;

     for (i = 0 ; i < sizeof (raster) / sizeof (raster[0]) ; i++)
          TextOut (hdc, 9 * cxChar, (i + 10) * cyChar, szBuffer,
               wsprintf (szBuffer, TEXT ("%-45s %3s"), raster[i].szDesc,
                    GetDeviceCaps (hdcInfo, RASTERCAPS) & raster[i].iMask ?
                         TEXT ("Yes") : TEXT ("No"))) ;
}

void DoBitCodedCaps (HDC hdc, HDC hdcInfo, int cxChar, int cyChar, int iType)
{
     static BITS curves[] =
     {
          CC_CIRCLES,    TEXT ("CC_CIRCLES    Can do circles:"),
          CC_PIE,        TEXT ("CC_PIE        Can do pie wedges:"),
          CC_CHORD,      TEXT ("CC_CHORD      Can do chord arcs:"),
          CC_ELLIPSES,   TEXT ("CC_ELLIPSES   Can do ellipses:"),
          CC_WIDE,       TEXT ("CC_WIDE       Can do wide borders:"),
          CC_STYLED,     TEXT ("CC_STYLED     Can do styled borders:"),
          CC_WIDESTYLED, TEXT ("CC_WIDESTYLED Can do wide and styled borders:"),
          CC_INTERIORS,  TEXT ("CC_INTERIORS  Can do interiors:")
     } ; 

     static BITS lines[] =
     {
          LC_POLYLINE,   TEXT ("LC_POLYLINE   Can do polyline:"),
          LC_MARKER,     TEXT ("LC_MARKER     Can do markers:"),
          LC_POLYMARKER, TEXT ("LC_POLYMARKER Can do polymarkers"),
          LC_WIDE,       TEXT ("LC_WIDE       Can do wide lines:"),
          LC_STYLED,     TEXT ("LC_STYLED     Can do styled lines:"),
          LC_WIDESTYLED, TEXT ("LC_WIDESTYLED Can do wide and styled lines:"),
          LC_INTERIORS,  TEXT ("LC_INTERIORS  Can do interiors:")
     } ;

     static BITS poly[] =
     {
          PC_POLYGON,     
               TEXT ("PC_POLYGON     Can do alternate fill polygon:"),
          PC_RECTANGLE,   TEXT ("PC_RECTANGLE   Can do rectangle:"),
          PC_WINDPOLYGON, 
               TEXT ("PC_WINDPOLYGON Can do winding number fill polygon:"),
          PC_SCANLINE,    TEXT ("PC_SCANLINE    Can do scanlines:"),
          PC_WIDE,        TEXT ("PC_WIDE        Can do wide borders:"),
          PC_STYLED,      TEXT ("PC_STYLED      Can do styled borders:"),
          PC_WIDESTYLED,  
               TEXT ("PC_WIDESTYLED  Can do wide and styled borders:"),
          PC_INTERIORS,   TEXT ("PC_INTERIORS   Can do interiors:")
     } ;

     static BITS text[] =
     {
          TC_OP_CHARACTER, 
               TEXT ("TC_OP_CHARACTER Can do character output precision:"),
          TC_OP_STROKE,    
               TEXT ("TC_OP_STROKE    Can do stroke output precision:"),
          TC_CP_STROKE,    
               TEXT ("TC_CP_STROKE    Can do stroke clip precision:"),
          TC_CR_90,        
               TEXT ("TC_CP_90        Can do 90 degree character rotation:"),
          TC_CR_ANY,       
               TEXT ("TC_CR_ANY       Can do any character rotation:"),
          TC_SF_X_YINDEP,  
               TEXT ("TC_SF_X_YINDEP  Can do scaling independent of X and Y:"),
          TC_SA_DOUBLE,    
               TEXT ("TC_SA_DOUBLE    Can do doubled character for scaling:"),
          TC_SA_INTEGER,   
               TEXT ("TC_SA_INTEGER   Can do integer multiples for scaling:"),
          TC_SA_CONTIN,    
               TEXT ("TC_SA_CONTIN    Can do any multiples for exact scaling:"),
          TC_EA_DOUBLE,    
               TEXT ("TC_EA_DOUBLE    Can do double weight characters:"),
          TC_IA_ABLE,      TEXT ("TC_IA_ABLE      Can do italicizing:"),
          TC_UA_ABLE,      TEXT ("TC_UA_ABLE      Can do underlining:"),
          TC_SO_ABLE,      TEXT ("TC_SO_ABLE      Can do strikeouts:"),
          TC_RA_ABLE,      TEXT ("TC_RA_ABLE      Can do raster fonts:"),
          TC_VA_ABLE,      TEXT ("TC_VA_ABLE      Can do vector fonts:")
     } ;

     static struct
     {
          int     iIndex ;
          TCHAR * szTitle ;
          BITS    (*pbits)[] ;
          int     iSize ;
     }
     bitinfo[] =
     {
          CURVECAPS,  TEXT ("CURVCAPS (Curve Capabilities)"),
               (BITS (*)[]) curves, sizeof (curves) / sizeof (curves[0]),
          LINECAPS,   TEXT ("LINECAPS (Line Capabilities)"),
               (BITS (*)[]) lines, sizeof (lines) / sizeof (lines[0]),
          POLYGONALCAPS, TEXT ("POLYGONALCAPS (Polygonal Capabilities)"),
               (BITS (*)[]) poly, sizeof (poly) / sizeof (poly[0]),
          TEXTCAPS,   TEXT ("TEXTCAPS (Text Capabilities)"),
               (BITS (*)[]) text, sizeof (text) / sizeof (text[0])
     } ;

     static TCHAR szBuffer[80] ;
     BITS         (*pbits)[] = bitinfo[iType].pbits ;
     int          i, iDevCaps = GetDeviceCaps (hdcInfo, bitinfo[iType].iIndex) ;

     TextOut (hdc, cxChar, cyChar, bitinfo[iType].szTitle,
              lstrlen (bitinfo[iType].szTitle)) ;

     for (i = 0 ; i < bitinfo[iType].iSize ; i++)
          TextOut (hdc, cxChar, (i + 3) * cyChar, szBuffer,
               wsprintf (szBuffer, TEXT ("%-55s %3s"), (*pbits)[i].szDesc,
                    iDevCaps & (*pbits)[i].iMask ? TEXT ("Yes") : TEXT ("No")));
}

简单打印

打印
GetPrnDC.c
获取打印设备环境

/*-------------------------------------
   GETPRNDC.C -- GetPrinterDC function
   -------------------------------------*/

#include <windows.h>

HDC GetPrinterDC (void)
{
     DWORD            dwNeeded, dwReturned ;
     HDC              hdc ;
     PRINTER_INFO_4 * pinfo4 ;
     PRINTER_INFO_5 * pinfo5 ; 

     if (GetVersion () & 0x80000000)         // Windows 98
     {
          EnumPrinters (PRINTER_ENUM_DEFAULT, NULL, 5, NULL,
                        0, &dwNeeded, &dwReturned) ;

          pinfo5 = malloc (dwNeeded) ;

          EnumPrinters (PRINTER_ENUM_DEFAULT, NULL, 5, (PBYTE) pinfo5,
                        dwNeeded, &dwNeeded, &dwReturned) ;

          hdc = CreateDC (NULL, pinfo5->pPrinterName, NULL, NULL) ;

          free (pinfo5) ;
     }
     else                                    // Windows NT
     {
          EnumPrinters (PRINTER_ENUM_LOCAL, NULL, 4, NULL,
                        0, &dwNeeded, &dwReturned) ;

          pinfo4 = malloc (dwNeeded) ;

          EnumPrinters (PRINTER_ENUM_LOCAL, NULL, 4, (PBYTE) pinfo4,
                        dwNeeded, &dwNeeded, &dwReturned) ;

          hdc = CreateDC (NULL, pinfo4->pPrinterName, NULL, NULL) ;

          free (pinfo4) ;
     }
     return hdc ;   
}

FormFeed.c

/*---------------------------------------------
   FORMFEED.C -- Advances printer to next page
                 (c) Charles Petzold, 1998
  ---------------------------------------------*/

#include <windows.h>

HDC GetPrinterDC (void) ;

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    LPSTR lpszCmdLine, int iCmdShow)
{
     static DOCINFO di = { sizeof (DOCINFO), TEXT ("FormFeed") } ;
     HDC            hdcPrint = GetPrinterDC () ;

     if (hdcPrint != NULL)
     {
          if (StartDoc (hdcPrint, &di) > 0)
               if (StartPage (hdcPrint) > 0 && EndPage (hdcPrint) > 0)
                    EndDoc (hdcPrint) ;

          DeleteDC (hdcPrint) ;
     }
     return 0 ;
}

打印的基本程序

在系统菜单处,添加打印菜单项。
PRINT.C

/*-----------------------------------------------------------
   PRINT.C -- Common routines for Print1, Print2, and Print3
  -----------------------------------------------------------*/

#include <windows.h>

LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
BOOL PrintMyPage (HWND) ;

extern HINSTANCE hInst ;
extern TCHAR     szAppName[] ;
extern TCHAR     szCaption[] ;

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    PSTR szCmdLine, int iCmdShow)
{
     HWND     hwnd ;
     MSG      msg ;
     WNDCLASS wndclass ;

     wndclass.style         = CS_HREDRAW | CS_VREDRAW ;
     wndclass.lpfnWndProc   = WndProc ;
     wndclass.cbClsExtra    = 0 ;
     wndclass.cbWndExtra    = 0 ;
     wndclass.hInstance     = hInstance ;
     wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION) ;
     wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
     wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
     wndclass.lpszMenuName  = NULL ;
     wndclass.lpszClassName = szAppName ;

     if (!RegisterClass (&wndclass))
     {
          MessageBox (NULL, TEXT ("This program requires Windows NT!"),
                      szAppName, MB_ICONERROR) ;
          return 0 ;
     }

     hInst = hInstance ;

     hwnd = CreateWindow (szAppName, szCaption,
                          WS_OVERLAPPEDWINDOW,
                          CW_USEDEFAULT, CW_USEDEFAULT,
                          CW_USEDEFAULT, CW_USEDEFAULT,
                          NULL, NULL, hInstance, NULL) ;

     ShowWindow (hwnd, iCmdShow) ;
     UpdateWindow (hwnd) ;

     while (GetMessage (&msg, NULL, 0, 0))
     {
          TranslateMessage (&msg) ;
          DispatchMessage (&msg) ;
     }
     return msg.wParam ;
}

void PageGDICalls (HDC hdcPrn, int cxPage, int cyPage)
{
     static TCHAR szTextStr[] = TEXT ("Hello, Printer!") ;

     Rectangle (hdcPrn, 0, 0, cxPage, cyPage) ;

     MoveToEx (hdcPrn, 0, 0, NULL) ;
     LineTo   (hdcPrn, cxPage, cyPage) ;
     MoveToEx (hdcPrn, cxPage, 0, NULL) ;
     LineTo   (hdcPrn, 0, cyPage) ;

     SaveDC (hdcPrn) ;

     SetMapMode       (hdcPrn, MM_ISOTROPIC) ;
     SetWindowExtEx   (hdcPrn, 1000, 1000, NULL) ;
     SetViewportExtEx (hdcPrn, cxPage / 2, -cyPage / 2, NULL) ;
     SetViewportOrgEx (hdcPrn, cxPage / 2,  cyPage / 2, NULL) ;

     Ellipse (hdcPrn, -500, 500, 500, -500) ;

     SetTextAlign (hdcPrn, TA_BASELINE | TA_CENTER) ;
     TextOut (hdcPrn, 0, 0, szTextStr, lstrlen (szTextStr)) ;

     RestoreDC (hdcPrn, -1) ;
}

LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
     static int   cxClient, cyClient ;
     HDC          hdc ;
     HMENU        hMenu ;
     PAINTSTRUCT  ps ;

     switch (message)
     {
     case WM_CREATE:
          hMenu = GetSystemMenu (hwnd, FALSE) ;
          AppendMenu (hMenu, MF_SEPARATOR, 0, NULL) ;
          AppendMenu (hMenu, 0, 1, TEXT ("&Print")) ;
          return 0 ;

     case WM_SIZE:
          cxClient = LOWORD (lParam) ;
          cyClient = HIWORD (lParam) ;
          return 0 ;

     case WM_SYSCOMMAND:
          if (wParam == 1)
          {
               if (!PrintMyPage (hwnd))
                    MessageBox (hwnd, TEXT ("Could not print page!"),
                                szAppName, MB_OK | MB_ICONEXCLAMATION) ;
               return 0 ;
          }
          break ;

     case WM_PAINT :
          hdc = BeginPaint (hwnd, &ps) ;

          PageGDICalls (hdc, cxClient, cyClient) ;

          EndPaint (hwnd, &ps) ;
          return 0 ;

     case WM_DESTROY :
          PostQuitMessage (0) ;
          return 0 ;
     }
     return DefWindowProc (hwnd, message, wParam, lParam) ;
}

Print1.c

/*---------------------------------------
   PRINT1.C -- Bare Bones Printing
               (c) Charles Petzold, 1998
  ---------------------------------------*/

#include <windows.h>

HDC  GetPrinterDC (void) ;              // in GETPRNDC.C
void PageGDICalls (HDC, int, int) ;     // in PRINT.C

HINSTANCE hInst ;
TCHAR     szAppName[] = TEXT ("Print1") ;
TCHAR     szCaption[] = TEXT ("Print Program 1") ;

BOOL PrintMyPage (HWND hwnd)
{
     static DOCINFO di = { sizeof (DOCINFO), TEXT ("Print1: Printing") } ;
     BOOL           bSuccess = TRUE ;
     HDC            hdcPrn ;
     int            xPage, yPage ;

     if (NULL == (hdcPrn = GetPrinterDC ()))
          return FALSE ;

     xPage = GetDeviceCaps (hdcPrn, HORZRES) ;
     yPage = GetDeviceCaps (hdcPrn, VERTRES) ;

     if (StartDoc (hdcPrn, &di) > 0)
     {
          if (StartPage (hdcPrn) > 0)
          {
               PageGDICalls (hdcPrn, xPage, yPage) ;

               if (EndPage (hdcPrn) > 0)
                    EndDoc (hdcPrn) ;
               else
                    bSuccess = FALSE ;
          }
     }
     else
          bSuccess = FALSE ;

     DeleteDC (hdcPrn) ;
     return bSuccess ;
}

放弃程序

对于大型文件,程序应该提供使用者在应用程序行印期间取消打印任务的便利性。也许使用者只要打印文件中的一页,而不是打印全部的537页。应该要能在印完全部的537页之前纠正这个错误。
在一个程序内取消一个打印任务需要一种被称为「放弃程序」的技术。

/*-------------------------------------------
   PRINT2.C -- Printing with Abort Procedure
               (c) Charles Petzold, 1998
  -------------------------------------------*/

#include <windows.h>

HDC  GetPrinterDC (void) ;              // in GETPRNDC.C
void PageGDICalls (HDC, int, int) ;     // in PRINT.C

HINSTANCE hInst ;
TCHAR     szAppName[] = TEXT ("Print2") ;
TCHAR     szCaption[] = TEXT ("Print Program 2 (Abort Procedure)") ;

BOOL CALLBACK AbortProc (HDC hdcPrn, int iCode)
{
     MSG msg ;

     while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
     {
          TranslateMessage (&msg) ;
          DispatchMessage (&msg) ;
     }
     return TRUE ;
}

BOOL PrintMyPage (HWND hwnd)
{
     static DOCINFO di = { sizeof (DOCINFO), TEXT ("Print2: Printing") } ;
     BOOL           bSuccess = TRUE ;
     HDC            hdcPrn ;
     short          xPage, yPage ;

     if (NULL == (hdcPrn = GetPrinterDC ()))
          return FALSE ;

     xPage = GetDeviceCaps (hdcPrn, HORZRES) ;
     yPage = GetDeviceCaps (hdcPrn, VERTRES) ;

     // 禁止窗口接收鼠标和键盘消息,避免重复打印
     EnableWindow (hwnd, FALSE) ;

     SetAbortProc (hdcPrn, AbortProc) ;

     if (StartDoc (hdcPrn, &di) > 0)
     {
          if (StartPage (hdcPrn) > 0)
          {
               PageGDICalls (hdcPrn, xPage, yPage) ;

               if (EndPage (hdcPrn) > 0)
                    EndDoc (hdcPrn) ;
               else
                    bSuccess = FALSE ;
          }
     }
     else
          bSuccess = FALSE ;

     // 启用窗口接收鼠标键盘消息
     EnableWindow (hwnd, TRUE) ;
     DeleteDC (hdcPrn) ;
     return bSuccess ;
}

增加打印对话框

打印对话框
AbortProc中的PeekMessage循环得被修改,以便将非系统模态对话框的消息发送给对话框窗口消息处理程序。PrintDlgProc必须处理WM_COMMAND消息,以检查「Cancel」按钮的状态。如果「Cancel」钮被按下,就将一个叫做bUserAbort的整体变量设为TRUE。AbortProc传回的值正好和bUserAbort相反。您可能还记得,如果AbortProc传回TRUE会继续打印,传回FALSE则放弃打印。

Print.rc

/
//
// Dialog
//

PRINTDLGBOX DIALOG DISCARDABLE  20, 20, 186, 63
STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
FONT 8, "MS Sans Serif"
BEGIN
    PUSHBUTTON      "Cancel",IDCANCEL,67,42,50,14
    CTEXT           "Cancel Printing",IDC_STATIC,7,21,172,8
END


/
//
// DESIGNINFO
//

#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO DISCARDABLE 
BEGIN
    "PRINTDLGBOX", DIALOG
    BEGIN
        LEFTMARGIN, 7
        RIGHTMARGIN, 179
        TOPMARGIN, 7
        BOTTOMMARGIN, 56
    END
END
#endif    // APSTUDIO_INVOKED

RESOURCE.H

#define IDC_STATIC                      -1

Print3.c

只有在AbortProc用PeekMessage找到消息,并用IsDialogMessage将它们传送给对话框窗口消息处理程序时,这个对话框才接收消息。只有在GDI模块处理EndPage函数时,才呼叫AbortProc。如果GDI发现AbortProc的传回值是FALSE, 它将控制权从EndPage传回到PrintMyPage。它不传回错误码。至此,PrintMyPage认为打印页已经发完了,并呼叫EndDoc函数。但是,由于GDI模块还没有完成对EndPage呼叫的处理,所以不会打印出什么东西来。

/*---------------------------------------
   PRINT3.C -- Printing with Dialog Box
                (c) Charles Petzold, 1998
  ---------------------------------------*/

#include <windows.h>

HDC  GetPrinterDC (void) ;              // in GETPRNDC.C
void PageGDICalls (HDC, int, int) ;     // in PRINT.C

HINSTANCE hInst ;
TCHAR     szAppName[] = TEXT ("Print3") ;
TCHAR     szCaption[] = TEXT ("Print Program 3 (Dialog Box)") ;

BOOL bUserAbort ;
HWND hDlgPrint ;

// 打印对话框处理程序
BOOL CALLBACK PrintDlgProc (HWND hDlg, UINT message, 
                            WPARAM wParam, LPARAM lParam)
{
     switch (message)
     {
     case WM_INITDIALOG:
         // 设置窗口标题
          SetWindowText (hDlg, szAppName) ;
          // 停用系统菜单的关闭选项
          EnableMenuItem (GetSystemMenu (hDlg, FALSE), SC_CLOSE, MF_GRAYED) ;
          return TRUE ;

     case WM_COMMAND:  // 按下取消按钮之后
         // 全局变量,TRUE标识取消按钮按下
          bUserAbort = TRUE ;
          EnableWindow (GetParent (hDlg), TRUE) ;  // 启动主窗口
          DestroyWindow (hDlg) ;  // 关闭对话框
          hDlgPrint = NULL ;  // 设定为NULL,防止在消息循环中呼叫IsDialogMessage
          return TRUE ;
     }
     return FALSE ;
}


// 放弃处理程序,用来停止打印
BOOL CALLBACK AbortProc (HDC hdcPrn, int iCode)
{
     MSG msg ;

     while (!bUserAbort && PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
     {
         // IsDialogMessage函数用来将消息发送给非系统模态对话框
          if (!hDlgPrint || !IsDialogMessage (hDlgPrint, &msg))
          {
               TranslateMessage (&msg) ;
               DispatchMessage (&msg) ;
          }
     }
     // 返回TRUE标识继续打印
     return !bUserAbort ;
}

BOOL PrintMyPage (HWND hwnd)
{
     static DOCINFO di = { sizeof (DOCINFO), TEXT ("Print3: Printing") } ;
     BOOL           bSuccess = TRUE ;
     HDC            hdcPrn ;
     int            xPage, yPage ;

     if (NULL == (hdcPrn = GetPrinterDC ()))
          return FALSE ;

     xPage = GetDeviceCaps (hdcPrn, HORZRES) ;
     yPage = GetDeviceCaps (hdcPrn, VERTRES) ;

     EnableWindow (hwnd, FALSE) ;

     // 先设置用户取消状态为False
     bUserAbort = FALSE ;
     // 设置弹窗回调函数
     hDlgPrint = CreateDialog (hInst, TEXT ("PrintDlgBox"), 
                               hwnd, PrintDlgProc) ;
     // 设置放弃处理程序回调函数
     SetAbortProc (hdcPrn, AbortProc) ;

     if (StartDoc (hdcPrn, &di) > 0)
     {
          if (StartPage (hdcPrn) > 0)
          {
               PageGDICalls (hdcPrn, xPage, yPage) ;

               if (EndPage (hdcPrn) > 0)
                    EndDoc (hdcPrn) ;
               else
                    bSuccess = FALSE ;
          }
     }
     else
          bSuccess = FALSE ;

     if (!bUserAbort)
     {
         // 如果用户没有取消打印,就重新启用主窗口,并清除打印对话框
          EnableWindow (hwnd, TRUE) ;
          DestroyWindow (hDlgPrint) ;
     }

     DeleteDC (hdcPrn) ;

     // bUserAbort可以告诉您使用者是否终止了打印作业
     // bSuccess会告诉您是否出了故障
     return bSuccess && !bUserAbort ;
}

为POPPAD增加打印功能

POPPAD

需要用到对话框一节的代码。

/*----------------------------------------------
   POPPRNT.C -- Popup Editor Printing Functions
  ----------------------------------------------*/

#include <windows.h>
#include <commdlg.h>
#include "resource.h"

BOOL bUserAbort ;
HWND hDlgPrint ;

BOOL CALLBACK PrintDlgProc (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
     switch (msg)
     {
     case WM_INITDIALOG :
          EnableMenuItem (GetSystemMenu (hDlg, FALSE), SC_CLOSE, MF_GRAYED) ;
          return TRUE ;

     case WM_COMMAND :
          bUserAbort = TRUE ;
          EnableWindow (GetParent (hDlg), TRUE) ;
          DestroyWindow (hDlg) ;
          hDlgPrint = NULL ;
          return TRUE ;
     }
     return FALSE ;
}          

BOOL CALLBACK AbortProc (HDC hPrinterDC, int iCode)
{
     MSG msg ;

     while (!bUserAbort && PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
     {
          if (!hDlgPrint || !IsDialogMessage (hDlgPrint, &msg))
          {
               TranslateMessage (&msg) ;
               DispatchMessage (&msg) ;
          }
     }
     return !bUserAbort ;
}

BOOL PopPrntPrintFile (HINSTANCE hInst, HWND hwnd, HWND hwndEdit, 
                       PTSTR szTitleName)
{
     static DOCINFO  di = { sizeof (DOCINFO) } ;
     // 通用对话框结构
     static PRINTDLG pd ;
     BOOL            bSuccess ;
     int             yChar, iCharsPerLine, iLinesPerPage, iTotalLines,
                     iTotalPages, iPage, iLine, iLineNum ;
     PTSTR           pstrBuffer ;
     TCHAR           szJobName [64 + MAX_PATH] ;
     TEXTMETRIC      tm ;
     WORD            iColCopy, iNoiColCopy ;

          // Invoke Print common dialog box

     pd.lStructSize         = sizeof (PRINTDLG) ;
     pd.hwndOwner           = hwnd ;
     pd.hDevMode            = NULL ;
     pd.hDevNames           = NULL ;
     pd.hDC                 = NULL ;
     // PD_COLLATE允许多份打印
     pd.Flags               = PD_ALLPAGES | PD_COLLATE | 
                              PD_RETURNDC | PD_NOSELECTION ;
     pd.nFromPage           = 0 ;
     pd.nToPage             = 0 ;
     pd.nMinPage            = 0 ;
     pd.nMaxPage            = 0 ;
     pd.nCopies             = 1 ;
     pd.hInstance           = NULL ;
     pd.lCustData           = 0L ;
     pd.lpfnPrintHook       = NULL ;
     pd.lpfnSetupHook       = NULL ;
     pd.lpPrintTemplateName = NULL ;
     pd.lpSetupTemplateName = NULL ;
     pd.hPrintTemplate      = NULL ;
     pd.hSetupTemplate      = NULL ;

     // PrintDlg显示打印对话框
     if (!PrintDlg (&pd))
          return TRUE ;

     // 发送EM_GETLINECOUNT来确定总行数
     if (0 == (iTotalLines = SendMessage (hwndEdit, EM_GETLINECOUNT, 0, 0)))
          return TRUE ;

          // Calculate necessary metrics for file 

     GetTextMetrics (pd.hDC, &tm) ;
     yChar = tm.tmHeight + tm.tmExternalLeading ;

     iCharsPerLine = GetDeviceCaps (pd.hDC, HORZRES) / tm.tmAveCharWidth ;
     iLinesPerPage = GetDeviceCaps (pd.hDC, VERTRES) / yChar ;
     iTotalPages   = (iTotalLines + iLinesPerPage - 1) / iLinesPerPage ;

          // Allocate a buffer for each line of text

     pstrBuffer = malloc (sizeof (TCHAR) * (iCharsPerLine + 1)) ;

          // Display the printing dialog box

     EnableWindow (hwnd, FALSE) ;

     bSuccess   = TRUE ;
     bUserAbort = FALSE ;

     hDlgPrint = CreateDialog (hInst, TEXT ("PrintDlgBox"), 
                               hwnd, PrintDlgProc) ;

     SetDlgItemText (hDlgPrint, IDC_FILENAME, szTitleName) ;
     SetAbortProc (pd.hDC, AbortProc) ;

          // Start the document

     GetWindowText (hwnd, szJobName, sizeof (szJobName)) ;
     di.lpszDocName = szJobName ;

     if (StartDoc (pd.hDC, &di) > 0)
     {
               // Collation requires this loop and iNoiColCopy
         // 逐份打印
          for (iColCopy = 0 ;
               iColCopy < ((WORD) pd.Flags & PD_COLLATE ? pd.nCopies : 1) ;
               iColCopy++)
          {
               for (iPage = 0 ; iPage < iTotalPages ; iPage++)
               {
                    for (iNoiColCopy = 0 ;
                         iNoiColCopy < (pd.Flags & PD_COLLATE ? 1 : pd.nCopies);
                         iNoiColCopy++)
                    {
                              // Start the page

                         if (StartPage (pd.hDC) < 0)
                         {
                              bSuccess = FALSE ;
                              break ;
                         }

                              // For each page, print the lines

                         for (iLine = 0 ; iLine < iLinesPerPage ; iLine++)
                         {
                              iLineNum = iLinesPerPage * iPage + iLine ;

                              if (iLineNum > iTotalLines)
                                   break ;

                              *(int *) pstrBuffer = iCharsPerLine ;

                              TextOut (pd.hDC, 0, yChar * iLine, pstrBuffer,
                                       (int) SendMessage (hwndEdit, EM_GETLINE,
                                       (WPARAM) iLineNum, (LPARAM) pstrBuffer));
                         }

                         if (EndPage (pd.hDC) < 0)
                         {
                              bSuccess = FALSE ;
                              break ;
                         }

                         if (bUserAbort)
                              break ;
                    }

                    if (!bSuccess || bUserAbort)
                         break ;
               }

               if (!bSuccess || bUserAbort)
                    break ;
          }
     }
     else
          bSuccess = FALSE ;

     if (bSuccess)
          EndDoc (pd.hDC) ;

     if (!bUserAbort)
     {
          EnableWindow (hwnd, TRUE) ;
          DestroyWindow (hDlgPrint) ;
     }

     free (pstrBuffer) ;
     DeleteDC (pd.hDC) ;

     return bSuccess && !bUserAbort ;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小龙在山东

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值