942 lines
28 KiB
C
942 lines
28 KiB
C
//THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
|
|
//ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
|
|
//THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
|
|
// PARTICULAR PURPOSE.
|
|
//
|
|
// Copyright 1994-1997 Microsoft Corporation. All Rights Reserved.
|
|
//
|
|
// FILE:
|
|
// Print.c
|
|
//
|
|
// PURPOSE:
|
|
// Illustrates the 'minimum' functionality of a well-behaved Win32 application.
|
|
//
|
|
// PLATFORMS:
|
|
// Windows 95, Windows NT
|
|
//
|
|
// SPECIAL INSTRUCTIONS: N/A
|
|
//
|
|
|
|
// Windows Header Files:
|
|
#pragma warning(disable:4001) // Single-line comment warnings
|
|
#pragma warning(disable:4115) // Named type definition in parentheses
|
|
#pragma warning(disable:4201) // Nameless struct/union warning
|
|
#pragma warning(disable:4214) // Bit field types other than int warnings
|
|
#pragma warning(disable:4514) // Unreferenced inline function has been removed
|
|
|
|
// Windows Header Files:
|
|
#include <Windows.h>
|
|
#include <WindowsX.h>
|
|
#include <commdlg.h>
|
|
#include <winspool.h>
|
|
#include "icm.h"
|
|
|
|
// Restore the warnings--leave the single-line comment warning OFF
|
|
#pragma warning(default:4115) // Named type definition in parentheses
|
|
#pragma warning(default:4201) // Nameless struct/union warning
|
|
#pragma warning(default:4214) // Bit field types other than int warnings
|
|
#pragma warning(default:4514) // Unreferenced inline function has been removed
|
|
|
|
// C RunTime Header Files
|
|
#include <TCHAR.H>
|
|
|
|
// Local Header Files
|
|
#include "IcmView.h"
|
|
#include "Child.h"
|
|
#include "dibinfo.h"
|
|
#include "Dibs.h"
|
|
|
|
#include "Debug.h"
|
|
|
|
#include "Print.h"
|
|
#include "RegUtil.h"
|
|
#include "Resource.h"
|
|
|
|
// local definitions
|
|
|
|
#ifndef ICM_DONE_OUTSIDEDC
|
|
#define ICM_DONE_OUTSIDEDC 4
|
|
#endif
|
|
|
|
// default settings
|
|
|
|
// external functions
|
|
|
|
// external data
|
|
|
|
// public data
|
|
|
|
// private data
|
|
BOOL gbUserAbort;
|
|
FARPROC glpfnPrintDlgProc;
|
|
FARPROC glpfnAbortProc;
|
|
HWND ghDlgPrint;
|
|
HWND ghWndParent;
|
|
LOGFONT gLogFont = { 0, 0, 0, 0, 400, 0, 0, 0, 0, 0, 0, 0, 0, __TEXT("Arial")};
|
|
|
|
// private functions
|
|
BOOL FreeMemory(HANDLE hInfo);
|
|
LPBYTE GetMemory(LPHANDLE lphInfo, DWORD dwSize);
|
|
DWORD SPL_EnumPrinters(DWORD dwType, LPTSTR lpszName, DWORD dwLevel, LPHANDLE lphPrinterInfo);
|
|
BOOL PrintDIB (HANDLE hDIB, HDC hDC, int xOrigin, int yOrigin, int xSize, int ySize, BOOL bStretch);
|
|
static HDC PASCAL InitPrinting(HWND hWnd, LPTSTR lpszFriendlyName, PDEVMODE pDevMode);
|
|
static void PASCAL TermPrinting(HDC hDC);
|
|
BOOL FAR PASCAL PrintDlgProc (HWND hDlg, unsigned iMessage, WORD wParam, DWORD lParam);
|
|
BOOL FAR PASCAL AbortProc (HDC hPrnDC, short nCode);
|
|
|
|
|
|
extern DWORD NumColorsInDIB(LPBITMAPINFOHEADER lpbi);
|
|
|
|
// public functions
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
// Function: SelectPrinter
|
|
//
|
|
// Description:
|
|
// Uses the Print common dialog box to provide the user with the
|
|
// opportunity to select and set up a particular printer.
|
|
//
|
|
// Parameters:
|
|
// hWnd Handle to the parent window.
|
|
//
|
|
// Returns:
|
|
// HDC to requested printer if successful; NULL otherwise.
|
|
//
|
|
// Comments:
|
|
// If this function returns NULL, the caller should check
|
|
// the latest COMMDLG error by calling CommDlgExtendedError().
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
HDC SelectPrinter(HWND hWnd)
|
|
{
|
|
// Local variables
|
|
BOOL bPrintDlg; // Return code from PrintDlg function
|
|
PRINTDLG pd; // Printer dialog structure
|
|
DWORD dwError;
|
|
HDC hDC; // DC to printer
|
|
|
|
// Initialize variables
|
|
hDC = NULL;
|
|
#ifdef _DEBUG
|
|
memset(&pd, UNINIT_BYTE, sizeof(PRINTDLG));
|
|
#endif
|
|
|
|
/* Initialize the PRINTDLG members. */
|
|
|
|
pd.lStructSize = sizeof(PRINTDLG);
|
|
pd.hwndOwner = hWnd;
|
|
pd.Flags = PD_RETURNDC | PD_PRINTSETUP;
|
|
pd.hDevMode = (HANDLE) NULL;
|
|
pd.hDevNames = (HANDLE) NULL;
|
|
pd.hDC = (HDC) NULL;
|
|
pd.nFromPage = 1;
|
|
pd.nToPage = 1;
|
|
pd.nMinPage = 0;
|
|
pd.nMaxPage = 0;
|
|
pd.nCopies = 1;
|
|
pd.hInstance = (HANDLE) NULL;
|
|
pd.lCustData = 0L;
|
|
pd.lpfnPrintHook = (LPPRINTHOOKPROC) NULL;
|
|
pd.lpfnSetupHook = (LPSETUPHOOKPROC) NULL;
|
|
pd.lpPrintTemplateName = (LPTSTR) NULL;
|
|
pd.lpSetupTemplateName = (LPTSTR) NULL;
|
|
pd.hPrintTemplate = (HANDLE) NULL;
|
|
pd.hSetupTemplate = (HANDLE) NULL;
|
|
|
|
// Display the PRINT dialog box.
|
|
bPrintDlg = PrintDlg(&pd);
|
|
if (!bPrintDlg) // Either no changes, or a common dialog error occured
|
|
{
|
|
dwError = CommDlgExtendedError();
|
|
if (dwError != 0)
|
|
{
|
|
return(NULL);
|
|
}
|
|
}
|
|
else // Passed call, set up DC
|
|
{
|
|
ASSERT(pd.hDC != NULL); // HDC should never be NULL if we passed the call
|
|
hDC = pd.hDC;
|
|
}
|
|
return(hDC);
|
|
} // End of SelectPrinter
|
|
|
|
|
|
// private functions
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Function: GetPrinterDC
|
|
//
|
|
// Description:
|
|
// Obtains a DC from the specified friendly name.
|
|
//
|
|
// Parameters:
|
|
// @@@
|
|
//
|
|
// Returns:
|
|
// HDC
|
|
//
|
|
// Comments:
|
|
//
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////
|
|
HDC GetPrinterDC(LPTSTR lpszFriendlyName, PDEVMODE pDevMode)
|
|
{
|
|
HDC hDC;
|
|
BOOL bFreeDevMode = FALSE;
|
|
|
|
|
|
// Initialize variables
|
|
hDC = NULL;
|
|
|
|
if (lpszFriendlyName != NULL)
|
|
{
|
|
// Make sure that we have a devmode.
|
|
if (NULL == pDevMode)
|
|
{
|
|
pDevMode = GetDefaultPrinterDevMode(lpszFriendlyName);
|
|
bFreeDevMode = TRUE;
|
|
}
|
|
|
|
// Now get a DC for the printer
|
|
hDC = CreateDC(NULL, lpszFriendlyName, NULL, pDevMode);
|
|
|
|
// Free devmode if created in routine.
|
|
if (bFreeDevMode)
|
|
{
|
|
GlobalFree((HANDLE)pDevMode);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DebugMsg(__TEXT("GetPrinterDC: lpszFriendlyName == NULL"));
|
|
}
|
|
|
|
return hDC;
|
|
} // End of function GetPrinterDC
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Function: GetDefaultPrinterName
|
|
//
|
|
// Description:
|
|
// Obtains the name of the default printer.
|
|
//
|
|
// Parameters:
|
|
// none
|
|
//
|
|
// Returns:
|
|
// LPTSTR Name of printer, or NULL if failed.
|
|
//
|
|
// Comments:
|
|
//
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////
|
|
LPTSTR GetDefaultPrinterName(void)
|
|
{
|
|
// Local variables
|
|
LPTSTR lpszDefaultPrinter = NULL;
|
|
|
|
if (IS_WIN95)
|
|
{
|
|
|
|
lpszDefaultPrinter = GetRegistryString(HKEY_CURRENT_CONFIG,
|
|
__TEXT("SYSTEM\\CurrentControlSet\\Control\\Print\\Printers"),
|
|
__TEXT("Default"));
|
|
}
|
|
else if (IS_NT)
|
|
{
|
|
TCHAR szTemp[MAX_PATH];
|
|
LPTSTR lpszTemp;
|
|
|
|
// Get Default printer name.
|
|
GetProfileString(__TEXT("windows"), __TEXT("device"), __TEXT(""),
|
|
szTemp, sizeof(szTemp));
|
|
|
|
if (lstrlen(szTemp) == 0)
|
|
{
|
|
// INVARIANT: no default printer.
|
|
return(NULL);
|
|
}
|
|
|
|
// Terminate at first comma, just want printer name.
|
|
lpszTemp = _tcschr(szTemp, ',');
|
|
if (lpszTemp != NULL)
|
|
{
|
|
*lpszTemp = '\x0';
|
|
}
|
|
lpszDefaultPrinter = CopyString((LPTSTR)szTemp);
|
|
}
|
|
return(lpszDefaultPrinter);
|
|
} // End of function GetDefaultPrinterName
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Function: PopulatePrinterCombobox
|
|
//
|
|
// Description:
|
|
// Enumerates all printers into a ComboBox based upon the provided flags.
|
|
//
|
|
// Parameters:
|
|
// @@@
|
|
//
|
|
// Returns:
|
|
// DWORD Number of printers enumerated. -1 indicates failure.
|
|
//
|
|
// Comments:
|
|
//
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////
|
|
DWORD PopulatePrinterCombobox(HWND hDlg, int iControlId, LPTSTR lpszCurrentPrinter)
|
|
{
|
|
// Local variables
|
|
DWORD dwReturnCode;
|
|
DWORD dwIndex;
|
|
DWORD dwNumPRN;
|
|
LPPRINTER_INFO_2 lpPrinterInfo2;
|
|
HGLOBAL hFree;
|
|
|
|
// Initialize variables
|
|
lpPrinterInfo2 = NULL;
|
|
|
|
// Initialize ComboBox
|
|
SendDlgItemMessage(hDlg, iControlId, EM_LIMITTEXT, (WPARAM)MAX_PATH, 0L);
|
|
SendDlgItemMessage(hDlg, iControlId, CB_RESETCONTENT, (WPARAM)0, (LPARAM)0L);
|
|
|
|
dwNumPRN = SPL_EnumPrinters(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS, NULL, 2, (LPVOID)&lpPrinterInfo2);
|
|
EnableWindow(GetDlgItem(hDlg, iControlId), (dwNumPRN != 0));
|
|
if (dwNumPRN <= 0)
|
|
{
|
|
dwReturnCode = SendDlgItemMessage(hDlg, iControlId, CB_ADDSTRING, 0, (LPARAM)(LPTSTR)__TEXT("No printers installed"));
|
|
dwReturnCode = SendDlgItemMessage(hDlg, iControlId, WM_SETTEXT, 0, (LPARAM)(LPTSTR)__TEXT("No printers installed"));
|
|
return (dwNumPRN); // No printers to deal with. -1 if EnumPrinters call failed.
|
|
}
|
|
|
|
if (lpPrinterInfo2 != NULL) // Got array of PRINTER_INFO structures
|
|
{
|
|
for (dwIndex =0; dwIndex < dwNumPRN; dwIndex++)
|
|
{
|
|
dwReturnCode = SendDlgItemMessage(hDlg, iControlId, CB_ADDSTRING, 0, (LPARAM)(LPTSTR)lpPrinterInfo2[dwIndex].pPrinterName);
|
|
if (dwReturnCode == CB_ERR)
|
|
{
|
|
return((DWORD)-1);
|
|
}
|
|
|
|
// If this is the current printer, load it into edit control
|
|
if (lstrcmpi((LPTSTR)lpPrinterInfo2[dwIndex].pPrinterName, lpszCurrentPrinter) == 0)
|
|
{
|
|
dwReturnCode = SendDlgItemMessage(hDlg, iControlId, WM_SETTEXT, 0, (LPARAM)(LPTSTR)lpPrinterInfo2[dwIndex].pPrinterName);
|
|
if (dwReturnCode == CB_ERR)
|
|
{
|
|
return((DWORD)-1);
|
|
} // CB_ERR
|
|
} // current printer
|
|
} // for (dwIndex = 0 ...
|
|
} // if (lpPrinterInfo2 != NULL)
|
|
else
|
|
{
|
|
return((DWORD)-1);
|
|
}
|
|
|
|
// Free memory
|
|
hFree = GlobalFree(lpPrinterInfo2);
|
|
return(dwNumPRN);
|
|
} // End of function PopulatePrinterCombobox
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FunctionName: SPL_EnumPrinters()
|
|
//
|
|
// Purpose:
|
|
//
|
|
// Parameters:
|
|
// None.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// Comments:
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
DWORD SPL_EnumPrinters(DWORD dwType, LPTSTR lpszName, DWORD dwLevel, LPVOID *lpvPrinterInfo)
|
|
|
|
{
|
|
DWORD dwSize;
|
|
DWORD dwPrinters;
|
|
DWORD dwNeeded = 0;
|
|
DWORD dwErrorCode = 0;
|
|
BOOL bReturnCode;
|
|
BOOL bRC = FALSE;
|
|
LPBYTE lpInfo = NULL;
|
|
|
|
// Enumerate Printers.
|
|
bReturnCode = EnumPrinters(dwType, lpszName, dwLevel, NULL, 0, &dwSize, &dwPrinters);
|
|
|
|
// If Return Code is TRUE, there is nothing to enumerate.
|
|
if (bReturnCode)
|
|
{
|
|
DebugMsg(__TEXT("EnumPrinter(): No printers found\r\n"));
|
|
return(0);
|
|
}
|
|
|
|
// Since Return Code is FALSE, check LastError.
|
|
// If LastError is any thing other than allocate size error, flag and exit.
|
|
dwErrorCode = GetLastError();
|
|
if (dwErrorCode != ERROR_INSUFFICIENT_BUFFER)
|
|
{
|
|
return((DWORD)-1);
|
|
}
|
|
|
|
// Loop until we have size right.
|
|
while (!bRC)
|
|
{
|
|
if (NULL != (lpInfo = (LPBYTE)GlobalAlloc(GPTR, dwSize)))
|
|
{
|
|
#ifdef _DEBUG
|
|
memset(lpInfo, UNINIT_BYTE, dwSize);
|
|
#endif
|
|
// Enumerate
|
|
bRC = EnumPrinters(dwType, lpszName, dwLevel, lpInfo, dwSize, &dwNeeded, &dwPrinters);
|
|
if (!bRC)
|
|
{
|
|
dwErrorCode = GetLastError();
|
|
|
|
// If anything other than allocate size error, flag and exit.
|
|
if (dwErrorCode != ERROR_INSUFFICIENT_BUFFER)
|
|
{
|
|
return((DWORD)-1);
|
|
}
|
|
else
|
|
{
|
|
GlobalFree(lpInfo);
|
|
lpInfo = NULL;
|
|
dwSize = dwNeeded;
|
|
}
|
|
} // if (!bRC)
|
|
else // EnumPrinters returned success
|
|
{
|
|
*lpvPrinterInfo = lpInfo; // Save pointer to PRINTER_INFO structure
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return((DWORD)-1);
|
|
}
|
|
}
|
|
return(dwPrinters);
|
|
} // End of function SPL_EnumPrinters
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FUNCTION: PrintDIB(HANDLE hDIB, HDC hDC, int x, int y, int dx, int dy)
|
|
//
|
|
// PURPOSE: Set the DIB bits to the printer DC.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
BOOL PrintDIB (HANDLE hDIB, HDC hDC, int xOrigin, int yOrigin, int xSize, int ySize, BOOL bStretch)
|
|
{
|
|
int iBits;
|
|
HCURSOR hCurSave;
|
|
LPBITMAPINFOHEADER lpDIB;
|
|
LPBITMAPINFOHEADER lpbi;
|
|
|
|
|
|
// Initailize variables
|
|
START_WAIT_CURSOR(hCurSave); // put up busy cursor
|
|
|
|
lpDIB = (LPBITMAPINFOHEADER)GlobalLock(hDIB);
|
|
|
|
// If size > BITMAPINFOHEADER header then
|
|
// need to convert to BITMAPINFOHEADER.
|
|
lpbi = lpDIB;
|
|
#ifdef OSR2
|
|
if (sizeof(BITMAPINFOHEADER) < lpDIB->biSize)
|
|
{
|
|
DWORD dwColorTableSize;
|
|
DWORD dwHeaderDataSize;
|
|
|
|
// Allocate Bitmapinfo memory.
|
|
dwHeaderDataSize = sizeof(BITMAPINFOHEADER) + (lpDIB->biCompression == BI_BITFIELDS ? 12 : 0);
|
|
dwColorTableSize = NumColorsInDIB(lpDIB) * sizeof(RGBQUAD);
|
|
lpbi = (LPBITMAPINFOHEADER) GlobalAlloc(GPTR, dwHeaderDataSize + dwColorTableSize);
|
|
if (NULL == lpbi)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// Convert header data into bitmapinfo header.
|
|
memcpy(lpbi, lpDIB, dwHeaderDataSize);
|
|
lpbi->biSize = sizeof(BITMAPINFOHEADER);
|
|
|
|
// Copy color table if any.
|
|
if (0 != dwColorTableSize)
|
|
memcpy((LPBYTE)lpbi + dwHeaderDataSize, (LPBYTE)lpDIB + lpDIB->biSize, dwColorTableSize);
|
|
}
|
|
#endif
|
|
|
|
if (bStretch)
|
|
{
|
|
iBits = StretchDIBits(hDC,
|
|
xOrigin, yOrigin,
|
|
xSize, ySize,
|
|
0, 0,
|
|
BITMAPWIDTH(lpbi), abs(BITMAPHEIGHT(lpbi)),
|
|
FindDIBBits(lpDIB),
|
|
(LPBITMAPINFO)lpbi,
|
|
DIB_RGB_COLORS,
|
|
SRCCOPY);
|
|
}
|
|
else
|
|
{
|
|
iBits = SetDIBitsToDevice (hDC, // hDC
|
|
xOrigin, // DestX
|
|
yOrigin, // DestY
|
|
BITMAPWIDTH(lpbi), // nDestWidth
|
|
abs(BITMAPHEIGHT(lpbi)), // nDestHeight
|
|
0, // SrcX
|
|
0, // SrcY
|
|
0, // nStartScan
|
|
abs(BITMAPHEIGHT(lpbi)), // nNumScans
|
|
FindDIBBits(lpDIB),
|
|
(LPBITMAPINFO) lpbi, // lpBitsInfo
|
|
DIB_RGB_COLORS); // wUsage
|
|
}
|
|
END_WAIT_CURSOR(hCurSave); // restore cursor
|
|
if (lpbi != lpDIB)
|
|
{
|
|
GlobalFree((HANDLE)lpbi);
|
|
}
|
|
GlobalUnlock(hDIB);
|
|
return((iBits != 0) && (iBits != GDI_ERROR));
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Function: PrintImage
|
|
//
|
|
// Description:
|
|
// Prints the image to the printer specified within the DIBINFO structure.
|
|
//
|
|
// Parameters:
|
|
// @@@
|
|
//
|
|
// Returns:
|
|
// BOOL
|
|
//
|
|
// Comments:
|
|
//
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////
|
|
BOOL PrintImage(HWND hWnd)
|
|
{
|
|
// Local variables
|
|
LPBITMAPINFOHEADER lpBi;
|
|
int xSize, ySize, xRes, yRes, dx, dy;
|
|
LPDIBINFO lpDIBInfo;
|
|
HDC hDC;
|
|
HANDLE hDIB;
|
|
int iICMMode, iPrevICMMode;
|
|
int iXOrigin, iYOrigin;
|
|
BOOL bRC; // general return code
|
|
BOOL bStretch; // TRUE if to use StretchDIBits,
|
|
// FALSE if to use SetDIBitsToDevice
|
|
TCHAR stPrintMsg[MAX_PATH*2];
|
|
HANDLE hDIBPrinter;
|
|
DWORD dwLCSIntent;
|
|
|
|
|
|
// Initialize variables
|
|
hDIBPrinter = NULL;
|
|
lpDIBInfo = GetDIBInfoPtr(hWnd);
|
|
if (NULL == lpDIBInfo)
|
|
{
|
|
SetLastError(ERROR_INVALID_DATA);;
|
|
return(FALSE);
|
|
}
|
|
hDIB = lpDIBInfo->hDIB;
|
|
if (!ConvertIntent(lpDIBInfo->dwRenderIntent, ICC_TO_LCS, &dwLCSIntent))
|
|
{
|
|
ErrMsg(hWnd, __TEXT("Invalid Intent. Aborting Print process"));
|
|
}
|
|
|
|
|
|
if (CHECK_DWFLAG(lpDIBInfo->dwICMFlags, ICMVFLAGS_ICM20)
|
|
&& (CHECK_DWFLAG(lpDIBInfo->dwICMFlags, ICMVFLAGS_ENABLE_ICM)))
|
|
{
|
|
// ICM On, using outside DC, a.k.a. ICM20
|
|
DebugMsg(__TEXT("PrintImage: Outside DC, ICM Enabled\r\n"));
|
|
|
|
// Create transform of the original bits to the printer
|
|
ASSERT(NULL != lpDIBInfo->lpszPrinterProfile);
|
|
hDIBPrinter = TransformDIBOutsideDC(lpDIBInfo->hDIB,
|
|
lpDIBInfo->bmFormat,
|
|
lpDIBInfo->lpszPrinterProfile,
|
|
NULL,
|
|
USE_BITMAP_INTENT, NULL, 0);
|
|
if (NULL == hDIBPrinter)
|
|
{
|
|
ErrMsg(hWnd, __TEXT("PrintImage: Unable to transform DIB"));
|
|
return(FALSE);
|
|
}
|
|
else // Transform worked
|
|
{
|
|
hDIB = hDIBPrinter;
|
|
}
|
|
}
|
|
ASSERT(NULL != hDIB);
|
|
lpBi = GlobalLock(hDIB);
|
|
|
|
// Initialize printing
|
|
hDC = InitPrinting(hWnd, lpDIBInfo->lpszPrinterName, lpDIBInfo->pDevMode);
|
|
if (NULL != hDC)
|
|
{
|
|
// Get addresses of dialog procs
|
|
glpfnPrintDlgProc = (FARPROC)&PrintDlgProc;
|
|
glpfnAbortProc = (FARPROC)&AbortProc;
|
|
|
|
// Create the printing dialog
|
|
ghDlgPrint = CreateDialog(ghInst, MAKEINTRESOURCE(IDD_PRINTING), ghWndParent, (DLGPROC)glpfnPrintDlgProc);
|
|
|
|
EnableWindow( ghWndParent, FALSE); // Disable Parent
|
|
CenterWindow(ghDlgPrint, ghWndParent);
|
|
wsprintf(stPrintMsg, __TEXT("Printing image\r\n\r\n%s\r\n\r\nto\r\n\r\n%s"), lpDIBInfo->lpszImageFileName, lpDIBInfo->lpszPrinterName);
|
|
SetWindowText(GetDlgItem(ghDlgPrint, IDC_PRINT_FILENAME), (LPTSTR)stPrintMsg);
|
|
ShowWindow(ghDlgPrint, SW_SHOW);
|
|
|
|
// Set the abort procedure
|
|
if (SetAbortProc(hDC, (ABORTPROC)glpfnAbortProc) == SP_ERROR)
|
|
{
|
|
ErrMsg(hWnd, __TEXT("InitPrinting: SetAbortProc FAILED, LastError = %ld"), GetLastError());
|
|
}
|
|
|
|
// Use the printable region of the printer to determine
|
|
// the margins.
|
|
iXOrigin = GetDeviceCaps(hDC, PHYSICALOFFSETX);
|
|
iYOrigin = GetDeviceCaps(hDC, PHYSICALOFFSETY);
|
|
|
|
// Obtain info about printer resolution
|
|
xSize = GetDeviceCaps(hDC, HORZRES);
|
|
ySize = GetDeviceCaps(hDC, VERTRES);
|
|
xRes = GetDeviceCaps(hDC, LOGPIXELSX);
|
|
yRes = GetDeviceCaps(hDC, LOGPIXELSY);
|
|
|
|
// Stretch to best fit, if necessary. Maintain the same aspect ratio.
|
|
if (CHECK_DWFLAG(lpDIBInfo->dwPrintOption,ICMV_PRINT_BESTFIT))
|
|
{
|
|
bStretch = TRUE;
|
|
dy = ySize - (yRes/2);
|
|
dx = ((int)((long)dy * BITMAPWIDTH(lpBi)/abs(BITMAPHEIGHT(lpBi)) ));
|
|
|
|
// Make sure the image still fits.
|
|
if (dx > xSize)
|
|
{
|
|
dx = xSize - xRes/2;
|
|
dy = ((int)((long)dx * abs(BITMAPHEIGHT(lpBi))/BITMAPWIDTH(lpBi)));
|
|
}
|
|
}
|
|
else // Actual size
|
|
{
|
|
bStretch = FALSE;
|
|
dx = BITMAPWIDTH(lpBi);
|
|
dy = abs(BITMAPHEIGHT(lpBi));
|
|
}
|
|
|
|
// Set ICM mode according to properties set in ICMINFO structure
|
|
iICMMode = ICM_OFF;
|
|
if (CHECK_DWFLAG(lpDIBInfo->dwICMFlags, ICMVFLAGS_ENABLE_ICM))
|
|
{
|
|
if (!CHECK_DWFLAG(lpDIBInfo->dwICMFlags, ICMVFLAGS_ICM20))
|
|
{
|
|
TCHAR stProfile[MAX_PATH];
|
|
|
|
|
|
// ICM enabled, using ICM10--inside DC
|
|
|
|
iICMMode = ICM_ON;
|
|
wsprintf(stProfile, __TEXT("%s\\%s"), gstProfilesDir, lpDIBInfo->lpszPrinterProfile);
|
|
bRC = SetICMProfile(hDC, (LPTSTR)stProfile);
|
|
DebugMsg(__TEXT("PrintImage: Inside DC using profile \"%s\".\r\n"), stProfile);
|
|
if (!bRC)
|
|
{
|
|
DebugMsg(__TEXT("Print.C, PrintImage: SetICMProfile() FAILED!!\r\n"));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
iICMMode = ICM_DONE_OUTSIDEDC;
|
|
}
|
|
}
|
|
iPrevICMMode = SetICMMode(hDC, iICMMode); // Explicitly set ICMMode--don't count on any behavior
|
|
if (0 == iPrevICMMode)
|
|
{
|
|
DebugMsg(__TEXT("PRINT.C : PrintImage : SetICMMode(%d) FAILED \r\n"), iICMMode);
|
|
}
|
|
PrintDIB(hDIB, hDC, iXOrigin, iYOrigin, dx, dy, bStretch);
|
|
|
|
// Terminate printing and delete the printer DC
|
|
TermPrinting(hDC);
|
|
DeleteDC(hDC);
|
|
}
|
|
|
|
// Delete DIB transform for printer if necessary
|
|
GlobalUnlock(hDIB);
|
|
if (NULL != hDIBPrinter)
|
|
{
|
|
GlobalFree(hDIBPrinter);
|
|
}
|
|
|
|
GlobalUnlock(GlobalHandle(lpDIBInfo));
|
|
|
|
return TRUE;
|
|
} // End of function PrintImage
|
|
|
|
|
|
// //////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FUNCTION: PrintDlgProc (hWnd, unsigned , WORD , DWORD )
|
|
//
|
|
// PURPOSE: Dialog function for the "Cancel Printing" dialog. It sets
|
|
// the abort flag if the user presses <Cancel>.
|
|
//
|
|
// //////////////////////////////////////////////////////////////////////////
|
|
BOOL FAR PASCAL PrintDlgProc (HWND hDlg, unsigned iMessage, WORD wParam, DWORD lParam)
|
|
{
|
|
|
|
lParam = lParam; // Eliminates 'unused formal parameter' warning
|
|
wParam = wParam; // Eliminates 'unused formal parameter' warning
|
|
|
|
switch (iMessage)
|
|
{
|
|
case WM_INITDIALOG:
|
|
EnableMenuItem (GetSystemMenu (hDlg, FALSE), SC_CLOSE, MF_GRAYED);
|
|
break;
|
|
|
|
case WM_COMMAND:
|
|
gbUserAbort = TRUE;
|
|
EnableWindow (ghWndParent, TRUE);
|
|
DestroyWindow (hDlg);
|
|
ghDlgPrint = 0;
|
|
break;
|
|
|
|
default:
|
|
return(FALSE);
|
|
}
|
|
return(TRUE);
|
|
}
|
|
|
|
// //////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FUNCTION: AbortProc (HDC hPrnDC, short nCode)
|
|
//
|
|
// PURPOSE: Checks message queue for messages from the "Cancel Printing"
|
|
// dialog. If it sees a message, (this will be from a print
|
|
// cancel command), it terminates.
|
|
//
|
|
// RETURNS: Inverse of Abort flag
|
|
//
|
|
// //////////////////////////////////////////////////////////////////////////
|
|
BOOL FAR PASCAL AbortProc (HDC hPrnDC, short nCode)
|
|
{
|
|
MSG msg;
|
|
|
|
nCode = nCode; // Eliminates 'unused formal paramater' warning
|
|
hPrnDC = hPrnDC; // Eliminates 'unused formal paramater' warning
|
|
while (!gbUserAbort && PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
|
|
{
|
|
if (!ghDlgPrint || !IsDialogMessage(ghDlgPrint, &msg))
|
|
{
|
|
TranslateMessage (&msg);
|
|
DispatchMessage (&msg);
|
|
}
|
|
}
|
|
return(!gbUserAbort);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Function: InitPrinting
|
|
//
|
|
// Description:
|
|
// Sets up print job.
|
|
//
|
|
// Parameters:
|
|
// @@@
|
|
//
|
|
// Returns:
|
|
// HDC PASCAL
|
|
//
|
|
// Comments:
|
|
//
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////
|
|
static HDC PASCAL InitPrinting(HWND hWnd, LPTSTR lpszFriendlyName, PDEVMODE pDevMode)
|
|
{
|
|
// Local variables
|
|
HDC hDC;
|
|
DOCINFO diDocInfo; // Document infor for StartDoc call
|
|
BOOL bRetVal;
|
|
|
|
// Initialize variables
|
|
hDC = NULL;
|
|
bRetVal = TRUE;
|
|
gbUserAbort = FALSE;
|
|
ghWndParent = hWnd;
|
|
SetLastError(0);
|
|
|
|
hDC = GetPrinterDC(lpszFriendlyName, pDevMode);
|
|
if (hDC == NULL)
|
|
{
|
|
DebugMsg(__TEXT("InitPrinting : GetPrinterDC returned NULL\r\n"));
|
|
return(NULL);
|
|
}
|
|
|
|
// Fill in the DOCINFO structure
|
|
diDocInfo.cbSize = sizeof(DOCINFO);
|
|
diDocInfo.lpszDocName = lpszFriendlyName;
|
|
diDocInfo.lpszOutput = NULL;
|
|
diDocInfo.lpszDatatype = NULL;
|
|
diDocInfo.fwType = 0;
|
|
|
|
// Start the document
|
|
if (StartDoc(hDC, &diDocInfo)== SP_ERROR)
|
|
{
|
|
ErrMsg(hWnd, __TEXT("InitPrinting: StartDoc FAILED"));
|
|
bRetVal = FALSE;
|
|
goto exit;
|
|
}
|
|
|
|
// Start the page
|
|
if (StartPage(hDC) == SP_ERROR)
|
|
{
|
|
DISPLAY_LASTERROR(LASTERROR_NOALLOC,GetLastError());
|
|
ErrMsg(hWnd, __TEXT("InitPrinting: StartPage FAILED"));
|
|
AbortDoc(hDC);
|
|
bRetVal = FALSE;
|
|
}
|
|
|
|
exit:
|
|
if (bRetVal == FALSE)
|
|
{
|
|
EnableWindow( ghWndParent, TRUE);
|
|
DestroyWindow(ghDlgPrint);
|
|
}
|
|
return(hDC);
|
|
} // End of function InitPrinting
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Function: TermPrinting
|
|
//
|
|
// Description:
|
|
// Terminates the print job.
|
|
//
|
|
// Parameters:
|
|
// @@@
|
|
//
|
|
// Returns:
|
|
// void PASCAL
|
|
//
|
|
// Comments:
|
|
//
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////
|
|
static void PASCAL TermPrinting(HDC hDC)
|
|
{
|
|
// Local variables
|
|
if (EndPage(hDC) == SP_ERROR)
|
|
{
|
|
ErrMsg(NULL, __TEXT("TermPrinting: EndPage FAILED"));
|
|
}
|
|
if (EndDoc(hDC) == SP_ERROR)
|
|
{
|
|
ErrMsg(NULL, __TEXT("TermPrinting: EndDoc FAILED"));
|
|
}
|
|
|
|
// Dstroy the dialog
|
|
EnableWindow(ghWndParent, TRUE);
|
|
DestroyWindow(ghDlgPrint);
|
|
} // End of function TermPrinting
|
|
|
|
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Function: GetDefaultPrinterDC
|
|
//
|
|
// Description:
|
|
// Returns a DC for the default printer.
|
|
//
|
|
// Parameters:
|
|
// @@@
|
|
//
|
|
// Returns:
|
|
// HDC
|
|
//
|
|
// Comments:
|
|
//
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////
|
|
HDC GetDefaultPrinterDC()
|
|
{
|
|
HDC hDC;
|
|
LPTSTR lpszPrinterName;
|
|
|
|
|
|
// Initialize variables
|
|
hDC = NULL;
|
|
|
|
lpszPrinterName = GetDefaultPrinterName();
|
|
if (lpszPrinterName != NULL)
|
|
{
|
|
hDC = GetPrinterDC(lpszPrinterName, NULL);
|
|
GlobalFree(lpszPrinterName);
|
|
}
|
|
else
|
|
{
|
|
DebugMsg(__TEXT("GetDefaultPrinterDC: Could not obtain default printer name.\r\n"));
|
|
}
|
|
|
|
return hDC;
|
|
} // End of function GetDefaultPrinterDC
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Function: GetDefaultPrinterDevMode
|
|
//
|
|
// Description:
|
|
// Returns a printer's default devmode.
|
|
//
|
|
// Parameters:
|
|
// @@@
|
|
//
|
|
// Returns:
|
|
// PDEVMODE
|
|
//
|
|
// Comments:
|
|
//
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////
|
|
PDEVMODE GetDefaultPrinterDevMode(LPTSTR lpszPrinterName)
|
|
{
|
|
LONG lDevModeSize;
|
|
HANDLE hDevMode;
|
|
PDEVMODE pDevMode = NULL;
|
|
|
|
|
|
lDevModeSize = DocumentProperties(NULL, NULL, lpszPrinterName, NULL, NULL, 0);
|
|
if (lDevModeSize > 0)
|
|
{
|
|
hDevMode = GlobalAlloc(GHND, lDevModeSize);
|
|
pDevMode = (PDEVMODE) GlobalLock(hDevMode);
|
|
DocumentProperties(NULL, NULL, lpszPrinterName, pDevMode, NULL, DM_OUT_BUFFER);
|
|
}
|
|
else
|
|
{
|
|
DebugMsg(__TEXT("GetDefaultPrinterDevMode: Could not obtain printer's devmode.\r\n"));
|
|
}
|
|
|
|
return pDevMode;
|
|
}
|
|
|
|
|
|
|