/* * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ #include "awt_Component.h" #include "awt_PrintControl.h" #include "awt.h" #include "awt_PrintDialog.h" #include #include #include #define ROUNDTOINT(x) ((int)((x)+0.5)) static const int DEFAULT_RES = 72; static const double TENTHS_MM_TO_POINTS = 3.527777778; static const double LOMETRIC_TO_POINTS = (72.0 / 254.0); /* Values must match those defined in WPrinterJob.java */ static const DWORD SET_COLOR = 0x00000200; static const DWORD SET_ORIENTATION = 0x00004000; static const DWORD SET_DUP_VERTICAL = 0x00000010; static const DWORD SET_DUP_HORIZONTAL = 0x00000020; static const DWORD SET_RES_HIGH = 0x00000040; static const DWORD SET_RES_LOW = 0x00000080; /* These methods and fields are on sun.awt.windows.WPrinterJob */ jfieldID AwtPrintControl::dialogOwnerPeerID; jmethodID AwtPrintControl::getPrintDCID; jmethodID AwtPrintControl::setPrintDCID; jmethodID AwtPrintControl::getDevmodeID; jmethodID AwtPrintControl::setDevmodeID; jmethodID AwtPrintControl::getDevnamesID; jmethodID AwtPrintControl::setDevnamesID; jmethodID AwtPrintControl::getParentWindowID; jfieldID AwtPrintControl::driverDoesMultipleCopiesID; jfieldID AwtPrintControl::driverDoesCollationID; jmethodID AwtPrintControl::getWin32MediaID; jmethodID AwtPrintControl::setWin32MediaID; jmethodID AwtPrintControl::getWin32MediaTrayID; jmethodID AwtPrintControl::setWin32MediaTrayID; jmethodID AwtPrintControl::getColorID; jmethodID AwtPrintControl::getCopiesID; jmethodID AwtPrintControl::getSelectID; jmethodID AwtPrintControl::getDestID; jmethodID AwtPrintControl::getDialogID; jmethodID AwtPrintControl::getFromPageID; jmethodID AwtPrintControl::getMaxPageID; jmethodID AwtPrintControl::getMinPageID; jmethodID AwtPrintControl::getCollateID; jmethodID AwtPrintControl::getOrientID; jmethodID AwtPrintControl::getQualityID; jmethodID AwtPrintControl::getPrintToFileEnabledID; jmethodID AwtPrintControl::getPrinterID; jmethodID AwtPrintControl::setPrinterID; jmethodID AwtPrintControl::getResID; jmethodID AwtPrintControl::getSidesID; jmethodID AwtPrintControl::getToPageID; jmethodID AwtPrintControl::setToPageID; jmethodID AwtPrintControl::setNativeAttID; jmethodID AwtPrintControl::setRangeCopiesID; jmethodID AwtPrintControl::setResID; jmethodID AwtPrintControl::setJobAttributesID; BOOL AwtPrintControl::IsSupportedLevel(HANDLE hPrinter, DWORD dwLevel) { BOOL isSupported = FALSE; DWORD cbBuf = 0; LPBYTE pPrinter = NULL; DASSERT(hPrinter != NULL); VERIFY(::GetPrinter(hPrinter, dwLevel, NULL, 0, &cbBuf) == 0); if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) { pPrinter = new BYTE[cbBuf]; if (::GetPrinter(hPrinter, dwLevel, pPrinter, cbBuf, &cbBuf)) { isSupported = TRUE; } delete[] pPrinter; } return isSupported; } BOOL AwtPrintControl::FindPrinter(jstring printerName, LPBYTE pPrinterEnum, LPDWORD pcbBuf, LPTSTR * foundPrinter, LPTSTR * foundPort) { JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); DWORD cReturned = 0; if (pPrinterEnum == NULL) { // Compute size of buffer DWORD cbNeeded = 0; ::EnumPrinters(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS, NULL, 2, NULL, 0, &cbNeeded, &cReturned); ::EnumPrinters(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, pcbBuf, &cReturned); if (cbNeeded > (*pcbBuf)) { *pcbBuf = cbNeeded; } return TRUE; } DASSERT(printerName != NULL); DWORD cbBuf = *pcbBuf, dummyWord = 0; JavaStringBuffer printerNameBuf(env, printerName); LPTSTR lpcPrinterName = (LPTSTR)printerNameBuf; DASSERT(lpcPrinterName != NULL); // For NT, first do a quick check of all remote and local printers. // This only allows us to search by name, though. PRINTER_INFO_4 // doesn't support port searches. So, if the user has specified the // printer name as "LPT1:" (even though this is actually a port // name), we won't find the printer here. if (!::EnumPrinters(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS, NULL, 4, pPrinterEnum, cbBuf, &dummyWord, &cReturned)) { return FALSE; } for (DWORD i = 0; i < cReturned; i++) { PRINTER_INFO_4 *info4 = (PRINTER_INFO_4 *) (pPrinterEnum + i * sizeof(PRINTER_INFO_4)); if (info4->pPrinterName != NULL && _tcsicmp(lpcPrinterName, info4->pPrinterName) == 0) { // Fix for BugTraq Id 4281380. // Get the port name since some drivers may require // this name to be passed to ::DeviceCapabilities(). HANDLE hPrinter = NULL; if (::OpenPrinter(info4->pPrinterName, &hPrinter, NULL)) { // Fix for BugTraq Id 4286812. // Some drivers don't support PRINTER_INFO_5. // In this case we try PRINTER_INFO_2, and if that // isn't supported as well return NULL port name. try { if (AwtPrintControl::IsSupportedLevel(hPrinter, 5)) { VERIFY(::GetPrinter(hPrinter, 5, pPrinterEnum, cbBuf, &dummyWord)); PRINTER_INFO_5 *info5 = (PRINTER_INFO_5 *)pPrinterEnum; *foundPrinter = info5->pPrinterName; // pPortName may specify multiple ports. We only want one. *foundPort = (info5->pPortName != NULL) ? _tcstok(info5->pPortName, TEXT(",")) : NULL; } else if (AwtPrintControl::IsSupportedLevel(hPrinter, 2)) { VERIFY(::GetPrinter(hPrinter, 2, pPrinterEnum, cbBuf, &dummyWord)); PRINTER_INFO_2 *info2 = (PRINTER_INFO_2 *)pPrinterEnum; *foundPrinter = info2->pPrinterName; // pPortName may specify multiple ports. We only want one. *foundPort = (info2->pPortName != NULL) ? _tcstok(info2->pPortName, TEXT(",")) : NULL; } else { *foundPrinter = info4->pPrinterName; // We failed to determine port name for the found printer. *foundPort = NULL; } } catch (std::bad_alloc&) { VERIFY(::ClosePrinter(hPrinter)); throw; } VERIFY(::ClosePrinter(hPrinter)); return TRUE; } return FALSE; } } // We still haven't found the printer, /* or we're using 95/98. */ // PRINTER_INFO_5 supports both printer name and port name, so // we'll test both. On NT, PRINTER_ENUM_LOCAL means just local // printers. This is what we want, because we already tested all // remote printer names above (and remote printer port names are // the same as remote printer names). On 95/98, PRINTER_ENUM_LOCAL // means both remote and local printers. This is also what we want // because we haven't tested any printers yet. if (!::EnumPrinters(PRINTER_ENUM_LOCAL, NULL, 5, pPrinterEnum, cbBuf, &dummyWord, &cReturned)) { return FALSE; } for (DWORD i = 0; i < cReturned; i++) { PRINTER_INFO_5 *info5 = (PRINTER_INFO_5 *) (pPrinterEnum + i * sizeof(PRINTER_INFO_5)); // pPortName can specify multiple ports. Test them one at // a time. if (info5->pPortName != NULL) { LPTSTR port = _tcstok(info5->pPortName, TEXT(",")); while (port != NULL) { if (_tcsicmp(lpcPrinterName, port) == 0) { *foundPrinter = info5->pPrinterName; *foundPort = port; return TRUE; } port = _tcstok(NULL, TEXT(",")); } } } return FALSE; } void AwtPrintControl::initIDs(JNIEnv *env, jclass cls) { TRY; jclass cls = env->FindClass("sun/awt/windows/WPrinterJob"); CHECK_NULL(cls); AwtPrintControl::dialogOwnerPeerID = env->GetFieldID(cls, "dialogOwnerPeer", "Ljava/awt/peer/ComponentPeer;"); DASSERT(AwtPrintControl::dialogOwnerPeerID != NULL); CHECK_NULL(AwtPrintControl::dialogOwnerPeerID); AwtPrintControl::getParentWindowID = env->GetMethodID(cls, "getParentWindowID", "()J"); DASSERT(AwtPrintControl::getParentWindowID != NULL); CHECK_NULL(AwtPrintControl::getParentWindowID); AwtPrintControl::getPrintDCID = env->GetMethodID(cls, "getPrintDC", "()J"); DASSERT(AwtPrintControl::getPrintDCID != NULL); CHECK_NULL(AwtPrintControl::getPrintDCID); AwtPrintControl::setPrintDCID = env->GetMethodID(cls, "setPrintDC", "(J)V"); DASSERT(AwtPrintControl::setPrintDCID != NULL); CHECK_NULL(AwtPrintControl::setPrintDCID); AwtPrintControl::getDevmodeID = env->GetMethodID(cls, "getDevMode", "()J"); DASSERT(AwtPrintControl::getDevmodeID != NULL); CHECK_NULL(AwtPrintControl::getDevmodeID); AwtPrintControl::setDevmodeID = env->GetMethodID(cls, "setDevMode", "(J)V"); DASSERT(AwtPrintControl::setDevmodeID != NULL); CHECK_NULL(AwtPrintControl::setDevmodeID); AwtPrintControl::getDevnamesID = env->GetMethodID(cls, "getDevNames", "()J"); DASSERT(AwtPrintControl::getDevnamesID != NULL); CHECK_NULL(AwtPrintControl::getDevnamesID); AwtPrintControl::setDevnamesID = env->GetMethodID(cls, "setDevNames", "(J)V"); DASSERT(AwtPrintControl::setDevnamesID != NULL); CHECK_NULL(AwtPrintControl::setDevnamesID); AwtPrintControl::driverDoesMultipleCopiesID = env->GetFieldID(cls, "driverDoesMultipleCopies", "Z"); DASSERT(AwtPrintControl::driverDoesMultipleCopiesID != NULL); CHECK_NULL(AwtPrintControl::driverDoesMultipleCopiesID); AwtPrintControl::driverDoesCollationID = env->GetFieldID(cls, "driverDoesCollation", "Z"); DASSERT(AwtPrintControl::driverDoesCollationID != NULL); CHECK_NULL(AwtPrintControl::driverDoesCollationID); AwtPrintControl::getCopiesID = env->GetMethodID(cls, "getCopiesAttrib", "()I"); DASSERT(AwtPrintControl::getCopiesID != NULL); CHECK_NULL(AwtPrintControl::getCopiesID); AwtPrintControl::getCollateID = env->GetMethodID(cls, "getCollateAttrib","()I"); DASSERT(AwtPrintControl::getCollateID != NULL); CHECK_NULL(AwtPrintControl::getCollateID); AwtPrintControl::getOrientID = env->GetMethodID(cls, "getOrientAttrib", "()I"); DASSERT(AwtPrintControl::getOrientID != NULL); CHECK_NULL(AwtPrintControl::getOrientID); AwtPrintControl::getFromPageID = env->GetMethodID(cls, "getFromPageAttrib", "()I"); DASSERT(AwtPrintControl::getFromPageID != NULL); CHECK_NULL(AwtPrintControl::getFromPageID); AwtPrintControl::getToPageID = env->GetMethodID(cls, "getToPageAttrib", "()I"); DASSERT(AwtPrintControl::getToPageID != NULL); CHECK_NULL(AwtPrintControl::getToPageID); AwtPrintControl::getMinPageID = env->GetMethodID(cls, "getMinPageAttrib", "()I"); DASSERT(AwtPrintControl::getMinPageID != NULL); CHECK_NULL(AwtPrintControl::getMinPageID); AwtPrintControl::getMaxPageID = env->GetMethodID(cls, "getMaxPageAttrib", "()I"); DASSERT(AwtPrintControl::getMaxPageID != NULL); CHECK_NULL(AwtPrintControl::getMaxPageID); AwtPrintControl::getDestID = env->GetMethodID(cls, "getDestAttrib", "()Z"); DASSERT(AwtPrintControl::getDestID != NULL); CHECK_NULL(AwtPrintControl::getDestID); AwtPrintControl::getQualityID = env->GetMethodID(cls, "getQualityAttrib", "()I"); DASSERT(AwtPrintControl::getQualityID != NULL); CHECK_NULL(AwtPrintControl::getQualityID); AwtPrintControl::getColorID = env->GetMethodID(cls, "getColorAttrib", "()I"); DASSERT(AwtPrintControl::getColorID != NULL); CHECK_NULL(AwtPrintControl::getColorID); AwtPrintControl::getSidesID = env->GetMethodID(cls, "getSidesAttrib", "()I"); DASSERT(AwtPrintControl::getSidesID != NULL); CHECK_NULL(AwtPrintControl::getSidesID); AwtPrintControl::getPrinterID = env->GetMethodID(cls, "getPrinterAttrib", "()Ljava/lang/String;"); DASSERT(AwtPrintControl::getPrinterID != NULL); CHECK_NULL(AwtPrintControl::getPrinterID); AwtPrintControl::getWin32MediaID = env->GetMethodID(cls, "getWin32MediaAttrib", "()[I"); DASSERT(AwtPrintControl::getWin32MediaID != NULL); CHECK_NULL(AwtPrintControl::getWin32MediaID); AwtPrintControl::setWin32MediaID = env->GetMethodID(cls, "setWin32MediaAttrib", "(III)V"); DASSERT(AwtPrintControl::setWin32MediaID != NULL); CHECK_NULL(AwtPrintControl::setWin32MediaID); AwtPrintControl::getWin32MediaTrayID = env->GetMethodID(cls, "getMediaTrayAttrib", "()I"); DASSERT(AwtPrintControl::getWin32MediaTrayID != NULL); CHECK_NULL(AwtPrintControl::getWin32MediaTrayID); AwtPrintControl::setWin32MediaTrayID = env->GetMethodID(cls, "setMediaTrayAttrib", "(I)V"); DASSERT(AwtPrintControl::setWin32MediaTrayID != NULL); CHECK_NULL(AwtPrintControl::setWin32MediaTrayID); AwtPrintControl::getSelectID = env->GetMethodID(cls, "getSelectAttrib", "()I"); DASSERT(AwtPrintControl::getSelectID != NULL); CHECK_NULL(AwtPrintControl::getSelectID); AwtPrintControl::getPrintToFileEnabledID = env->GetMethodID(cls, "getPrintToFileEnabled", "()Z"); DASSERT(AwtPrintControl::getPrintToFileEnabledID != NULL); CHECK_NULL(AwtPrintControl::getPrintToFileEnabledID); AwtPrintControl::setNativeAttID = env->GetMethodID(cls, "setNativeAttributes", "(III)V"); DASSERT(AwtPrintControl::setNativeAttID != NULL); CHECK_NULL(AwtPrintControl::setNativeAttID); AwtPrintControl::setRangeCopiesID = env->GetMethodID(cls, "setRangeCopiesAttribute", "(IIZI)V"); DASSERT(AwtPrintControl::setRangeCopiesID != NULL); CHECK_NULL(AwtPrintControl::setRangeCopiesID); AwtPrintControl::setResID = env->GetMethodID(cls, "setResolutionDPI", "(II)V"); DASSERT(AwtPrintControl::setResID != NULL); CHECK_NULL(AwtPrintControl::setResID); AwtPrintControl::setPrinterID = env->GetMethodID(cls, "setPrinterNameAttrib", "(Ljava/lang/String;)V"); DASSERT(AwtPrintControl::setPrinterID != NULL); CHECK_NULL(AwtPrintControl::setPrinterID); AwtPrintControl::setJobAttributesID = env->GetMethodID(cls, "setJobAttributes", "(Ljavax/print/attribute/PrintRequestAttributeSet;IISSSSSSS)V"); DASSERT(AwtPrintControl::setJobAttributesID != NULL); CHECK_NULL(AwtPrintControl::setJobAttributesID); CATCH_BAD_ALLOC; } BOOL CALLBACK PrintDlgHook(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam) { TRY; if (iMsg == WM_INITDIALOG) { SetForegroundWindow(hDlg); return FALSE; } return FALSE; CATCH_BAD_ALLOC_RET(TRUE); } BOOL AwtPrintControl::CreateDevModeAndDevNames(PRINTDLG *ppd, LPTSTR pPrinterName, LPTSTR pPortName) { DWORD cbNeeded = 0; LPBYTE pPrinter = NULL; BOOL retval = FALSE; HANDLE hPrinter; try { if (!::OpenPrinter(pPrinterName, &hPrinter, NULL)) { goto done; } VERIFY(::GetPrinter(hPrinter, 2, NULL, 0, &cbNeeded) == 0); if (::GetLastError() != ERROR_INSUFFICIENT_BUFFER) { goto done; } pPrinter = new BYTE[cbNeeded]; if (!::GetPrinter(hPrinter, 2, pPrinter, cbNeeded, &cbNeeded)) { goto done; } PRINTER_INFO_2 *info2 = (PRINTER_INFO_2 *)pPrinter; // Create DEVMODE, if it exists. if (info2->pDevMode != NULL) { size_t devmodeSize = sizeof(DEVMODE) + info2->pDevMode->dmDriverExtra; ppd->hDevMode = ::GlobalAlloc(GHND, devmodeSize); if (ppd->hDevMode == NULL) { throw std::bad_alloc(); } DEVMODE *devmode = (DEVMODE *)::GlobalLock(ppd->hDevMode); DASSERT(!::IsBadWritePtr(devmode, devmodeSize)); memcpy(devmode, info2->pDevMode, devmodeSize); VERIFY(::GlobalUnlock(ppd->hDevMode) == 0); DASSERT(::GetLastError() == NO_ERROR); } // Create DEVNAMES. if (pPortName != NULL) { info2->pPortName = pPortName; } else if (info2->pPortName != NULL) { // pPortName may specify multiple ports. We only want one. info2->pPortName = _tcstok(info2->pPortName, TEXT(",")); } size_t lenDriverName = ((info2->pDriverName != NULL) ? _tcslen(info2->pDriverName) : 0) + 1; size_t lenPrinterName = ((pPrinterName != NULL) ? _tcslen(pPrinterName) : 0) + 1; size_t lenOutputName = ((info2->pPortName != NULL) ? _tcslen(info2->pPortName) : 0) + 1; size_t devnameSize= sizeof(DEVNAMES) + lenDriverName*sizeof(TCHAR) + lenPrinterName*sizeof(TCHAR) + lenOutputName*sizeof(TCHAR); ppd->hDevNames = ::GlobalAlloc(GHND, devnameSize); if (ppd->hDevNames == NULL) { throw std::bad_alloc(); } DEVNAMES *devnames = (DEVNAMES *)::GlobalLock(ppd->hDevNames); DASSERT(!IsBadWritePtr(devnames, devnameSize)); LPTSTR lpcDevnames = (LPTSTR)devnames; // note: all sizes are in characters, not in bytes devnames->wDriverOffset = sizeof(DEVNAMES)/sizeof(TCHAR); devnames->wDeviceOffset = static_cast(sizeof(DEVNAMES)/sizeof(TCHAR) + lenDriverName); devnames->wOutputOffset = static_cast(sizeof(DEVNAMES)/sizeof(TCHAR) + lenDriverName + lenPrinterName); if (info2->pDriverName != NULL) { _tcscpy_s(lpcDevnames + devnames->wDriverOffset, devnameSize - devnames->wDriverOffset, info2->pDriverName); } else { *(lpcDevnames + devnames->wDriverOffset) = _T('\0'); } if (pPrinterName != NULL) { _tcscpy_s(lpcDevnames + devnames->wDeviceOffset, devnameSize - devnames->wDeviceOffset, pPrinterName); } else { *(lpcDevnames + devnames->wDeviceOffset) = _T('\0'); } if (info2->pPortName != NULL) { _tcscpy_s(lpcDevnames + devnames->wOutputOffset, devnameSize - devnames->wOutputOffset, info2->pPortName); } else { *(lpcDevnames + devnames->wOutputOffset) = _T('\0'); } VERIFY(::GlobalUnlock(ppd->hDevNames) == 0); DASSERT(::GetLastError() == NO_ERROR); } catch (std::bad_alloc&) { if (ppd->hDevNames != NULL) { VERIFY(::GlobalFree(ppd->hDevNames) == NULL); ppd->hDevNames = NULL; } if (ppd->hDevMode != NULL) { VERIFY(::GlobalFree(ppd->hDevMode) == NULL); ppd->hDevMode = NULL; } delete [] pPrinter; VERIFY(::ClosePrinter(hPrinter)); hPrinter = NULL; throw; } retval = TRUE; done: delete [] pPrinter; if (hPrinter) { VERIFY(::ClosePrinter(hPrinter)); hPrinter = NULL; } return retval; } WORD AwtPrintControl::getNearestMatchingPaper(LPTSTR printer, LPTSTR port, double origWid, double origHgt, double* newWid, double *newHgt) { const double epsilon = 0.50; const double tolerance = (1.0 * 72.0); // # inches * 72 int numPaperSizes = 0; WORD *papers = NULL; POINT *paperSizes = NULL; if ((printer== NULL) || (port == NULL)) { return 0; } SAVE_CONTROLWORD numPaperSizes = (int)DeviceCapabilities(printer, port, DC_PAPERSIZE, NULL, NULL); if (numPaperSizes > 0) { papers = (WORD*)SAFE_SIZE_ARRAY_ALLOC(safe_Malloc, sizeof(WORD), numPaperSizes); paperSizes = (POINT *)SAFE_SIZE_ARRAY_ALLOC(safe_Malloc, sizeof(*paperSizes), numPaperSizes); DWORD result1 = DeviceCapabilities(printer, port, DC_PAPERS, (LPTSTR) papers, NULL); DWORD result2 = DeviceCapabilities(printer, port, DC_PAPERSIZE, (LPTSTR) paperSizes, NULL); // REMIND: cache in papers and paperSizes if (result1 == -1 || result2 == -1 ) { free((LPTSTR) papers); papers = NULL; free((LPTSTR) paperSizes); paperSizes = NULL; } } RESTORE_CONTROLWORD double closestWid = 0.0; double closestHgt = 0.0; WORD closestMatch = 0; if (paperSizes != NULL) { /* Paper sizes are in 0.1mm units. Convert to 1/72" * For each paper size, compute the difference from the paper size * passed in. Use a least-squares difference, so paper much different * in x or y should score poorly */ double diffw = origWid; double diffh = origHgt; double least_square = diffw * diffw + diffh * diffh; double tmp_ls; double widpts, hgtpts; for (int i=0;i 0) { *newWid = closestWid; } if (closestHgt > 0) { *newHgt = closestHgt; } if (papers != NULL) { free((LPTSTR)papers); } if (paperSizes != NULL) { free((LPTSTR)paperSizes); } return closestMatch; } /* * Copy settings into a print dialog & any devmode */ BOOL AwtPrintControl::InitPrintDialog(JNIEnv *env, jobject printCtrl, PRINTDLG &pd) { HWND hwndOwner = NULL; jobject dialogOwner = env->GetObjectField(printCtrl, AwtPrintControl::dialogOwnerPeerID); if (dialogOwner != NULL) { AwtComponent *dialogOwnerComp = (AwtComponent *)JNI_GET_PDATA(dialogOwner); hwndOwner = dialogOwnerComp->GetHWnd(); env->DeleteLocalRef(dialogOwner); dialogOwner = NULL; } jobject mdh = NULL; jobject dest = NULL; jobject select = NULL; jobject dialog = NULL; LPTSTR printName = NULL; LPTSTR portName = NULL; // If the user didn't specify a printer, then this call returns the // name of the default printer. jstring printerName = (jstring) env->CallObjectMethod(printCtrl, AwtPrintControl::getPrinterID); if (printerName != NULL) { pd.hDevMode = AwtPrintControl::getPrintHDMode(env, printCtrl); pd.hDevNames = AwtPrintControl::getPrintHDName(env, printCtrl); LPTSTR getName = (LPTSTR)JNU_GetStringPlatformChars(env, printerName, NULL); if (getName == NULL) { env->DeleteLocalRef(printerName); throw std::bad_alloc(); } BOOL samePrinter = FALSE; // check if given printername is same as the currently saved printer if (pd.hDevNames != NULL ) { DEVNAMES *devnames = (DEVNAMES *)::GlobalLock(pd.hDevNames); if (devnames != NULL) { LPTSTR lpdevnames = (LPTSTR)devnames; printName = lpdevnames+devnames->wDeviceOffset; if (!_tcscmp(printName, getName)) { samePrinter = TRUE; printName = _tcsdup(lpdevnames+devnames->wDeviceOffset); portName = _tcsdup(lpdevnames+devnames->wOutputOffset); } } ::GlobalUnlock(pd.hDevNames); } if (!samePrinter) { LPTSTR foundPrinter = NULL; LPTSTR foundPort = NULL; DWORD cbBuf = 0; VERIFY(AwtPrintControl::FindPrinter(NULL, NULL, &cbBuf, NULL, NULL)); LPBYTE buffer = new BYTE[cbBuf]; if (AwtPrintControl::FindPrinter(printerName, buffer, &cbBuf, &foundPrinter, &foundPort) && (foundPrinter != NULL) && (foundPort != NULL)) { printName = _tcsdup(foundPrinter); portName = _tcsdup(foundPort); if (!AwtPrintControl::CreateDevModeAndDevNames(&pd, foundPrinter, foundPort)) { delete [] buffer; if (printName != NULL) { free(printName); } if (portName != NULL) { free(portName); } env->DeleteLocalRef(printerName); return FALSE; } DASSERT(pd.hDevNames != NULL); } else { delete [] buffer; if (printName != NULL) { free(printName); } if (portName != NULL) { free(portName); } env->DeleteLocalRef(printerName); return FALSE; } delete [] buffer; } env->DeleteLocalRef(printerName); // PrintDlg may change the values of hDevMode and hDevNames so we // re-initialize our saved handles. AwtPrintControl::setPrintHDMode(env, printCtrl, NULL); AwtPrintControl::setPrintHDName(env, printCtrl, NULL); } else { // There is no default printer. This means that there are no // printers installed at all. if (printName != NULL) { free(printName); } if (portName != NULL) { free(portName); } // Returning TRUE means try to display the native print dialog // which will either display an error message or prompt the // user to install a printer. return TRUE; } // Now, set-up the struct for the real calls to ::PrintDlg and ::CreateDC pd.hwndOwner = hwndOwner; pd.Flags = PD_ENABLEPRINTHOOK | PD_RETURNDC | PD_USEDEVMODECOPIESANDCOLLATE; pd.lpfnPrintHook = (LPPRINTHOOKPROC)PrintDlgHook; pd.nFromPage = (WORD)env->CallIntMethod(printCtrl, AwtPrintControl::getFromPageID); pd.nToPage = (WORD)env->CallIntMethod(printCtrl, AwtPrintControl::getToPageID); pd.nMinPage = (WORD)env->CallIntMethod(printCtrl, AwtPrintControl::getMinPageID); jint maxPage = env->CallIntMethod(printCtrl, AwtPrintControl::getMaxPageID); jint selectType = env->CallIntMethod(printCtrl, AwtPrintControl::getSelectID); pd.nMaxPage = (maxPage <= (jint)((WORD)-1)) ? (WORD)maxPage : (WORD)-1; // In the event that the application displays the dialog before // installing a Printable, but sets a page range, then max page will be 1 // since the default state of a PrinterJob is an empty "Book" Pageable. // Windows pops up an error dialog in such a case which isn't very // forthcoming about the exact problem. // So if we detect this fix up such a problem here. if (pd.nMinPage > pd.nFromPage) pd.nMinPage = pd.nFromPage; if (pd.nMaxPage < pd.nToPage) pd.nMaxPage = pd.nToPage; if (selectType != 0 && (pd.nFromPage > pd.nMinPage || pd.nToPage < pd.nMaxPage)) { if (selectType == PD_SELECTION) { pd.Flags |= PD_SELECTION; } else { pd.Flags |= PD_PAGENUMS; } } if (env->CallBooleanMethod(printCtrl, AwtPrintControl::getDestID)) { pd.Flags |= PD_PRINTTOFILE; } // selectType identifies whether No selection (2D) or // SunPageSelection (AWT) if (selectType != 0) { pd.Flags |= selectType; } if (!env->CallBooleanMethod(printCtrl, AwtPrintControl::getPrintToFileEnabledID)) { pd.Flags |= PD_DISABLEPRINTTOFILE; } if (pd.hDevMode != NULL) { DEVMODE *devmode = (DEVMODE *)::GlobalLock(pd.hDevMode); DASSERT(!IsBadWritePtr(devmode, sizeof(DEVMODE))); WORD copies = (WORD)env->CallIntMethod(printCtrl, AwtPrintControl::getCopiesID); if (copies > 0) { devmode->dmFields |= DM_COPIES; devmode->dmCopies = copies; } jint orient = env->CallIntMethod(printCtrl, AwtPrintControl::getOrientID); if (orient == 0) { // PageFormat.LANDSCAPE == 0 devmode->dmFields |= DM_ORIENTATION; devmode->dmOrientation = DMORIENT_LANDSCAPE; } else if (orient == 1) { // PageFormat.PORTRAIT == 1 devmode->dmFields |= DM_ORIENTATION; devmode->dmOrientation = DMORIENT_PORTRAIT; } // -1 means unset, so we'll accept the printer default. int collate = env->CallIntMethod(printCtrl, AwtPrintControl::getCollateID); if (collate == 1) { devmode->dmFields |= DM_COLLATE; devmode->dmCollate = DMCOLLATE_TRUE; } else if (collate == 0) { devmode->dmFields |= DM_COLLATE; devmode->dmCollate = DMCOLLATE_FALSE; } int quality = env->CallIntMethod(printCtrl, AwtPrintControl::getQualityID); if (quality) { devmode->dmFields |= DM_PRINTQUALITY; devmode->dmPrintQuality = quality; } int color = env->CallIntMethod(printCtrl, AwtPrintControl::getColorID); if (color) { devmode->dmFields |= DM_COLOR; devmode->dmColor = color; } int sides = env->CallIntMethod(printCtrl, AwtPrintControl::getSidesID); if (sides) { devmode->dmFields |= DM_DUPLEX; devmode->dmDuplex = (int)sides; } jintArray obj = (jintArray)env->CallObjectMethod(printCtrl, AwtPrintControl::getWin32MediaID); jboolean isCopy; jint *wid_ht = env->GetIntArrayElements(obj, &isCopy); double newWid = 0.0, newHt = 0.0; if (wid_ht != NULL && wid_ht[0] != 0 && wid_ht[1] != 0) { devmode->dmFields |= DM_PAPERSIZE; devmode->dmPaperSize = AwtPrintControl::getNearestMatchingPaper( printName, portName, (double)wid_ht[0], (double)wid_ht[1], &newWid, &newHt); } env->ReleaseIntArrayElements(obj, wid_ht, 0); ::GlobalUnlock(pd.hDevMode); devmode = NULL; } if (printName != NULL) { free(printName); } if (portName != NULL) { free(portName); } return TRUE; } /* * Copy settings from print dialog & any devmode back into attributes * or properties. */ extern "C" { extern void setCapabilities(JNIEnv *env, jobject WPrinterJob, HDC hdc); } BOOL AwtPrintControl::UpdateAttributes(JNIEnv *env, jobject printCtrl, PRINTDLG &pd) { DEVNAMES *devnames = NULL; DEVMODE *devmode = NULL; unsigned int copies = 1; DWORD pdFlags = pd.Flags; DWORD dmFields = 0, dmValues = 0; bool newDC = false; // This call ensures that default PrintService gets updated for the // case where initially, there weren't any printers. env->CallObjectMethod(printCtrl, AwtPrintControl::getPrinterID); if (pd.hDevMode != NULL) { devmode = (DEVMODE *)::GlobalLock(pd.hDevMode); DASSERT(!IsBadReadPtr(devmode, sizeof(DEVMODE))); } if (devmode != NULL) { /* Query the settings we understand and are interested in. * For the flags that are set in dmFields, where the values * are a simple enumeration, set the same bits in a clean dmFields * variable, and set bits in a dmValues variable to indicate the * selected value. These can all be passed up to Java in one * call to sync up the Java view of this. */ if (devmode->dmFields & DM_COPIES) { dmFields |= DM_COPIES; copies = devmode->dmCopies; if (pd.nCopies == 1) { env->SetBooleanField(printCtrl, driverDoesMultipleCopiesID, JNI_TRUE); } else { copies = pd.nCopies; } } if (devmode->dmFields & DM_PAPERSIZE) { env->CallVoidMethod(printCtrl, AwtPrintControl::setWin32MediaID, devmode->dmPaperSize, devmode->dmPaperWidth, devmode->dmPaperLength); } if (devmode->dmFields & DM_DEFAULTSOURCE) { env->CallVoidMethod(printCtrl, AwtPrintControl::setWin32MediaTrayID, devmode->dmDefaultSource); } if (devmode->dmFields & DM_COLOR) { dmFields |= DM_COLOR; if (devmode->dmColor == DMCOLOR_COLOR) { dmValues |= SET_COLOR; } } if (devmode->dmFields & DM_ORIENTATION) { dmFields |= DM_ORIENTATION; if (devmode->dmOrientation == DMORIENT_LANDSCAPE) { dmValues |= SET_ORIENTATION; } } if (devmode->dmFields & DM_COLLATE) { dmFields |= DM_COLLATE; if (devmode->dmCollate == DMCOLLATE_TRUE) { pdFlags |= PD_COLLATE; env->SetBooleanField(printCtrl, driverDoesCollationID, JNI_TRUE); } else { pdFlags &= ~PD_COLLATE; } } if (devmode->dmFields & DM_PRINTQUALITY) { /* value < 0 indicates quality setting. * value > 0 indicates X resolution. In that case * hopefully we will also find y-resolution specified. * If its not, assume its the same as x-res. * Maybe Java code should try to reconcile this against * the printers claimed set of supported resolutions. */ if (devmode->dmPrintQuality < 0) { if (dmFields |= DM_PRINTQUALITY) { if (devmode->dmPrintQuality == DMRES_HIGH) { dmValues |= SET_RES_HIGH; } else if ((devmode->dmPrintQuality == DMRES_LOW) || (devmode->dmPrintQuality == DMRES_DRAFT)) { dmValues |= SET_RES_LOW; } else if (devmode->dmPrintQuality == DMRES_MEDIUM) { /* default */ } } } else { int xRes = devmode->dmPrintQuality; /* For some printers, printer quality can specify 1200IQ * In this case, dmPrintQuality comes out 600 and * dmYResolution comes out 2, similarly for 2400IQ * dmPrintQuality comes out 600 and dmYResolution comes out 4 * which is not a valid resolution * so for IQ setting, we modify y-resolution only when it is * greater than 10. */ int yRes = (devmode->dmFields & DM_YRESOLUTION) && (devmode->dmYResolution > 10) ? devmode->dmYResolution : devmode->dmPrintQuality; env->CallVoidMethod(printCtrl, AwtPrintControl::setResID, xRes, yRes); } } if (devmode->dmFields & DM_DUPLEX) { dmFields |= DM_DUPLEX; if (devmode->dmDuplex == DMDUP_HORIZONTAL) { dmValues |= SET_DUP_HORIZONTAL; } else if (devmode->dmDuplex == DMDUP_VERTICAL) { dmValues |= SET_DUP_VERTICAL; } } ::GlobalUnlock(pd.hDevMode); devmode = NULL; } else { copies = pd.nCopies; } if (pd.hDevNames != NULL) { DEVNAMES *devnames = (DEVNAMES*)::GlobalLock(pd.hDevNames); DASSERT(!IsBadReadPtr(devnames, sizeof(DEVNAMES))); LPTSTR lpcNames = (LPTSTR)devnames; LPTSTR pbuf = (_tcslen(lpcNames + devnames->wDeviceOffset) == 0 ? TEXT("") : lpcNames + devnames->wDeviceOffset); if (pbuf != NULL) { jstring jstr = JNU_NewStringPlatform(env, pbuf); env->CallVoidMethod(printCtrl, AwtPrintControl::setPrinterID, jstr); env->DeleteLocalRef(jstr); } pbuf = (_tcslen(lpcNames + devnames->wOutputOffset) == 0 ? TEXT("") : lpcNames + devnames->wOutputOffset); if (pbuf != NULL) { if (wcscmp(pbuf, L"FILE:") == 0) { pdFlags |= PD_PRINTTOFILE; } } ::GlobalUnlock(pd.hDevNames); devnames = NULL; } env->CallVoidMethod(printCtrl, AwtPrintControl::setNativeAttID, pdFlags, dmFields, dmValues); // copies & range are always set so no need to check for any flags env->CallVoidMethod(printCtrl, AwtPrintControl::setRangeCopiesID, pd.nFromPage, pd.nToPage, (pdFlags & PD_PAGENUMS), copies); // repeated calls to printDialog should not leak handles HDC oldDC = AwtPrintControl::getPrintDC(env, printCtrl); if (pd.hDC != oldDC) { if (oldDC != NULL) { ::DeleteDC(oldDC); } AwtPrintControl::setPrintDC(env, printCtrl, pd.hDC); newDC = true; } // Need to update WPrinterJob with device resolution settings for // new or changed DC. setCapabilities(env, printCtrl, pd.hDC); HGLOBAL oldG = AwtPrintControl::getPrintHDMode(env, printCtrl); if (pd.hDevMode != oldG) { AwtPrintControl::setPrintHDMode(env, printCtrl, pd.hDevMode); } oldG = AwtPrintControl::getPrintHDName(env, printCtrl); if (pd.hDevNames != oldG) { AwtPrintControl::setPrintHDName(env, printCtrl, pd.hDevNames); } return newDC; } BOOL AwtPrintControl::getDevmode( HANDLE hPrinter, LPTSTR printerName, LPDEVMODE *pDevMode) { if (hPrinter == NULL || printerName == NULL || pDevMode == NULL) { return FALSE; } SAVE_CONTROLWORD DWORD dwNeeded = ::DocumentProperties(NULL, hPrinter, printerName, NULL, NULL, 0); RESTORE_CONTROLWORD if (dwNeeded <= 0) { *pDevMode = NULL; return FALSE; } *pDevMode = (LPDEVMODE)GlobalAlloc(GPTR, dwNeeded); if (*pDevMode == NULL) { return FALSE; } DWORD dwRet = ::DocumentProperties(NULL, hPrinter, printerName, *pDevMode, NULL, DM_OUT_BUFFER); RESTORE_CONTROLWORD if (dwRet != IDOK) { /* if failure, cleanup and return failure */ GlobalFree(*pDevMode); *pDevMode = NULL; return FALSE; } return TRUE; }