home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / graphics / icm20 / icmview / print.c < prev    next >
C/C++ Source or Header  |  1997-09-07  |  29KB  |  942 lines

  1. //THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
  2. //ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
  3. //THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  4. // PARTICULAR PURPOSE.
  5. //
  6. // Copyright  1994-1997  Microsoft Corporation.  All Rights Reserved.
  7. //
  8. //  FILE:
  9. //    Print.c
  10. //
  11. //  PURPOSE:
  12. //    Illustrates the 'minimum' functionality of a well-behaved Win32 application.
  13. //
  14. //  PLATFORMS:
  15. //    Windows 95, Windows NT
  16. //
  17. //  SPECIAL INSTRUCTIONS: N/A
  18. //
  19.  
  20. // Windows Header Files:
  21. #pragma warning(disable:4001)   // Single-line comment warnings
  22. #pragma warning(disable:4115)   // Named type definition in parentheses
  23. #pragma warning(disable:4201)   // Nameless struct/union warning
  24. #pragma warning(disable:4214)   // Bit field types other than int warnings
  25. #pragma warning(disable:4514)   // Unreferenced inline function has been removed
  26.  
  27. // Windows Header Files:
  28. #include <Windows.h>
  29. #include <WindowsX.h>
  30. #include <commdlg.h>
  31. #include <winspool.h>
  32. #include "icm.h"
  33.  
  34. // Restore the warnings--leave the single-line comment warning OFF
  35. #pragma warning(default:4115)   // Named type definition in parentheses
  36. #pragma warning(default:4201)   // Nameless struct/union warning
  37. #pragma warning(default:4214)   // Bit field types other than int warnings
  38. #pragma warning(default:4514)   // Unreferenced inline function has been removed
  39.  
  40. // C RunTime Header Files
  41. #include <TCHAR.H>
  42.  
  43. // Local Header Files
  44. #include "IcmView.h"
  45. #include "Child.h"
  46. #include "dibinfo.h"
  47. #include "Dibs.h"
  48.  
  49. #include "Debug.h"
  50.  
  51. #include "Print.h"
  52. #include "RegUtil.h"
  53. #include "Resource.h"
  54.  
  55. // local definitions
  56.  
  57. #ifndef ICM_DONE_OUTSIDEDC
  58.     #define ICM_DONE_OUTSIDEDC  4
  59. #endif
  60.  
  61. // default settings
  62.  
  63. // external functions
  64.  
  65. // external data
  66.  
  67. // public data
  68.  
  69. // private data
  70. BOOL      gbUserAbort;
  71. FARPROC   glpfnPrintDlgProc;
  72. FARPROC   glpfnAbortProc;
  73. HWND      ghDlgPrint;
  74. HWND      ghWndParent;
  75. LOGFONT   gLogFont = { 0, 0, 0, 0, 400, 0, 0, 0, 0, 0, 0, 0, 0, __TEXT("Arial")};
  76.  
  77. // private functions
  78. BOOL FreeMemory(HANDLE hInfo);
  79. LPBYTE GetMemory(LPHANDLE lphInfo, DWORD dwSize);
  80. DWORD SPL_EnumPrinters(DWORD dwType, LPTSTR lpszName, DWORD dwLevel, LPHANDLE lphPrinterInfo);
  81. BOOL PrintDIB (HANDLE hDIB, HDC hDC, int xOrigin, int yOrigin, int xSize, int ySize, BOOL bStretch);
  82. static HDC PASCAL InitPrinting(HWND hWnd, LPTSTR lpszFriendlyName, PDEVMODE pDevMode);
  83. static void PASCAL TermPrinting(HDC hDC);
  84. BOOL FAR PASCAL PrintDlgProc (HWND hDlg, unsigned iMessage, WORD wParam, DWORD lParam);
  85. BOOL FAR PASCAL AbortProc (HDC hPrnDC, short nCode);
  86.  
  87.  
  88. extern DWORD NumColorsInDIB(LPBITMAPINFOHEADER lpbi);
  89.  
  90. // public functions
  91.  
  92. /////////////////////////////////////////////////////////////////////
  93. //  Function:  SelectPrinter
  94. //
  95. //  Description:
  96. //    Uses the Print common dialog box to provide the user with the
  97. //    opportunity to select and set up a particular printer.
  98. //
  99. //  Parameters:
  100. //    hWnd    Handle to the parent window.
  101. //
  102. //  Returns:
  103. //    HDC to requested printer if successful; NULL otherwise.
  104. //
  105. // Comments:
  106. //   If this function returns NULL, the caller should check
  107. //   the latest COMMDLG error by calling CommDlgExtendedError().
  108. //
  109. /////////////////////////////////////////////////////////////////////
  110.  
  111. HDC SelectPrinter(HWND hWnd)
  112. {
  113.     // Local variables
  114.     BOOL      bPrintDlg;        // Return code from PrintDlg function
  115.     PRINTDLG  pd;               // Printer dialog structure
  116.     DWORD     dwError;
  117.     HDC       hDC;              // DC to printer
  118.  
  119.     //  Initialize variables
  120.     hDC = NULL;
  121. #ifdef _DEBUG
  122.     memset(&pd, UNINIT_BYTE, sizeof(PRINTDLG));
  123. #endif
  124.  
  125.     /* Initialize the PRINTDLG members. */
  126.  
  127.     pd.lStructSize = sizeof(PRINTDLG);
  128.     pd.hwndOwner = hWnd;
  129.     pd.Flags = PD_RETURNDC | PD_PRINTSETUP;
  130.     pd.hDevMode = (HANDLE) NULL;
  131.     pd.hDevNames = (HANDLE) NULL;
  132.     pd.hDC = (HDC) NULL;
  133.     pd.nFromPage = 1;
  134.     pd.nToPage = 1;
  135.     pd.nMinPage = 0;
  136.     pd.nMaxPage = 0;
  137.     pd.nCopies = 1;
  138.     pd.hInstance = (HANDLE) NULL;
  139.     pd.lCustData = 0L;
  140.     pd.lpfnPrintHook = (LPPRINTHOOKPROC) NULL;
  141.     pd.lpfnSetupHook = (LPSETUPHOOKPROC) NULL;
  142.     pd.lpPrintTemplateName = (LPTSTR) NULL;
  143.     pd.lpSetupTemplateName = (LPTSTR)  NULL;
  144.     pd.hPrintTemplate = (HANDLE) NULL;
  145.     pd.hSetupTemplate = (HANDLE) NULL;
  146.  
  147.     // Display the PRINT dialog box.
  148.     bPrintDlg = PrintDlg(&pd);
  149.     if (!bPrintDlg)  // Either no changes, or a common dialog error occured
  150.     {
  151.         dwError = CommDlgExtendedError();
  152.         if (dwError != 0)
  153.         {
  154.             return(NULL);
  155.         }
  156.     }
  157.     else // Passed call, set up DC
  158.     {
  159.         ASSERT(pd.hDC != NULL); // HDC should never be NULL if we passed the call
  160.         hDC = pd.hDC;
  161.     }
  162.     return(hDC);
  163. }   // End of SelectPrinter
  164.  
  165.  
  166. // private functions
  167.  
  168.  
  169. //////////////////////////////////////////////////////////////////////////
  170. //  Function:  GetPrinterDC
  171. //
  172. //  Description:
  173. //    Obtains a DC from the specified friendly name.
  174. //
  175. //  Parameters:
  176. //    @@@
  177. //
  178. //  Returns:
  179. //    HDC
  180. //
  181. //  Comments:
  182. //
  183. //
  184. //////////////////////////////////////////////////////////////////////////
  185. HDC GetPrinterDC(LPTSTR lpszFriendlyName, PDEVMODE pDevMode)
  186. {
  187.     HDC     hDC;
  188.     BOOL    bFreeDevMode = FALSE;
  189.  
  190.  
  191.     //  Initialize variables
  192.     hDC = NULL;
  193.  
  194.     if (lpszFriendlyName != NULL)
  195.     {
  196.         // Make sure that we have a devmode.
  197.         if (NULL == pDevMode)
  198.         {
  199.             pDevMode = GetDefaultPrinterDevMode(lpszFriendlyName);
  200.             bFreeDevMode = TRUE;
  201.         }
  202.  
  203.         // Now get a DC for the printer
  204.         hDC = CreateDC(NULL, lpszFriendlyName, NULL, pDevMode);
  205.  
  206.         // Free devmode if created in routine.
  207.         if (bFreeDevMode)
  208.         {
  209.             GlobalFree((HANDLE)pDevMode);
  210.         }
  211.     }
  212.     else
  213.     {
  214.         DebugMsg(__TEXT("GetPrinterDC:  lpszFriendlyName == NULL"));
  215.     }
  216.  
  217.     return hDC;
  218. }   // End of function GetPrinterDC
  219.  
  220. //////////////////////////////////////////////////////////////////////////
  221. //  Function:  GetDefaultPrinterName
  222. //
  223. //  Description:
  224. //    Obtains the name of the default printer.
  225. //
  226. //  Parameters:
  227. //    none
  228. //
  229. //  Returns:
  230. //    LPTSTR   Name of printer, or NULL if failed.
  231. //
  232. //  Comments:
  233. //
  234. //
  235. //////////////////////////////////////////////////////////////////////////
  236. LPTSTR GetDefaultPrinterName(void)
  237. {
  238.     // Local variables
  239.     LPTSTR     lpszDefaultPrinter = NULL;
  240.  
  241.     if (IS_WIN95)
  242.     {
  243.  
  244.         lpszDefaultPrinter = GetRegistryString(HKEY_CURRENT_CONFIG,
  245.                                                __TEXT("SYSTEM\\CurrentControlSet\\Control\\Print\\Printers"),
  246.                                                __TEXT("Default"));
  247.     }
  248.     else if (IS_NT)
  249.     {
  250.         TCHAR szTemp[MAX_PATH];
  251.         LPTSTR lpszTemp;
  252.  
  253.         // Get Default printer name.
  254.         GetProfileString(__TEXT("windows"), __TEXT("device"), __TEXT(""),
  255.                          szTemp, sizeof(szTemp));
  256.  
  257.         if (lstrlen(szTemp) == 0)
  258.         {
  259.             // INVARIANT:  no default printer.
  260.             return(NULL);
  261.         }
  262.  
  263.         // Terminate at first comma, just want printer name.
  264.         lpszTemp = _tcschr(szTemp, ',');
  265.         if (lpszTemp != NULL)
  266.         {
  267.             *lpszTemp = '\x0';
  268.         }
  269.         lpszDefaultPrinter = CopyString((LPTSTR)szTemp);
  270.     }
  271.     return(lpszDefaultPrinter);
  272. }   // End of function GetDefaultPrinterName
  273.  
  274. //////////////////////////////////////////////////////////////////////////
  275. //  Function:  PopulatePrinterCombobox
  276. //
  277. //  Description:
  278. //    Enumerates all printers into a ComboBox based upon the provided flags.
  279. //
  280. //  Parameters:
  281. //    @@@
  282. //
  283. //  Returns:
  284. //    DWORD Number of printers enumerated.  -1 indicates failure.
  285. //
  286. //  Comments:
  287. //
  288. //
  289. //////////////////////////////////////////////////////////////////////////
  290. DWORD PopulatePrinterCombobox(HWND hDlg, int iControlId, LPTSTR lpszCurrentPrinter)
  291. {
  292.     // Local variables
  293.     DWORD             dwReturnCode;
  294.     DWORD             dwIndex;
  295.     DWORD             dwNumPRN;
  296.     LPPRINTER_INFO_2  lpPrinterInfo2;
  297.     HGLOBAL           hFree;
  298.  
  299.     //  Initialize variables
  300.     lpPrinterInfo2 = NULL;
  301.  
  302.     // Initialize ComboBox
  303.     SendDlgItemMessage(hDlg, iControlId, EM_LIMITTEXT, (WPARAM)MAX_PATH, 0L);
  304.     SendDlgItemMessage(hDlg,  iControlId, CB_RESETCONTENT, (WPARAM)0, (LPARAM)0L);
  305.  
  306.     dwNumPRN = SPL_EnumPrinters(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS, NULL, 2, (LPVOID)&lpPrinterInfo2);
  307.     EnableWindow(GetDlgItem(hDlg, iControlId), (dwNumPRN != 0));
  308.     if (dwNumPRN <= 0)
  309.     {
  310.         dwReturnCode = SendDlgItemMessage(hDlg, iControlId, CB_ADDSTRING, 0, (LPARAM)(LPTSTR)__TEXT("No printers installed"));
  311.         dwReturnCode = SendDlgItemMessage(hDlg, iControlId, WM_SETTEXT, 0, (LPARAM)(LPTSTR)__TEXT("No printers installed"));
  312.         return (dwNumPRN);  // No printers to deal with.  -1 if EnumPrinters call failed.
  313.     }
  314.  
  315.     if (lpPrinterInfo2 != NULL) // Got array of PRINTER_INFO structures
  316.     {
  317.         for (dwIndex =0; dwIndex < dwNumPRN; dwIndex++)
  318.         {
  319.             dwReturnCode = SendDlgItemMessage(hDlg, iControlId, CB_ADDSTRING, 0, (LPARAM)(LPTSTR)lpPrinterInfo2[dwIndex].pPrinterName);
  320.             if (dwReturnCode == CB_ERR)
  321.             {
  322.                 return((DWORD)-1);
  323.             }
  324.  
  325.             // If this is the current printer, load it into edit control
  326.             if (lstrcmpi((LPTSTR)lpPrinterInfo2[dwIndex].pPrinterName, lpszCurrentPrinter) == 0)
  327.             {
  328.                 dwReturnCode = SendDlgItemMessage(hDlg, iControlId, WM_SETTEXT, 0, (LPARAM)(LPTSTR)lpPrinterInfo2[dwIndex].pPrinterName);
  329.                 if (dwReturnCode == CB_ERR)
  330.                 {
  331.                     return((DWORD)-1);
  332.                 }  // CB_ERR
  333.             }  // current printer
  334.         } // for (dwIndex = 0 ...
  335.     }  // if (lpPrinterInfo2 != NULL)
  336.     else
  337.     {
  338.         return((DWORD)-1);
  339.     }
  340.  
  341.     // Free memory
  342.     hFree = GlobalFree(lpPrinterInfo2);
  343.     return(dwNumPRN);
  344. }   // End of function PopulatePrinterCombobox
  345.  
  346. ////////////////////////////////////////////////////////////////////////////
  347. //
  348. // FunctionName: SPL_EnumPrinters()
  349. //
  350. // Purpose:
  351. //
  352. // Parameters:
  353. //    None.
  354. //
  355. // Return Value:
  356. //
  357. // Comments:
  358. //
  359. ////////////////////////////////////////////////////////////////////////////
  360.  
  361. DWORD SPL_EnumPrinters(DWORD dwType, LPTSTR lpszName, DWORD dwLevel, LPVOID *lpvPrinterInfo)
  362.  
  363. {
  364.     DWORD        dwSize;
  365.     DWORD        dwPrinters;
  366.     DWORD        dwNeeded    = 0;
  367.     DWORD        dwErrorCode = 0;
  368.     BOOL         bReturnCode;
  369.     BOOL         bRC         = FALSE;
  370.     LPBYTE       lpInfo      = NULL;
  371.  
  372.     // Enumerate Printers.
  373.     bReturnCode = EnumPrinters(dwType, lpszName, dwLevel, NULL, 0, &dwSize, &dwPrinters);
  374.  
  375.     // If Return Code is TRUE, there is nothing to enumerate.
  376.     if (bReturnCode)
  377.     {
  378.         DebugMsg(__TEXT("EnumPrinter():  No printers found\r\n"));
  379.         return(0);
  380.     }
  381.  
  382.     // Since Return Code is FALSE, check LastError.
  383.     // If LastError is any thing other than allocate size error, flag and exit.
  384.     dwErrorCode = GetLastError();
  385.     if (dwErrorCode != ERROR_INSUFFICIENT_BUFFER)
  386.     {
  387.         return((DWORD)-1);
  388.     }
  389.  
  390.     // Loop until we have size right.
  391.     while (!bRC)
  392.     {
  393.         if (NULL != (lpInfo = (LPBYTE)GlobalAlloc(GPTR, dwSize)))
  394.         {
  395. #ifdef _DEBUG
  396.             memset(lpInfo, UNINIT_BYTE, dwSize);
  397. #endif
  398.             // Enumerate
  399.             bRC = EnumPrinters(dwType, lpszName, dwLevel, lpInfo, dwSize, &dwNeeded, &dwPrinters);
  400.             if (!bRC)
  401.             {
  402.                 dwErrorCode = GetLastError();
  403.  
  404.                 // If anything other than allocate size error, flag and exit.
  405.                 if (dwErrorCode != ERROR_INSUFFICIENT_BUFFER)
  406.                 {
  407.                     return((DWORD)-1);
  408.                 }
  409.                 else
  410.                 {
  411.                     GlobalFree(lpInfo);
  412.                     lpInfo = NULL;
  413.                     dwSize = dwNeeded;
  414.                 }
  415.             } // if (!bRC)
  416.             else  // EnumPrinters returned success
  417.             {
  418.                 *lpvPrinterInfo = lpInfo;  // Save pointer to PRINTER_INFO structure
  419.             }
  420.         }
  421.         else
  422.         {
  423.             return((DWORD)-1);
  424.         }
  425.     }
  426.     return(dwPrinters);
  427. }  // End of function SPL_EnumPrinters
  428.  
  429. ////////////////////////////////////////////////////////////////////////////
  430. //
  431. //  FUNCTION:  PrintDIB(HANDLE hDIB, HDC hDC, int x, int y, int dx, int dy)
  432. //
  433. //  PURPOSE:  Set the DIB bits to the printer DC.
  434. //
  435. ////////////////////////////////////////////////////////////////////////////
  436. BOOL PrintDIB (HANDLE hDIB, HDC hDC, int xOrigin, int yOrigin, int xSize, int ySize, BOOL bStretch)
  437. {
  438.     int                 iBits;
  439.     HCURSOR             hCurSave;
  440.     LPBITMAPINFOHEADER  lpDIB;
  441.     LPBITMAPINFOHEADER  lpbi;
  442.  
  443.  
  444.     // Initailize variables
  445.     START_WAIT_CURSOR(hCurSave);  // put up busy cursor
  446.  
  447.     lpDIB = (LPBITMAPINFOHEADER)GlobalLock(hDIB);
  448.  
  449.     // If size > BITMAPINFOHEADER header then
  450.     // need to convert to BITMAPINFOHEADER.
  451.     lpbi = lpDIB;
  452. #ifdef OSR2
  453.     if (sizeof(BITMAPINFOHEADER) < lpDIB->biSize)
  454.     {
  455.         DWORD dwColorTableSize;
  456.         DWORD dwHeaderDataSize;
  457.  
  458.         // Allocate Bitmapinfo memory.
  459.         dwHeaderDataSize = sizeof(BITMAPINFOHEADER) + (lpDIB->biCompression == BI_BITFIELDS ? 12 : 0);
  460.         dwColorTableSize = NumColorsInDIB(lpDIB) * sizeof(RGBQUAD);
  461.         lpbi = (LPBITMAPINFOHEADER) GlobalAlloc(GPTR, dwHeaderDataSize + dwColorTableSize);
  462.         if (NULL == lpbi)
  463.         {
  464.             return FALSE;
  465.         }
  466.  
  467.         // Convert header data into bitmapinfo header.
  468.         memcpy(lpbi, lpDIB, dwHeaderDataSize);
  469.         lpbi->biSize = sizeof(BITMAPINFOHEADER);
  470.  
  471.         // Copy color table if any.
  472.         if (0 != dwColorTableSize)
  473.             memcpy((LPBYTE)lpbi + dwHeaderDataSize, (LPBYTE)lpDIB + lpDIB->biSize, dwColorTableSize);
  474.     }
  475. #endif
  476.  
  477.     if (bStretch)
  478.     {
  479.         iBits = StretchDIBits(hDC,
  480.                               xOrigin, yOrigin,
  481.                               xSize, ySize,
  482.                               0, 0,
  483.                               BITMAPWIDTH(lpbi), abs(BITMAPHEIGHT(lpbi)),
  484.                               FindDIBBits(lpDIB),
  485.                               (LPBITMAPINFO)lpbi,
  486.                               DIB_RGB_COLORS,
  487.                               SRCCOPY);
  488.     }
  489.     else
  490.     {
  491.         iBits  =   SetDIBitsToDevice (hDC,                                  // hDC
  492.                                       xOrigin,                              // DestX
  493.                                       yOrigin,                              // DestY
  494.                                       BITMAPWIDTH(lpbi),                    // nDestWidth
  495.                                       abs(BITMAPHEIGHT(lpbi)),              // nDestHeight
  496.                                       0,                                    // SrcX
  497.                                       0,                                    // SrcY
  498.                                       0,                                    // nStartScan
  499.                                       abs(BITMAPHEIGHT(lpbi)),              // nNumScans
  500.                                       FindDIBBits(lpDIB),
  501.                                       (LPBITMAPINFO) lpbi,                  // lpBitsInfo
  502.                                       DIB_RGB_COLORS);                      // wUsage
  503.     }
  504.     END_WAIT_CURSOR(hCurSave);   // restore cursor
  505.     if (lpbi != lpDIB)
  506.     {
  507.         GlobalFree((HANDLE)lpbi);
  508.     }
  509.     GlobalUnlock(hDIB);
  510.     return((iBits != 0) && (iBits != GDI_ERROR));
  511. }
  512.  
  513. //////////////////////////////////////////////////////////////////////////
  514. //  Function:  PrintImage
  515. //
  516. //  Description:
  517. //    Prints the image to the printer specified within the DIBINFO structure.
  518. //
  519. //  Parameters:
  520. //    @@@
  521. //
  522. //  Returns:
  523. //    BOOL
  524. //
  525. //  Comments:
  526. //
  527. //
  528. //////////////////////////////////////////////////////////////////////////
  529. BOOL PrintImage(HWND hWnd)
  530. {
  531.     // Local variables
  532.     LPBITMAPINFOHEADER lpBi;
  533.     int               xSize, ySize, xRes, yRes, dx, dy;
  534.     LPDIBINFO         lpDIBInfo;
  535.     HDC               hDC;
  536.     HANDLE            hDIB;
  537.     int               iICMMode, iPrevICMMode;
  538.     int               iXOrigin, iYOrigin;
  539.     BOOL              bRC;                    // general return code
  540.     BOOL              bStretch;     // TRUE if to use StretchDIBits,
  541.                                     // FALSE if to use SetDIBitsToDevice
  542.     TCHAR             stPrintMsg[MAX_PATH*2];
  543.     HANDLE            hDIBPrinter;
  544.     DWORD             dwLCSIntent;
  545.  
  546.  
  547.     //  Initialize variables
  548.     hDIBPrinter = NULL;
  549.     lpDIBInfo = GetDIBInfoPtr(hWnd);
  550.     if (NULL == lpDIBInfo)
  551.     {
  552.         SetLastError(ERROR_INVALID_DATA);;
  553.         return(FALSE);
  554.     }
  555.     hDIB = lpDIBInfo->hDIB;
  556.     if (!ConvertIntent(lpDIBInfo->dwRenderIntent, ICC_TO_LCS, &dwLCSIntent))
  557.     {
  558.         ErrMsg(hWnd, __TEXT("Invalid Intent.  Aborting Print process"));
  559.     }
  560.  
  561.  
  562.     if (CHECK_DWFLAG(lpDIBInfo->dwICMFlags, ICMVFLAGS_ICM20)
  563.         && (CHECK_DWFLAG(lpDIBInfo->dwICMFlags, ICMVFLAGS_ENABLE_ICM)))
  564.     {
  565.         // ICM On, using outside DC, a.k.a. ICM20
  566.         DebugMsg(__TEXT("PrintImage:  Outside DC, ICM Enabled\r\n"));
  567.  
  568.         // Create transform of the original bits to the printer
  569.         ASSERT(NULL != lpDIBInfo->lpszPrinterProfile);
  570.         hDIBPrinter  = TransformDIBOutsideDC(lpDIBInfo->hDIB,
  571.                                              lpDIBInfo->bmFormat,
  572.                                              lpDIBInfo->lpszPrinterProfile,
  573.                                              NULL,
  574.                                              USE_BITMAP_INTENT, NULL, 0);
  575.         if (NULL == hDIBPrinter)
  576.         {
  577.             ErrMsg(hWnd, __TEXT("PrintImage:  Unable to transform DIB"));
  578.             return(FALSE);
  579.         }
  580.         else // Transform worked
  581.         {
  582.             hDIB = hDIBPrinter;
  583.         }
  584.     }
  585.     ASSERT(NULL != hDIB);
  586.     lpBi = GlobalLock(hDIB);
  587.  
  588.     // Initialize printing
  589.     hDC = InitPrinting(hWnd, lpDIBInfo->lpszPrinterName, lpDIBInfo->pDevMode);
  590.     if (NULL != hDC)
  591.     {
  592.         // Get addresses of dialog procs
  593.         glpfnPrintDlgProc = (FARPROC)&PrintDlgProc;
  594.         glpfnAbortProc = (FARPROC)&AbortProc;
  595.  
  596.         // Create the printing dialog
  597.         ghDlgPrint = CreateDialog(ghInst, MAKEINTRESOURCE(IDD_PRINTING), ghWndParent, (DLGPROC)glpfnPrintDlgProc);
  598.  
  599.         EnableWindow( ghWndParent, FALSE);  // Disable Parent
  600.         CenterWindow(ghDlgPrint, ghWndParent);
  601.         wsprintf(stPrintMsg, __TEXT("Printing image\r\n\r\n%s\r\n\r\nto\r\n\r\n%s"), lpDIBInfo->lpszImageFileName, lpDIBInfo->lpszPrinterName);
  602.         SetWindowText(GetDlgItem(ghDlgPrint, IDC_PRINT_FILENAME), (LPTSTR)stPrintMsg);
  603.         ShowWindow(ghDlgPrint, SW_SHOW);
  604.  
  605.         // Set the abort procedure
  606.         if (SetAbortProc(hDC, (ABORTPROC)glpfnAbortProc) == SP_ERROR)
  607.         {
  608.             ErrMsg(hWnd, __TEXT("InitPrinting:  SetAbortProc FAILED, LastError = %ld"), GetLastError());
  609.         }
  610.  
  611.         // Use the printable region of the printer to determine
  612.         // the margins.
  613.         iXOrigin = GetDeviceCaps(hDC, PHYSICALOFFSETX);
  614.         iYOrigin = GetDeviceCaps(hDC, PHYSICALOFFSETY);
  615.  
  616.         // Obtain info about printer resolution
  617.         xSize = GetDeviceCaps(hDC, HORZRES);
  618.         ySize = GetDeviceCaps(hDC, VERTRES);
  619.         xRes  = GetDeviceCaps(hDC, LOGPIXELSX);
  620.         yRes  = GetDeviceCaps(hDC, LOGPIXELSY);
  621.  
  622.         // Stretch to best fit, if necessary.  Maintain the same aspect ratio.
  623.         if (CHECK_DWFLAG(lpDIBInfo->dwPrintOption,ICMV_PRINT_BESTFIT))
  624.         {
  625.             bStretch = TRUE;
  626.             dy = ySize - (yRes/2);
  627.             dx = ((int)((long)dy * BITMAPWIDTH(lpBi)/abs(BITMAPHEIGHT(lpBi)) ));
  628.  
  629.             // Make sure the image still fits.
  630.             if (dx > xSize)
  631.             {
  632.                 dx = xSize - xRes/2;
  633.                 dy = ((int)((long)dx * abs(BITMAPHEIGHT(lpBi))/BITMAPWIDTH(lpBi)));
  634.             }
  635.         }
  636.         else // Actual size
  637.         {
  638.             bStretch = FALSE;
  639.             dx = BITMAPWIDTH(lpBi);
  640.             dy = abs(BITMAPHEIGHT(lpBi));
  641.         }
  642.  
  643.         // Set ICM mode according to properties set in ICMINFO structure
  644.         iICMMode = ICM_OFF;
  645.         if (CHECK_DWFLAG(lpDIBInfo->dwICMFlags, ICMVFLAGS_ENABLE_ICM))
  646.         {
  647.             if (!CHECK_DWFLAG(lpDIBInfo->dwICMFlags, ICMVFLAGS_ICM20))
  648.             {
  649.                 TCHAR   stProfile[MAX_PATH];
  650.  
  651.  
  652.                 // ICM enabled, using ICM10--inside DC
  653.  
  654.                 iICMMode = ICM_ON;
  655.                 wsprintf(stProfile, __TEXT("%s\\%s"), gstProfilesDir, lpDIBInfo->lpszPrinterProfile);
  656.                 bRC = SetICMProfile(hDC, (LPTSTR)stProfile);
  657.                 DebugMsg(__TEXT("PrintImage:  Inside DC using profile \"%s\".\r\n"), stProfile);
  658.                 if (!bRC)
  659.                 {
  660.                     DebugMsg(__TEXT("Print.C, PrintImage:  SetICMProfile() FAILED!!\r\n"));
  661.                 }
  662.             }
  663.             else
  664.             {
  665.                 iICMMode = ICM_DONE_OUTSIDEDC;
  666.             }
  667.         }
  668.         iPrevICMMode = SetICMMode(hDC, iICMMode);  // Explicitly set ICMMode--don't count on any behavior
  669.         if (0 == iPrevICMMode)
  670.         {
  671.             DebugMsg(__TEXT("PRINT.C : PrintImage : SetICMMode(%d) FAILED \r\n"), iICMMode);
  672.         }
  673.         PrintDIB(hDIB, hDC, iXOrigin, iYOrigin, dx, dy, bStretch);
  674.  
  675.         // Terminate printing and delete the printer DC
  676.         TermPrinting(hDC);
  677.         DeleteDC(hDC);
  678.     }
  679.  
  680.     // Delete DIB transform for printer if necessary
  681.     GlobalUnlock(hDIB);
  682.     if (NULL != hDIBPrinter)
  683.     {
  684.         GlobalFree(hDIBPrinter);
  685.     }
  686.  
  687.     GlobalUnlock(GlobalHandle(lpDIBInfo));
  688.  
  689.     return TRUE;
  690. }   // End of function PrintImage
  691.  
  692.  
  693. // //////////////////////////////////////////////////////////////////////////
  694. //
  695. //  FUNCTION:  PrintDlgProc (hWnd, unsigned , WORD , DWORD )
  696. //
  697. //  PURPOSE:  Dialog function for the "Cancel Printing" dialog. It sets
  698. //              the abort flag if the user presses <Cancel>.
  699. //
  700. // //////////////////////////////////////////////////////////////////////////
  701. BOOL FAR PASCAL PrintDlgProc (HWND hDlg, unsigned iMessage, WORD wParam, DWORD lParam)
  702. {
  703.  
  704.     lParam = lParam;  // Eliminates 'unused formal parameter' warning
  705.     wParam = wParam;  // Eliminates 'unused formal parameter' warning
  706.  
  707.     switch (iMessage)
  708.     {
  709.         case WM_INITDIALOG:
  710.             EnableMenuItem (GetSystemMenu (hDlg, FALSE), SC_CLOSE, MF_GRAYED);
  711.             break;
  712.  
  713.         case WM_COMMAND:
  714.             gbUserAbort = TRUE;
  715.             EnableWindow (ghWndParent, TRUE);
  716.             DestroyWindow (hDlg);
  717.             ghDlgPrint = 0;
  718.             break;
  719.  
  720.         default:
  721.             return(FALSE);
  722.     }
  723.     return(TRUE);
  724. }
  725.  
  726. // //////////////////////////////////////////////////////////////////////////
  727. //
  728. //  FUNCTION:  AbortProc (HDC hPrnDC, short nCode)
  729. //
  730. //  PURPOSE:  Checks message queue for messages from the "Cancel Printing"
  731. //              dialog. If it sees a message, (this will be from a print
  732. //              cancel command), it terminates.
  733. //
  734. //  RETURNS:  Inverse of Abort flag
  735. //
  736. // //////////////////////////////////////////////////////////////////////////
  737. BOOL FAR PASCAL AbortProc (HDC hPrnDC, short nCode)
  738. {
  739.     MSG   msg;
  740.  
  741.     nCode = nCode;  // Eliminates 'unused formal paramater' warning
  742.     hPrnDC = hPrnDC;  // Eliminates 'unused formal paramater' warning
  743.     while (!gbUserAbort && PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
  744.     {
  745.         if (!ghDlgPrint || !IsDialogMessage(ghDlgPrint, &msg))
  746.         {
  747.             TranslateMessage (&msg);
  748.             DispatchMessage (&msg);
  749.         }
  750.     }
  751.     return(!gbUserAbort);
  752. }
  753.  
  754. //////////////////////////////////////////////////////////////////////////
  755. //  Function:  InitPrinting
  756. //
  757. //  Description:
  758. //    Sets up print job.
  759. //
  760. //  Parameters:
  761. //    @@@
  762. //
  763. //  Returns:
  764. //    HDC PASCAL
  765. //
  766. //  Comments:
  767. //
  768. //
  769. //////////////////////////////////////////////////////////////////////////
  770. static HDC PASCAL InitPrinting(HWND hWnd, LPTSTR lpszFriendlyName, PDEVMODE pDevMode)
  771. {
  772.     // Local variables
  773.     HDC       hDC;
  774.     DOCINFO   diDocInfo;      // Document infor for StartDoc call
  775.     BOOL      bRetVal;
  776.  
  777.     //  Initialize variables
  778.     hDC = NULL;
  779.     bRetVal = TRUE;
  780.     gbUserAbort = FALSE;
  781.     ghWndParent = hWnd;
  782.     SetLastError(0);
  783.  
  784.     hDC = GetPrinterDC(lpszFriendlyName, pDevMode);
  785.     if (hDC == NULL)
  786.     {
  787.         DebugMsg(__TEXT("InitPrinting : GetPrinterDC returned NULL\r\n"));
  788.         return(NULL);
  789.     }
  790.  
  791.     // Fill in the DOCINFO structure
  792.     diDocInfo.cbSize = sizeof(DOCINFO);
  793.     diDocInfo.lpszDocName = lpszFriendlyName;
  794.     diDocInfo.lpszOutput = NULL;
  795.     diDocInfo.lpszDatatype = NULL;
  796.     diDocInfo.fwType = 0;
  797.  
  798.     // Start the document
  799.     if (StartDoc(hDC, &diDocInfo)== SP_ERROR)
  800.     {
  801.         ErrMsg(hWnd, __TEXT("InitPrinting:  StartDoc FAILED"));
  802.         bRetVal = FALSE;
  803.         goto exit;
  804.     }
  805.  
  806.     // Start the page
  807.     if (StartPage(hDC) == SP_ERROR)
  808.     {
  809.         DISPLAY_LASTERROR(LASTERROR_NOALLOC,GetLastError());
  810.         ErrMsg(hWnd, __TEXT("InitPrinting:  StartPage FAILED"));
  811.         AbortDoc(hDC);
  812.         bRetVal = FALSE;
  813.     }
  814.  
  815.     exit:
  816.     if (bRetVal == FALSE)
  817.     {
  818.         EnableWindow(   ghWndParent,    TRUE);
  819.         DestroyWindow(ghDlgPrint);
  820.     }
  821.     return(hDC);
  822. }   // End of function InitPrinting
  823.  
  824. //////////////////////////////////////////////////////////////////////////
  825. //  Function:  TermPrinting
  826. //
  827. //  Description:
  828. //    Terminates the print job.
  829. //
  830. //  Parameters:
  831. //    @@@
  832. //
  833. //  Returns:
  834. //    void PASCAL
  835. //
  836. //  Comments:
  837. //
  838. //
  839. //////////////////////////////////////////////////////////////////////////
  840. static void PASCAL TermPrinting(HDC hDC)
  841. {
  842.     // Local variables
  843.     if (EndPage(hDC) == SP_ERROR)
  844.     {
  845.         ErrMsg(NULL, __TEXT("TermPrinting:  EndPage FAILED"));
  846.     }
  847.     if (EndDoc(hDC) == SP_ERROR)
  848.     {
  849.         ErrMsg(NULL, __TEXT("TermPrinting:  EndDoc FAILED"));
  850.     }
  851.  
  852.     // Dstroy the dialog
  853.     EnableWindow(ghWndParent, TRUE);
  854.     DestroyWindow(ghDlgPrint);
  855. }   // End of function TermPrinting
  856.  
  857.  
  858.  
  859.  
  860.  
  861. //////////////////////////////////////////////////////////////////////////
  862. //  Function:  GetDefaultPrinterDC
  863. //
  864. //  Description:
  865. //    Returns a DC for the default printer.
  866. //
  867. //  Parameters:
  868. //    @@@
  869. //
  870. //  Returns:
  871. //    HDC
  872. //
  873. //  Comments:
  874. //
  875. //
  876. //////////////////////////////////////////////////////////////////////////
  877. HDC GetDefaultPrinterDC()
  878. {
  879.     HDC     hDC;
  880.     LPTSTR  lpszPrinterName;
  881.  
  882.  
  883.     //  Initialize variables
  884.     hDC = NULL;
  885.  
  886.     lpszPrinterName = GetDefaultPrinterName();
  887.     if (lpszPrinterName != NULL)
  888.     {
  889.         hDC = GetPrinterDC(lpszPrinterName, NULL);
  890.         GlobalFree(lpszPrinterName);
  891.     }
  892.     else
  893.     {
  894.         DebugMsg(__TEXT("GetDefaultPrinterDC:  Could not obtain default printer name.\r\n"));
  895.     }
  896.  
  897.     return hDC;
  898. }   // End of function GetDefaultPrinterDC
  899.  
  900.  
  901.  
  902. //////////////////////////////////////////////////////////////////////////
  903. //  Function:  GetDefaultPrinterDevMode
  904. //
  905. //  Description:
  906. //    Returns a printer's default devmode.
  907. //
  908. //  Parameters:
  909. //    @@@
  910. //
  911. //  Returns:
  912. //    PDEVMODE
  913. //
  914. //  Comments:
  915. //
  916. //
  917. //////////////////////////////////////////////////////////////////////////
  918. PDEVMODE GetDefaultPrinterDevMode(LPTSTR lpszPrinterName)
  919. {
  920.     LONG        lDevModeSize;
  921.     HANDLE      hDevMode;
  922.     PDEVMODE    pDevMode = NULL;
  923.  
  924.  
  925.     lDevModeSize = DocumentProperties(NULL, NULL, lpszPrinterName, NULL, NULL, 0);
  926.     if (lDevModeSize > 0)
  927.     {
  928.         hDevMode = GlobalAlloc(GHND, lDevModeSize);
  929.         pDevMode = (PDEVMODE) GlobalLock(hDevMode);
  930.         DocumentProperties(NULL, NULL, lpszPrinterName, pDevMode, NULL, DM_OUT_BUFFER);
  931.     }
  932.     else
  933.     {
  934.         DebugMsg(__TEXT("GetDefaultPrinterDevMode:  Could not obtain printer's devmode.\r\n"));
  935.     }
  936.  
  937.     return pDevMode;
  938. }
  939.  
  940.  
  941.  
  942.