PRINTER.C
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:34k
源码类别:

Windows编程

开发平台:

Visual C++

  1. /******************************************************************************
  2. *       This is a part of the Microsoft Source Code Samples. 
  3. *       Copyright (C) 1993-1997 Microsoft Corporation.
  4. *       All rights reserved. 
  5. *       This source code is only intended as a supplement to 
  6. *       Microsoft Development Tools and/or WinHelp documentation.
  7. *       See these sources for detailed information regarding the 
  8. *       Microsoft samples programs.
  9. ******************************************************************************/
  10. /******************************************************************************
  11. *
  12. *  PROGRAM:     PRINTER.C
  13. *
  14. *  PURPOSE:     This is a sample application demostrating some of the new
  15. *               printing functionality in Windows NT. This app allows the
  16. *               user to select between various GDI graphics primitives,
  17. *               to choose pen & brush colors, styles, and sizes, and to
  18. *               the print these graphics to a printer. Also, the app
  19. *               provides the user the ability to query information (reso-
  20. *               lution, etc.) about the various printers & drivers by
  21. *               making calls to GetDeviceCaps, etc.
  22. *
  23. *               Functionality for PRINTER is split into six different
  24. *               modules as follows:
  25. *
  26. *                 printer.c - main event loop
  27. *                             main window procedure
  28. *                             about & abort dialog procedures
  29. *                             printing thread
  30. *
  31. *                 paint.c   - handles all painting printers & most painting
  32. *                             to window
  33. *
  34. *                 enumprt.c - manages the display of information returned
  35. *                             from calling EnumPrinters, EnumPrinterDrivers
  36. *
  37. *                 devcapsx.c- manages the display of information returned
  38. *                             from calling DeviceCapabilitiesEx
  39. *
  40. *                 getpdriv.c- manages the display of information returned
  41. *                             from calling GetPrinterDriver
  42. *
  43. *                 getcaps.c - manages the display of information returned
  44. *                             from calling GetDeviceCaps
  45. *
  46. *  FUNCTIONS:   WinMain               - initialization, create window, msg loop
  47. *               MainWndProc           - processes main window msgs
  48. *               AboutDlgProc          - processes About dlg msgs
  49. *               InvalidateClient      - invalidates graphics part of client wnd
  50. *               RefreshPrinterCombobox- updates list of printers
  51. *               PrintThread           - printing done here
  52. *               AbortProc             - msg loop for abort
  53. *               AbortDlgProc          - processes abort dialog messages
  54. *
  55. ******************************************************************************/
  56. #include <windows.h>
  57. #include <stdio.h>
  58. #include <string.h>
  59. #include <stdlib.h> // for _mbstrlen
  60. #include <winspool.h>
  61. #include <commdlg.h>
  62. #include "common.h"
  63. #include "printer.h"
  64. // for internationalization
  65. #define My_mbslen _mbstrlen
  66. /******************************************************************************
  67. *
  68. *  FUNCTION:    WinMain (standard WinMain INPUTS/RETURNS)
  69. *
  70. *  COMMENTS:    Register & create main window, loop for messages
  71. *
  72. ******************************************************************************/
  73. int WINAPI WinMain (HANDLE ghInstance, HANDLE hPrevInstance, LPSTR lpCmdLine,
  74.                     int    nCmdShow)
  75. {
  76.   MSG msg;
  77.   ghInst = ghInstance;
  78.   if (!hPrevInstance)
  79.   {
  80.     WNDCLASS wc;
  81.     wc.style         = MAIN_CLASS_STYLE;
  82.     wc.lpfnWndProc   = (WNDPROC) MainWndProc;
  83.     wc.cbClsExtra    = 0;
  84.     wc.cbWndExtra    = 0;
  85.     wc.hInstance     = ghInst;
  86.     wc.hIcon         = LoadIcon (ghInst, MAKEINTRESOURCE(MAIN_ICON));
  87.     wc.hCursor       = LoadCursor (NULL, IDC_ARROW);
  88.     wc.hbrBackground = NULL;
  89.     wc.lpszMenuName  = (LPCSTR) MAIN_MENU_NAME;
  90.     wc.lpszClassName = (LPCSTR) MAIN_CLASS_NAME;
  91.     if (!RegisterClass (&wc))
  92.     {
  93.       MessageBox (NULL, "WinMain(): RegisterClass() failed",
  94.                   GetStringRes2(ERR_MOD_NAME), MB_OK | MB_ICONHAND);
  95.       return FALSE;
  96.     }
  97.   }
  98.   if (!(ghwndMain = CreateWindow ((LPCSTR) MAIN_CLASS_NAME,
  99.                                   (LPCSTR) GetStringRes(MAIN_WND_TITLE),
  100.                                   MAIN_WND_STYLE,
  101.                                   CW_USEDEFAULT, CW_USEDEFAULT,
  102.                                   CW_USEDEFAULT, CW_USEDEFAULT,
  103.                                   NULL, NULL, ghInst, NULL)))
  104.     return FALSE;
  105.   ShowWindow (ghwndMain, nCmdShow);
  106.   while (GetMessage (&msg, NULL, 0, 0))
  107.   {
  108.     TranslateMessage (&msg);
  109.     DispatchMessage  (&msg);
  110.   }
  111.   return msg.wParam;
  112. }
  113. /******************************************************************************
  114. *
  115. *  FUNCTION:    MainWndProc (standard window procedure INPUTS/RETURNS)
  116. *
  117. *  COMMENTS:    Handles main app window msg processing
  118. *
  119. ******************************************************************************/
  120. LRESULT CALLBACK MainWndProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
  121. {
  122.   static HMENU hMappingModesSubMenu;
  123.   static HMENU hGraphicsSubMenu;
  124.   static HMENU hPenWidthSubMenu;
  125.   static HMENU hPenStyleSubMenu;
  126.   static HMENU hBrushStyleSubMenu;
  127.   static HWND  hwndCombobox;
  128.   static int   iComboboxWidth;
  129.   static LONG  lTextHeight;
  130.   int i;
  131.   switch (msg)
  132.   {
  133.     case WM_COMMAND:
  134.       switch (LOWORD (wParam))
  135.       {
  136.         case IDM_PRINT:
  137.         case IDM_PRINTDLG:
  138.         {
  139.           DWORD  threadId;
  140.           if (!CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE) PrintThread,
  141.                              (LPVOID) wParam, 0, &threadId))
  142.             MessageBox (hwnd,
  143.                         "MainWndProc(): Error creating print thread",
  144.                         GetStringRes2(ERR_MOD_NAME), MB_OK | MB_ICONHAND);
  145.           break;
  146.         }
  147.         case IDM_GETDEVICECAPS:
  148.           DialogBox (ghInst, (LPCTSTR) "List", hwnd,
  149.                      (DLGPROC) GetDeviceCapsDlgProc);
  150.           break;
  151.         case IDM_ENUMPRINTERS:
  152.           DialogBox (ghInst, (LPCTSTR) "List", hwnd,
  153.                      (DLGPROC) EnumPrintersDlgProc);
  154.           break;
  155.         case IDM_GETPRINTERDRIVER:
  156.           if (strcmp (gszDeviceName, "Display"))
  157.             DialogBox (ghInst, (LPCTSTR) "List", hwnd,
  158.                        (DLGPROC) GetPrinterDriverDlgProc);
  159.           else
  160.             MessageBox (hwnd, (LPCTSTR) GetStringRes(IDS_ASKSELPRT),
  161.                         (LPCTSTR) "PRINTER.EXE:", MB_OK);
  162.           break;
  163.         case IDM_ENUMPRINTERDRIVERS:
  164.           DialogBox (ghInst, (LPCTSTR) "List", hwnd,
  165.                      (DLGPROC) EnumPrinterDriversDlgProc);
  166.           break;
  167.         case IDM_REFRESH:
  168.           RefreshPrinterCombobox (hwndCombobox);
  169.           break;
  170.         case IDM_ABOUT:
  171.           DialogBox (ghInst, (LPCTSTR) "About", hwnd, (DLGPROC) AboutDlgProc);
  172.           break;
  173.         case IDM_HIENGLISH:
  174.         case IDM_HIMETRIC:
  175.         case IDM_LOENGLISH:
  176.         case IDM_LOMETRIC:
  177.         case IDM_TWIPS:
  178.         case IDM_ISOTROPIC:
  179.         case IDM_ANISOTROPIC:
  180.         case IDM_TEXT:
  181.           //
  182.           // Uncheck the last map mode menuitem, check the new map mode
  183.           //   menuitem, set iMappingMode according to menu id, cause a
  184.           //   repaint
  185.           //
  186.           for (i = 0; i < MAX_MAP_MODES; i++)
  187.             if (giMapMode == gaMMLookup[i].iMapMode)
  188.             {
  189.               CheckMenuItem (hMappingModesSubMenu, gaMMLookup[i].wMenuItem,
  190.                              MF_UNCHECKED | MF_BYCOMMAND);
  191.               break;
  192.             }
  193.           CheckMenuItem (hMappingModesSubMenu, LOWORD (wParam),
  194.                          MF_CHECKED | MF_BYCOMMAND);
  195.           for (i = 0; i < MAX_MAP_MODES; i++)
  196.             if (LOWORD (wParam) == gaMMLookup[i].wMenuItem)
  197.             {
  198.               giMapMode = gaMMLookup[i].iMapMode;
  199.               break;
  200.             }
  201.           //
  202.           // invalidate the entire client so toolbar text gets updated
  203.           //
  204.           InvalidateRect (hwnd, NULL, TRUE);
  205.           break;
  206.         case IDM_ARC:
  207.         case IDM_ELLIPSE:
  208.         case IDM_LINETO:
  209.         case IDM_PIE:
  210.         case IDM_PLGBLT:
  211.         case IDM_POLYBEZIER:
  212.         case IDM_POLYGON:
  213.         case IDM_POLYLINE:
  214.         case IDM_POLYPOLYGON:
  215.         case IDM_RECTANGLE:
  216.         case IDM_ROUNDRECT:
  217.         case IDM_STRETCHBLT:
  218.         {
  219.           //
  220.           // Retrieve the DWORD flag value for the particular menuitem,
  221.           //   toggle (un/check) the menuitem, set/clear the flag in
  222.           //   gdwGraphicsOptions, cause a repaint
  223.           //
  224.           DWORD dwGraphic;
  225.           for (i = 0; i < MAX_GRAPHICS; i++)
  226.             if (LOWORD (wParam) == gaGraphicLookup[i].wMenuItem)
  227.             {
  228.               dwGraphic = gaGraphicLookup[i].dwGraphic;
  229.               break;
  230.             }
  231.           if (GetMenuState (hGraphicsSubMenu, LOWORD(wParam), MF_BYCOMMAND)
  232.               & MF_CHECKED)
  233.           {
  234.             gdwGraphicsOptions &= ~dwGraphic;
  235.             CheckMenuItem (hGraphicsSubMenu, LOWORD(wParam),
  236.                             MF_UNCHECKED | MF_BYCOMMAND);
  237.           }
  238.           else
  239.           {
  240.             //
  241.             // Clear/uncheck the ENUMFONTS flag/menuitem
  242.             //
  243.             gdwGraphicsOptions &= ~ENUMFONTS;
  244.             CheckMenuItem (hGraphicsSubMenu, IDM_ENUMFONTS,
  245.                            MF_UNCHECKED | MF_BYCOMMAND);
  246.             gdwGraphicsOptions |= dwGraphic;
  247.             CheckMenuItem (hGraphicsSubMenu, LOWORD(wParam),
  248.                             MF_CHECKED | MF_BYCOMMAND);
  249.           }
  250.           InvalidateClient ();
  251.           break;
  252.         }
  253.         case IDM_ALLGRAPHICS:
  254.           //
  255.           // Clear/uncheck the ENUMFONTS flag/menuitem, set/check all
  256.           //   other graphics flags/menuitems, cause a repaint
  257.           //
  258.           CheckMenuItem (hGraphicsSubMenu, IDM_ENUMFONTS,
  259.                           MF_UNCHECKED | MF_BYCOMMAND);
  260.           for (i = 0; i < MAX_GRAPHICS; i++)
  261.             CheckMenuItem (hGraphicsSubMenu, IDM_ARC + i,
  262.                            MF_CHECKED | MF_BYCOMMAND);
  263.           gdwGraphicsOptions = ALLGRAPHICS | (gdwGraphicsOptions & DRAWAXIS);
  264.           InvalidateClient ();
  265.           break;
  266.         case IDM_NOGRAPHICS:
  267.           //
  268.           // Clear/uncheck all graphics flags/menuitems, cause a repaint
  269.           //
  270.           for (i = 0; i < MAX_GRAPHICS; i++)
  271.             CheckMenuItem (hGraphicsSubMenu, IDM_ARC + i,
  272.                            MF_UNCHECKED | MF_BYCOMMAND);
  273.           gdwGraphicsOptions &= (DRAWAXIS | ENUMFONTS);
  274.           InvalidateClient ();
  275.           break;
  276.         case IDM_ENUMFONTS:
  277.           //
  278.           // Set/clear ENUMFONTS flag, toggle (un/check) menuitem, if
  279.           //   checking IDM_ENUMFONTS then uncheck all other items,
  280.           //   cause a repaint
  281.           //
  282.           if (GetMenuState (hGraphicsSubMenu, IDM_ENUMFONTS, MF_BYCOMMAND)
  283.                 & MF_CHECKED)
  284.           {
  285.             gdwGraphicsOptions &= DRAWAXIS;
  286.             CheckMenuItem (hGraphicsSubMenu, IDM_ENUMFONTS,
  287.                            MF_UNCHECKED | MF_BYCOMMAND);
  288.           }
  289.           else
  290.           {
  291.             SendMessage (hwnd, WM_COMMAND, IDM_NOGRAPHICS, 0);
  292.             gdwGraphicsOptions = ENUMFONTS | (gdwGraphicsOptions & DRAWAXIS);
  293.             CheckMenuItem (hGraphicsSubMenu, IDM_ENUMFONTS,
  294.                            MF_CHECKED | MF_BYCOMMAND);
  295.           }
  296.           InvalidateClient ();
  297.           break;
  298.         case IDM_DRAWAXIS:
  299.           //
  300.           // Set/clear DRAWAXIS flag, toggle (un/check) menuitem,
  301.           //   cause a repaint
  302.           //
  303.           if (GetMenuState (hGraphicsSubMenu, IDM_DRAWAXIS, MF_BYCOMMAND)
  304.                 & MF_CHECKED)
  305.           {
  306.             gdwGraphicsOptions &= ~DRAWAXIS;
  307.             CheckMenuItem (hGraphicsSubMenu, IDM_DRAWAXIS,
  308.                            MF_UNCHECKED | MF_BYCOMMAND);
  309.           }
  310.           else
  311.           {
  312.             gdwGraphicsOptions |= DRAWAXIS;
  313.             CheckMenuItem (hGraphicsSubMenu, IDM_DRAWAXIS,
  314.                            MF_CHECKED | MF_BYCOMMAND);
  315.           }
  316.           InvalidateClient ();
  317.           break;
  318.         case IDM_SETPENCOLOR:
  319.         case IDM_SETBRUSHCOLOR:
  320.         case IDM_TEXTCOLOR:
  321.         {
  322.           CHOOSECOLOR cc;
  323.           static DWORD adwCustColors[16];
  324.           memset ((void *) &cc, 0, sizeof (CHOOSECOLOR));
  325.           cc.lStructSize  = sizeof (CHOOSECOLOR);
  326.           cc.hwndOwner    = hwnd;
  327.           cc.Flags        = CC_RGBINIT;
  328.           cc.lpCustColors = adwCustColors;
  329.           if (LOWORD (wParam) == IDM_SETPENCOLOR)
  330.             cc.rgbResult = gdwPenColor;
  331.           else if (LOWORD (wParam) == IDM_SETBRUSHCOLOR)
  332.             cc.rgbResult = gdwBrushColor;
  333.           else
  334.             cc.rgbResult = gdwTextColor;
  335.           //
  336.           // bring up choose color common dialog
  337.           //
  338.           ChooseColor (&cc);
  339.           if (LOWORD (wParam) == IDM_SETPENCOLOR)
  340.             gdwPenColor   = cc.rgbResult;
  341.           else if (LOWORD (wParam) == IDM_SETBRUSHCOLOR)
  342.             gdwBrushColor = cc.rgbResult;
  343.           else
  344.             gdwTextColor  = cc.rgbResult;
  345.           InvalidateClient ();
  346.           break;
  347.         }
  348.         case IDM_PENWIDTH_1:
  349.         case IDM_PENWIDTH_2:
  350.         case IDM_PENWIDTH_3:
  351.         case IDM_PENWIDTH_4:
  352.         case IDM_PENWIDTH_5:
  353.         case IDM_PENWIDTH_6:
  354.         case IDM_PENWIDTH_7:
  355.         case IDM_PENWIDTH_8:
  356.           //
  357.           // uncheck old pen width menuitem, check new one, cause a repaint
  358.           //
  359.           for (i = 0; i < MAX_PENWIDTHS; i++)
  360.             if (giPenWidth == gaPenWidths[i].iPenWidth)
  361.             {
  362.               CheckMenuItem (hPenWidthSubMenu, gaPenWidths[i].wMenuItem,
  363.                              MF_UNCHECKED | MF_BYCOMMAND);
  364.               break;
  365.             }
  366.           for (i = 0; i < MAX_PENWIDTHS; i++)
  367.             if (LOWORD(wParam) == gaPenWidths[i].wMenuItem)
  368.             {
  369.               CheckMenuItem (hPenWidthSubMenu, gaPenWidths[i].wMenuItem,
  370.                              MF_CHECKED | MF_BYCOMMAND);
  371.               giPenWidth = gaPenWidths[i].iPenWidth;
  372.               break;
  373.             }
  374.           InvalidateClient ();
  375.           break;
  376.         case IDM_PENCOLOR_SOLID:
  377.         case IDM_PENCOLOR_DASH:
  378.         case IDM_PENCOLOR_DOT:
  379.         case IDM_PENCOLOR_DASHDOT:
  380.         case IDM_PENCOLOR_DASHDOTDOT:
  381.         case IDM_PENCOLOR_NULL:
  382.         case IDM_PENCOLOR_INSIDEFRAME:
  383.           //
  384.           // uncheck old pen style menuitem, check new one, cause a repaint
  385.           //
  386.           for (i = 0; i < MAX_PENSTYLES; i++)
  387.             if (giPenStyle == gaPenStyles[i].iPenStyle)
  388.             {
  389.               CheckMenuItem (hPenStyleSubMenu, gaPenStyles[i].wMenuItem,
  390.                              MF_UNCHECKED | MF_BYCOMMAND);
  391.               break;
  392.             }
  393.           for (i = 0; i < MAX_PENSTYLES; i++)
  394.             if (LOWORD(wParam) == gaPenStyles[i].wMenuItem)
  395.             {
  396.               CheckMenuItem (hPenStyleSubMenu, gaPenStyles[i].wMenuItem,
  397.                              MF_CHECKED | MF_BYCOMMAND);
  398.               giPenStyle = gaPenStyles[i].iPenStyle;
  399.               break;
  400.             }
  401.           InvalidateClient ();
  402.           break;
  403.         case IDM_BRUSHSTYLE_HORIZONTAL:
  404.         case IDM_BRUSHSTYLE_VERTICAL:
  405.         case IDM_BRUSHSTYLE_FDIAGONAL:
  406.         case IDM_BRUSHSTYLE_BDIAGONAL:
  407.         case IDM_BRUSHSTYLE_CROSS:
  408.         case IDM_BRUSHSTYLE_DIAGCROSS:
  409.         case IDM_BRUSHSTYLE_SOLIDCLR:
  410.         case IDM_BRUSHSTYLE_DITHEREDCLR:
  411.         case IDM_BRUSHSTYLE_SOLIDTEXTCLR:
  412.         case IDM_BRUSHSTYLE_DITHEREDTEXTCLR:
  413.         case IDM_BRUSHSTYLE_SOLIDBKCLR:
  414.         case IDM_BRUSHSTYLE_DITHEREDBKCLR:
  415.           //
  416.           // uncheck old brush style menuitem, check new one, cause a repaint
  417.           //
  418.           for (i = 0; i < MAX_BRUSHSTYLES; i++)
  419.             if (giBrushStyle == gaBrushStyles[i].iBrushStyle)
  420.             {
  421.               CheckMenuItem (hBrushStyleSubMenu, gaBrushStyles[i].wMenuItem,
  422.                              MF_UNCHECKED | MF_BYCOMMAND);
  423.               break;
  424.             }
  425.           for (i = 0; i < MAX_BRUSHSTYLES; i++)
  426.             if (LOWORD(wParam) == gaBrushStyles[i].wMenuItem)
  427.             {
  428.               CheckMenuItem (hBrushStyleSubMenu, gaBrushStyles[i].wMenuItem,
  429.                              MF_CHECKED | MF_BYCOMMAND);
  430.               giBrushStyle = gaBrushStyles[i].iBrushStyle;
  431.               break;
  432.             }
  433.           InvalidateClient ();
  434.           break;
  435.         case ID_COMBOBOX:
  436.           switch (HIWORD(wParam))
  437.           {
  438.             case CBN_SELCHANGE:
  439.             {
  440.               DWORD dwIndex;
  441.               char  buf[BUFSIZE];
  442.               //
  443.               // User clicked on one of the items in the toolbar combobox;
  444.               //   figure out which item, then parse the text apart and
  445.               //   copy it to the gszDriverName, gszDeviceName, and gszPort
  446.               //   variables.
  447.               //
  448.               dwIndex = (DWORD) SendMessage ((HWND) lParam,
  449.                                              CB_GETCURSEL, 0, 0);
  450.               SendMessage ((HWND) lParam, CB_GETLBTEXT, dwIndex,
  451.                            (LONG) buf);
  452.               if (!strcmp (buf, "Display"))
  453.               {
  454.                 strcpy (gszDeviceName, "Display");
  455.                 gszPort[0]       =
  456.                 gszDriverName[0] = '';
  457.               }
  458.               else
  459.               {
  460.                 LPSTR   lpszSrc;
  461.                 LPSTR   lpszDst;
  462.                 for (lpszSrc = buf, lpszDst = gszDeviceName;
  463.                     *lpszSrc && *lpszSrc != ';';    ) {
  464.                     if (IsDBCSLeadByte(*lpszSrc)) {
  465.                         *lpszDst++ = *lpszSrc++;
  466.                     }
  467.                     *lpszDst++ = *lpszSrc++;
  468.                 }
  469.                 *lpszDst = '';
  470.                 for (lpszSrc++, lpszDst = gszPort;
  471.                     *lpszSrc && *lpszSrc != ';';    ) {
  472.                     if (IsDBCSLeadByte(*lpszSrc)) {
  473.                         *lpszDst++ = *lpszSrc++;
  474.                     }
  475.                     *lpszDst++ = *lpszSrc++;
  476.                 }
  477.                 *lpszDst = '';
  478.                 for (lpszSrc++, lpszDst = gszDriverName; *lpszSrc;    ) {
  479.                     if (IsDBCSLeadByte(*lpszSrc)) {
  480.                         *lpszDst++ = *lpszSrc++;
  481.                     }
  482.                     *lpszDst++ = *lpszSrc++;
  483.                 }
  484.                 *lpszDst = '';
  485.               }
  486.               break;
  487.             }
  488.           }
  489.           break;
  490.       }
  491.       break;
  492.     case WM_PAINT:
  493.     {
  494.       PAINTSTRUCT ps;
  495.       RECT        rect;
  496.       HRGN        hrgn;
  497.       HPEN        hpen, hpenSave;
  498.       HBRUSH      hbr;
  499.       char        buf[BUFSIZE];
  500.       POINT       p;
  501.       BeginPaint (hwnd, &ps);
  502.       //
  503.       // paint 3d toolbar background & client size text
  504.       //
  505.       GetClientRect (hwnd, &rect);
  506.       rect.bottom = 2*glcyMenu;
  507.       FillRect (ps.hdc, &rect, GetStockObject (LTGRAY_BRUSH));
  508.       SelectObject (ps.hdc, GetStockObject (WHITE_PEN));
  509.       MoveToEx (ps.hdc, 0, 2*glcyMenu - 2, NULL);
  510.       LineTo   (ps.hdc, 0, 0);
  511.       LineTo   (ps.hdc, (int) rect.right, 0);
  512.       hpen = CreatePen (PS_SOLID, 1, 0x808080);
  513.       hpenSave = SelectObject (ps.hdc, hpen);
  514.       MoveToEx (ps.hdc, 0, (int) 2*glcyMenu-1, NULL);
  515.       LineTo   (ps.hdc, (int) rect.right - 1, (int) 2*glcyMenu-1);
  516.       LineTo   (ps.hdc, (int) rect.right - 1, 1);
  517.       SelectObject (ps.hdc, hpenSave);
  518.       DeleteObject (hpen);
  519.       GetClientRect (hwnd, &rect);
  520.       //
  521.       // positioning of the string based upon x,y,cx,cy of combobox
  522.       //
  523.       SetBkMode (ps.hdc, TRANSPARENT);
  524.       p.x = rect.right;
  525.       p.y = (rect.bottom - 2*glcyMenu < 0 ? 0 : rect.bottom - 2*glcyMenu);
  526.       SetMapMode (ps.hdc, giMapMode);
  527.       DPtoLP (ps.hdc, &p, 1);
  528.       if (giMapMode != MM_TEXT && giMapMode != MM_ANISOTROPIC)
  529.         //
  530.         // p.y will come out negative because we started with origin in
  531.         //   upper left corner
  532.         //
  533.         p.y = -p.y;
  534.       SetMapMode (ps.hdc, MM_TEXT);
  535.       sprintf (buf, "cxClient = %ld (%ld)", rect.right, p.x);
  536.       TextOut (ps.hdc, iComboboxWidth + (int) 3*glcyMenu/2, (int) glcyMenu/8,
  537.                buf, strlen (buf));
  538.       sprintf (buf, "cyClient = %ld (%ld)",
  539.                rect.bottom - 2*glcyMenu < 0 ? 0 : rect.bottom - 2*glcyMenu,
  540.                p.y);
  541.       TextOut (ps.hdc, iComboboxWidth + (int) 3*glcyMenu/2,
  542.                (int) (glcyMenu/8 + lTextHeight),
  543.                buf, strlen (buf));
  544.       //
  545.       // paint graphics background white
  546.       //
  547.       rect.top    += 2*glcyMenu;
  548.       FillRect (ps.hdc, &rect, GetStockObject (WHITE_BRUSH));
  549.       if (rect.bottom <= 4*glcyMenu)
  550.         //
  551.         // we don't want to overpaint the toolbar, so just skip Paint() call
  552.         //
  553.         goto done_painting;
  554.       //
  555.       // set up a clip region so we don't draw all over our toolbar
  556.       //
  557.       GetClientRect (hwnd, &rect);
  558.       rect.top += 2*glcyMenu;
  559.       hrgn = CreateRectRgnIndirect (&rect);
  560.       SelectClipRgn (ps.hdc, hrgn);
  561.       DeleteObject (hrgn);
  562.       //
  563.       // set up view port, pens/brushes, & map mode, then paint
  564.       //
  565.       rect.top -= 2*glcyMenu;
  566.       if (giMapMode == MM_TEXT || giMapMode == MM_ANISOTROPIC)
  567.         SetViewportOrgEx (ps.hdc, glcyMenu, 3*glcyMenu, NULL);
  568.       else
  569.         SetViewportOrgEx (ps.hdc, glcyMenu, rect.bottom - glcyMenu, NULL);
  570.       rect.bottom -= 4*glcyMenu;
  571.       rect.right  -= 2*glcyMenu;
  572.       hpen = CreatePen (giPenStyle, giPenWidth, gdwPenColor);
  573.       SelectObject (ps.hdc, hpen);
  574.       hbr  = CreateHatchBrush (giBrushStyle, gdwBrushColor);
  575.       SelectObject (ps.hdc, hbr);
  576.       SetTextColor (ps.hdc, gdwTextColor);
  577.       SetMapMode (ps.hdc, giMapMode);
  578.       Paint      (ps.hdc, &rect);
  579.       DeleteObject (hpen);
  580.       DeleteObject (hbr);
  581. done_painting:
  582.       EndPaint (hwnd, &ps);
  583.       break;
  584.     }
  585.     case WM_CREATE:
  586.     {
  587.       HDC         hdc;
  588.       TEXTMETRIC  tm;
  589.       SIZE        size;
  590.       HMENU       hmenu, hPenSubMenu, hBrushSubMenu;
  591.       //
  592.       // initialize the globals
  593.       //
  594.       glcyMenu = (LONG) GetSystemMetrics (SM_CYMENU);
  595.       hmenu                = GetMenu (hwnd);
  596.       hMappingModesSubMenu = GetSubMenu (hmenu, 1);
  597.       hGraphicsSubMenu     = GetSubMenu (hmenu, 2);
  598.       hPenSubMenu          = GetSubMenu (hmenu, 3);
  599.       hPenWidthSubMenu     = GetSubMenu (hPenSubMenu, 1);
  600.       hPenStyleSubMenu     = GetSubMenu (hPenSubMenu, 2);
  601.       hBrushSubMenu        = GetSubMenu (hmenu, 4);
  602.       hBrushStyleSubMenu   = GetSubMenu (hBrushSubMenu, 1);
  603.       GetTextMetrics ((hdc = GetDC (hwnd)), &tm);
  604.       lTextHeight = tm.tmHeight;
  605.       //
  606.       // create combobox to display current printers in. the width
  607.       //   is caluculated by getting the text extent of a typical
  608.       //   entry in the listbox.
  609.       //
  610.       #define ASTRING "long  printer  name;long  port  name;long  driver  name"
  611.       GetTextExtentPoint (hdc, ASTRING, sizeof (ASTRING), &size);
  612.       iComboboxWidth = (int) size.cx;
  613.       ReleaseDC (hwnd, hdc);
  614.       hwndCombobox = CreateWindow ((LPCSTR) "COMBOBOX", (LPCSTR) "",
  615.                                    WS_CHILD | WS_VISIBLE | CBS_DROPDOWN,
  616.                                    (int) glcyMenu/2,
  617.                                    (int) glcyMenu/2 - 2,  // - 2 = fudge factor
  618.                                    iComboboxWidth,
  619.                                    (int) 6*glcyMenu,
  620.                                    hwnd, NULL, ghInst, NULL);
  621.       SetWindowLong (hwndCombobox, GWL_ID, ID_COMBOBOX);
  622.       PostMessage (hwnd, WM_COMMAND,
  623.                    (WPARAM) MAKELONG (IDM_REFRESH, 0),
  624.                    (LPARAM) 0);
  625.       PostMessage (hwnd, WM_COMMAND,
  626.                    (WPARAM) MAKELONG (IDM_POLYPOLYGON, 0),
  627.                    (LPARAM) 0);
  628.       break;
  629.     }
  630.     case WM_DESTROY:
  631.       PostQuitMessage (0);
  632.       break;
  633.     default:
  634.       return (DefWindowProc (hwnd, msg, wParam, lParam));
  635.   }
  636.   return 0;
  637. }
  638. /******************************************************************************
  639. *
  640. *  FUNCTION:    AboutDlgProc (standard dialog procedure INPUTS/RETURNS)
  641. *
  642. *  COMMENTS:    Handles "About" dialog messages
  643. *
  644. ******************************************************************************/
  645. LRESULT CALLBACK AboutDlgProc (HWND   hwnd, UINT msg, WPARAM wParam,
  646.                                LPARAM lParam)
  647. {
  648.   switch (msg)
  649.   {
  650.     case WM_INITDIALOG:
  651.       return TRUE;
  652.     case WM_COMMAND:
  653.       switch (LOWORD (wParam))
  654.       {
  655.         case IDOK:
  656.           EndDialog (hwnd, TRUE);
  657.           return 1;
  658.       }
  659.       break;
  660.   }
  661.   return 0;
  662. }
  663. /******************************************************************************
  664. *
  665. *  FUNCTION:    InvalidateClient
  666. *
  667. *  COMMENTS:    Eliminates the flashing of the toolbar when we redraw
  668. *
  669. ******************************************************************************/
  670. void InvalidateClient ()
  671. {
  672.   RECT rect;
  673.   GetClientRect (ghwndMain, &rect);
  674.   rect.top += 2*glcyMenu;
  675.   InvalidateRect (ghwndMain, &rect, TRUE);
  676. }
  677. /******************************************************************************
  678. *
  679. *  FUNCTION:    RefreshPrinterCombobox
  680. *
  681. *  INPUTS:      hwndCombobox- handle of the toolbar combobox
  682. *
  683. *  COMMENTS:    The idea here is to enumerate all printers & list them in
  684. *               then combobox in the form: "DEVICE_NAME;PORT;DRIVER_NAME".
  685. *               Then later, when a user selects one of these, we just
  686. *               query out the string & parse it apart, sticking the
  687. *               appropriate parts into the DriverName, DeviceName, and
  688. *               Port variables.
  689. *
  690. *               Also, the "Display" option is added to the combobox so
  691. *               that user can get DevCaps info about it.
  692. *
  693. ******************************************************************************/
  694. void RefreshPrinterCombobox (HWND hwndCombobox)
  695. {
  696.   DWORD            dwFlags = PRINTER_ENUM_FAVORITE | PRINTER_ENUM_LOCAL;
  697.   LPPRINTER_INFO_2 pPrinters;
  698.   DWORD            cbPrinters;
  699.   DWORD            cReturned, i;
  700.   char             buf[256];
  701.   SendMessage (hwndCombobox, CB_RESETCONTENT, 0, 0);
  702.   //
  703.   // add the "Display" option to the combobox
  704.   //
  705.   strcpy (buf, "Display");
  706.   SendMessage (hwndCombobox, CB_INSERTSTRING, (UINT)-1, (LONG) buf);
  707.   //
  708.   // get byte count needed for buffer, alloc buffer, the enum the printers
  709.   //
  710.   EnumPrinters (dwFlags, NULL, 2, NULL, 0, &cbPrinters,
  711.                 &cReturned);
  712.   if (!(pPrinters = (LPPRINTER_INFO_2) LocalAlloc (LPTR, cbPrinters + 4)))
  713.   {
  714.     MessageBox (ghwndMain, (LPCTSTR) GetStringRes(IDS_LALLOCFAIL),
  715.                 (LPCTSTR)GetStringRes2(ERR_MOD_NAME), MB_OK | MB_ICONEXCLAMATION);
  716.     goto done_refreshing;
  717.   }
  718.   if (!EnumPrinters (dwFlags, NULL, 2, (LPBYTE) pPrinters,
  719.                      cbPrinters, &cbPrinters, &cReturned))
  720.   {
  721.     MessageBox (ghwndMain, (LPCTSTR) GetStringRes(IDS_ENUMPRTFAIL),
  722.                 (LPCTSTR) GetStringRes2(ERR_MOD_NAME), MB_OK | MB_ICONEXCLAMATION);
  723.     goto done_refreshing;
  724.   }
  725.   if (cReturned > 0)
  726.     for (i = 0; i < cReturned; i++)
  727.     {
  728.       //
  729.       // for each printer in the PRINTER_INFO_2 array: build a string that
  730.       //   looks like "DEVICE_NAME;PORT;DRIVER_NAME"
  731.       //
  732.       strcpy (buf, (pPrinters + i)->pPrinterName);
  733.       strcat (buf, ";");
  734.       strcat (buf, (pPrinters + i)->pPortName);
  735.       strcat (buf, ";");
  736.       strcat (buf, (pPrinters + i)->pDriverName);
  737.       SendMessage (hwndCombobox, CB_INSERTSTRING, (UINT)-1, (LONG) buf);
  738.     }
  739.   else
  740.     MessageBox (ghwndMain, GetStringRes(IDS_NOPRTLST), "PRINTER.EXE", MB_OK);
  741. done_refreshing:
  742.   SendMessage (hwndCombobox, CB_SELECTSTRING, (UINT) -1, (LONG) buf);
  743.   PostMessage (ghwndMain, WM_COMMAND,
  744.                (WPARAM) MAKELONG (ID_COMBOBOX, CBN_SELCHANGE),
  745.                (LPARAM) hwndCombobox);
  746.   LocalFree (LocalHandle (pPrinters));
  747. }
  748. /******************************************************************************
  749. *
  750. *  FUNCTION:    PrintThread
  751. *
  752. *  INPUTS:      wParam - wParam of a WM_COMMAND message containing menuitem id
  753. *
  754. *  COMMENTS:    This is the code for the print thread created when the user
  755. *               selects the "Print" or "PrintDlg" menuitems. A thread is used
  756. *               here more demostration purposes only, since we really don't
  757. *               have any background processing to do. A real app would want
  758. *               to have alot more error checking here (e.g. check return of
  759. *               StartDoc, StartPage...).
  760. *
  761. ******************************************************************************/
  762. void PrintThread (LPVOID wParam)
  763. {
  764.   DOCINFO di;
  765.   RECT    rect;
  766.   HPEN    hpen;
  767.   HBRUSH  hbr;
  768.   switch (LOWORD((WPARAM) wParam))
  769.   {
  770.     case IDM_PRINT:
  771.     {
  772.       if (!strcmp (gszDeviceName, "Display"))
  773.       {
  774.         MessageBox (ghwndMain, GetStringRes(IDS_ASKSELPRT),
  775.                     "PRINTER.EXE:", MB_OK);
  776.         return;
  777.       }
  778.       else if (!(ghdc = CreateDC (gszDriverName, gszDeviceName, gszPort, NULL)))
  779.       {
  780.         MessageBox (ghwndMain, "PrintThread(): CreateDC() failed",
  781.                     GetStringRes2(ERR_MOD_NAME), MB_OK);
  782.         return;
  783.       }
  784.       break;
  785.     }
  786.     case IDM_PRINTDLG:
  787.     {
  788.       PRINTDLG  pd;
  789.       //
  790.       // Initialize a PRINTDLG struct and call PrintDlg to allow user to
  791.       //   specify various printing options...
  792.       //
  793.       memset ((void *) &pd, 0, sizeof(PRINTDLG));
  794.       pd.lStructSize = sizeof(PRINTDLG);
  795.       pd.hwndOwner   = ghwndMain;
  796.       pd.Flags       = PD_RETURNDC;
  797.       pd.hInstance   = NULL;
  798.       PrintDlg(&pd);
  799.       ghdc = pd.hDC;
  800.       if (pd.hDevMode)
  801.         GlobalFree (pd.hDevMode);
  802.       if (pd.hDevNames)
  803.         GlobalFree (pd.hDevNames);
  804.       if (!ghdc)
  805.       {
  806.         MessageBox (ghwndMain, GetStringRes(IDS_PRTDLGFAIL),
  807.                     GetStringRes2(ERR_MOD_NAME), MB_OK);
  808.         return;
  809.       }
  810.     }
  811.   }
  812.   //
  813.   // put up Abort & install the abort procedure
  814.   //
  815.   gbAbort = FALSE;
  816.   ghwndAbort = CreateDialog (ghInst, (LPCTSTR) "Abort", ghwndMain,
  817.                              (DLGPROC) AbortDlgProc);
  818.   EnableWindow (ghwndMain, FALSE);
  819.   SetAbortProc (ghdc, AbortProc);
  820.   //
  821.   // create & select pen/brush
  822.   //
  823.   hpen = CreatePen (giPenStyle, giPenWidth, gdwPenColor);
  824.   SelectObject (ghdc, hpen);
  825.   hbr  = CreateHatchBrush (giBrushStyle, gdwBrushColor);
  826.   SelectObject (ghdc, hbr);
  827.   SetTextColor (ghdc, gdwTextColor);
  828.   SetMapMode (ghdc, giMapMode);
  829.   rect.top       =
  830.   rect.left      = 0;
  831.   rect.right     = GetDeviceCaps (ghdc, HORZRES);
  832.   rect.bottom    = GetDeviceCaps (ghdc, VERTRES);
  833.   di.cbSize      = sizeof(DOCINFO);
  834.   di.lpszDocName = GetStringRes(IDS_PRTTST);
  835.   di.lpszOutput  = NULL;
  836.   StartDoc  (ghdc, &di);
  837.   StartPage (ghdc);
  838.   if (gdwGraphicsOptions)
  839.     Paint (ghdc, &rect);
  840.   else {
  841.     LPSTR pBuf = GetStringRes(IDS_BLANKPG); 
  842.     TextOut (ghdc, 5, 5, (LPCTSTR) pBuf, My_mbslen(pBuf));
  843. }
  844.   EndPage   (ghdc);
  845.   EndDoc    (ghdc);
  846.   DeleteDC  (ghdc);
  847.   if (!gbAbort)
  848.   {
  849.    EnableWindow  (ghwndMain, TRUE);
  850.    DestroyWindow (ghwndAbort);
  851.   }
  852. }
  853. /******************************************************************************
  854. *
  855. *  FUNCTION:    AbortProc
  856. *
  857. *  COMMENTS:    Standard printing abort proc
  858. *
  859. ******************************************************************************/
  860. BOOL CALLBACK AbortProc (HDC hdc, int error)
  861. {
  862.   MSG msg;
  863.   while (!gbAbort && PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
  864.     if (!ghwndAbort || !IsDialogMessage (ghwndAbort, &msg))
  865.     {
  866.       TranslateMessage (&msg);
  867.       DispatchMessage (&msg);
  868.     }
  869.   return !gbAbort;
  870. }
  871. /******************************************************************************
  872. *
  873. *  FUNCTION:    AbortDlgProc (standard dialog procedure INPUTS/RETURNS)
  874. *
  875. *  COMMENTS:    Handles "Abort" dialog messages
  876. *
  877. ******************************************************************************/
  878. LRESULT CALLBACK AbortDlgProc (HWND   hwnd, UINT msg, WPARAM wParam,
  879.                                LPARAM lParam)
  880. {
  881.   switch (msg)
  882.   {
  883.     case WM_INITDIALOG:
  884.       ghwndAbort = hwnd;
  885.       EnableMenuItem (GetSystemMenu (hwnd, FALSE), SC_CLOSE, MF_GRAYED);
  886.       break;
  887.     case WM_COMMAND:
  888.       switch (LOWORD (wParam))
  889.       {
  890.         case DID_CANCEL:
  891.           gbAbort = TRUE;
  892.           AbortDoc (ghdc);
  893.           EnableWindow  (ghwndMain, TRUE);
  894.           DestroyWindow (hwnd);
  895.           return TRUE;
  896.       }
  897.       break;
  898.   }
  899.   return 0;
  900. }
  901. /******************************************************************************
  902. *
  903. *  FUNCTION:    GetStringRes (int id INPUT ONLY)
  904. *
  905. *  COMMENTS:    Load the resource string with the ID given, and return a
  906. *               pointer to it.  Notice that the buffer is common memory so
  907. *               the string must be used before this call is made a second time.
  908. *
  909. ******************************************************************************/
  910. LPTSTR   GetStringRes (int id)
  911. {
  912.   static TCHAR buffer[MAX_PATH];
  913.   buffer[0]=0;
  914.   LoadString (GetModuleHandle (NULL), id, buffer, MAX_PATH);
  915.   return buffer;
  916. }
  917. LPTSTR   GetStringRes2 (int id)
  918. {
  919.   static TCHAR buffer[MAX_PATH];
  920.   buffer[0]=0;
  921.   LoadString (GetModuleHandle (NULL), id, buffer, MAX_PATH);
  922.   return buffer;
  923. }