home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / graphics / gdi / printer / printer.c < prev    next >
C/C++ Source or Header  |  1997-10-05  |  35KB  |  1,197 lines

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