1 /* 2 * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 #include "awt_Component.h" 27 #include "awt_PrintControl.h" 28 #include "awt.h" 29 #include "awt_PrintDialog.h" 30 #include <winspool.h> 31 #include <float.h> 32 #include <math.h> 33 34 #define ROUNDTOINT(x) ((int)((x)+0.5)) 35 static const int DEFAULT_RES = 72; 36 static const double TENTHS_MM_TO_POINTS = 3.527777778; 37 static const double LOMETRIC_TO_POINTS = (72.0 / 254.0); 38 39 40 /* Values must match those defined in WPrinterJob.java */ 41 static const DWORD SET_COLOR = 0x00000200; 42 static const DWORD SET_ORIENTATION = 0x00004000; 43 static const DWORD SET_DUP_VERTICAL = 0x00000010; 44 static const DWORD SET_DUP_HORIZONTAL = 0x00000020; 45 static const DWORD SET_RES_HIGH = 0x00000040; 46 static const DWORD SET_RES_LOW = 0x00000080; 47 48 49 /* These methods and fields are on sun.awt.windows.WPrinterJob */ 50 jfieldID AwtPrintControl::dialogOwnerPeerID; 51 jmethodID AwtPrintControl::getPrintDCID; 52 jmethodID AwtPrintControl::setPrintDCID; 53 jmethodID AwtPrintControl::getDevmodeID; 54 jmethodID AwtPrintControl::setDevmodeID; 55 jmethodID AwtPrintControl::getDevnamesID; 56 jmethodID AwtPrintControl::setDevnamesID; 57 jfieldID AwtPrintControl::driverDoesMultipleCopiesID; 58 jfieldID AwtPrintControl::driverDoesCollationID; 59 jmethodID AwtPrintControl::getWin32MediaID; 60 jmethodID AwtPrintControl::setWin32MediaID; 61 jmethodID AwtPrintControl::getWin32MediaTrayID; 62 jmethodID AwtPrintControl::setWin32MediaTrayID; 63 jmethodID AwtPrintControl::getColorID; 64 jmethodID AwtPrintControl::getCopiesID; 65 jmethodID AwtPrintControl::getSelectID; 66 jmethodID AwtPrintControl::getDestID; 67 jmethodID AwtPrintControl::getDialogID; 68 jmethodID AwtPrintControl::getFromPageID; 69 jmethodID AwtPrintControl::getMaxPageID; 70 jmethodID AwtPrintControl::getMinPageID; 71 jmethodID AwtPrintControl::getCollateID; 72 jmethodID AwtPrintControl::getOrientID; 73 jmethodID AwtPrintControl::getQualityID; 74 jmethodID AwtPrintControl::getPrintToFileEnabledID; 75 jmethodID AwtPrintControl::getPrinterID; 76 jmethodID AwtPrintControl::setPrinterID; 77 jmethodID AwtPrintControl::getResID; 78 jmethodID AwtPrintControl::getSidesID; 79 jmethodID AwtPrintControl::getToPageID; 80 jmethodID AwtPrintControl::setToPageID; 81 jmethodID AwtPrintControl::setNativeAttID; 82 jmethodID AwtPrintControl::setRangeCopiesID; 83 jmethodID AwtPrintControl::setResID; 84 jmethodID AwtPrintControl::setJobAttributesID; 85 86 87 BOOL AwtPrintControl::IsSupportedLevel(HANDLE hPrinter, DWORD dwLevel) { 88 BOOL isSupported = FALSE; 89 DWORD cbBuf = 0; 90 LPBYTE pPrinter = NULL; 91 92 DASSERT(hPrinter != NULL); 93 94 VERIFY(::GetPrinter(hPrinter, dwLevel, NULL, 0, &cbBuf) == 0); 95 if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) { 96 pPrinter = new BYTE[cbBuf]; 97 if (::GetPrinter(hPrinter, dwLevel, pPrinter, cbBuf, &cbBuf)) { 98 isSupported = TRUE; 99 } 100 delete[] pPrinter; 101 } 102 103 return isSupported; 104 } 105 106 BOOL AwtPrintControl::FindPrinter(jstring printerName, LPBYTE pPrinterEnum, 107 LPDWORD pcbBuf, LPTSTR * foundPrinter, 108 LPTSTR * foundPort) 109 { 110 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 111 112 DWORD cReturned = 0; 113 114 if (pPrinterEnum == NULL) { 115 // Compute size of buffer 116 DWORD cbNeeded = 0; 117 ::EnumPrinters(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS, 118 NULL, 2, NULL, 0, &cbNeeded, &cReturned); 119 ::EnumPrinters(PRINTER_ENUM_LOCAL, 120 NULL, 5, NULL, 0, pcbBuf, &cReturned); 121 if (cbNeeded > (*pcbBuf)) { 122 *pcbBuf = cbNeeded; 123 } 124 return TRUE; 125 } 126 127 DASSERT(printerName != NULL); 128 129 DWORD cbBuf = *pcbBuf, dummyWord = 0; 130 131 JavaStringBuffer printerNameBuf(env, printerName); 132 LPTSTR lpcPrinterName = (LPTSTR)printerNameBuf; 133 DASSERT(lpcPrinterName != NULL); 134 135 // For NT, first do a quick check of all remote and local printers. 136 // This only allows us to search by name, though. PRINTER_INFO_4 137 // doesn't support port searches. So, if the user has specified the 138 // printer name as "LPT1:" (even though this is actually a port 139 // name), we won't find the printer here. 140 if (!::EnumPrinters(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS, 141 NULL, 4, pPrinterEnum, cbBuf, &dummyWord, &cReturned)) { 142 return FALSE; 143 } 144 145 for (DWORD i = 0; i < cReturned; i++) { 146 PRINTER_INFO_4 *info4 = (PRINTER_INFO_4 *) 147 (pPrinterEnum + i * sizeof(PRINTER_INFO_4)); 148 if (info4->pPrinterName != NULL && 149 _tcsicmp(lpcPrinterName, info4->pPrinterName) == 0) { 150 151 // Fix for BugTraq Id 4281380. 152 // Get the port name since some drivers may require 153 // this name to be passed to ::DeviceCapabilities(). 154 HANDLE hPrinter = NULL; 155 if (::OpenPrinter(info4->pPrinterName, &hPrinter, NULL)) { 156 // Fix for BugTraq Id 4286812. 157 // Some drivers don't support PRINTER_INFO_5. 158 // In this case we try PRINTER_INFO_2, and if that 159 // isn't supported as well return NULL port name. 160 try { 161 if (AwtPrintControl::IsSupportedLevel(hPrinter, 5)) { 162 VERIFY(::GetPrinter(hPrinter, 5, pPrinterEnum, cbBuf, 163 &dummyWord)); 164 PRINTER_INFO_5 *info5 = (PRINTER_INFO_5 *)pPrinterEnum; 165 *foundPrinter = info5->pPrinterName; 166 // pPortName may specify multiple ports. We only want one. 167 *foundPort = (info5->pPortName != NULL) 168 ? _tcstok(info5->pPortName, TEXT(",")) : NULL; 169 } else if (AwtPrintControl::IsSupportedLevel(hPrinter, 2)) { 170 VERIFY(::GetPrinter(hPrinter, 2, pPrinterEnum, cbBuf, 171 &dummyWord)); 172 PRINTER_INFO_2 *info2 = (PRINTER_INFO_2 *)pPrinterEnum; 173 *foundPrinter = info2->pPrinterName; 174 // pPortName may specify multiple ports. We only want one. 175 *foundPort = (info2->pPortName != NULL) 176 ? _tcstok(info2->pPortName, TEXT(",")) : NULL; 177 } else { 178 *foundPrinter = info4->pPrinterName; 179 // We failed to determine port name for the found printer. 180 *foundPort = NULL; 181 } 182 } catch (std::bad_alloc&) { 183 VERIFY(::ClosePrinter(hPrinter)); 184 throw; 185 } 186 187 VERIFY(::ClosePrinter(hPrinter)); 188 189 return TRUE; 190 } 191 192 return FALSE; 193 } 194 } 195 196 // We still haven't found the printer, /* or we're using 95/98. */ 197 // PRINTER_INFO_5 supports both printer name and port name, so 198 // we'll test both. On NT, PRINTER_ENUM_LOCAL means just local 199 // printers. This is what we want, because we already tested all 200 // remote printer names above (and remote printer port names are 201 // the same as remote printer names). On 95/98, PRINTER_ENUM_LOCAL 202 // means both remote and local printers. This is also what we want 203 // because we haven't tested any printers yet. 204 if (!::EnumPrinters(PRINTER_ENUM_LOCAL, 205 NULL, 5, pPrinterEnum, cbBuf, &dummyWord, &cReturned)) { 206 return FALSE; 207 } 208 209 for (DWORD i = 0; i < cReturned; i++) { 210 PRINTER_INFO_5 *info5 = (PRINTER_INFO_5 *) 211 (pPrinterEnum + i * sizeof(PRINTER_INFO_5)); 212 // pPortName can specify multiple ports. Test them one at 213 // a time. 214 if (info5->pPortName != NULL) { 215 LPTSTR port = _tcstok(info5->pPortName, TEXT(",")); 216 while (port != NULL) { 217 if (_tcsicmp(lpcPrinterName, port) == 0) { 218 *foundPrinter = info5->pPrinterName; 219 *foundPort = port; 220 return TRUE; 221 } 222 port = _tcstok(NULL, TEXT(",")); 223 } 224 } 225 } 226 227 return FALSE; 228 } 229 230 231 void AwtPrintControl::initIDs(JNIEnv *env, jclass cls) 232 { 233 TRY; 234 235 jclass cls = env->FindClass("sun/awt/windows/WPrinterJob"); 236 CHECK_NULL(cls); 237 238 AwtPrintControl::dialogOwnerPeerID = 239 env->GetFieldID(cls, "dialogOwnerPeer", "Ljava/awt/peer/ComponentPeer;"); 240 DASSERT(AwtPrintControl::dialogOwnerPeerID != NULL); 241 CHECK_NULL(AwtPrintControl::dialogOwnerPeerID); 242 243 AwtPrintControl::getPrintDCID = env->GetMethodID(cls, "getPrintDC", "()J"); 244 DASSERT(AwtPrintControl::getPrintDCID != NULL); 245 CHECK_NULL(AwtPrintControl::getPrintDCID); 246 247 AwtPrintControl::setPrintDCID = 248 env->GetMethodID(cls, "setPrintDC", "(J)V"); 249 DASSERT(AwtPrintControl::setPrintDCID != NULL); 250 CHECK_NULL(AwtPrintControl::setPrintDCID); 251 252 AwtPrintControl::getDevmodeID = env->GetMethodID(cls, "getDevMode", "()J"); 253 DASSERT(AwtPrintControl::getDevmodeID != NULL); 254 CHECK_NULL(AwtPrintControl::getDevmodeID); 255 256 AwtPrintControl::setDevmodeID = 257 env->GetMethodID(cls, "setDevMode", "(J)V"); 258 DASSERT(AwtPrintControl::setDevmodeID != NULL); 259 CHECK_NULL(AwtPrintControl::setDevmodeID); 260 261 AwtPrintControl::getDevnamesID = 262 env->GetMethodID(cls, "getDevNames", "()J"); 263 DASSERT(AwtPrintControl::getDevnamesID != NULL); 264 CHECK_NULL(AwtPrintControl::getDevnamesID); 265 266 AwtPrintControl::setDevnamesID = 267 env->GetMethodID(cls, "setDevNames", "(J)V"); 268 DASSERT(AwtPrintControl::setDevnamesID != NULL); 269 CHECK_NULL(AwtPrintControl::setDevnamesID); 270 271 AwtPrintControl::driverDoesMultipleCopiesID = 272 env->GetFieldID(cls, "driverDoesMultipleCopies", "Z"); 273 DASSERT(AwtPrintControl::driverDoesMultipleCopiesID != NULL); 274 CHECK_NULL(AwtPrintControl::driverDoesMultipleCopiesID); 275 276 AwtPrintControl::driverDoesCollationID = 277 env->GetFieldID(cls, "driverDoesCollation", "Z"); 278 DASSERT(AwtPrintControl::driverDoesCollationID != NULL); 279 CHECK_NULL(AwtPrintControl::driverDoesCollationID); 280 281 AwtPrintControl::getCopiesID = 282 env->GetMethodID(cls, "getCopiesAttrib", "()I"); 283 DASSERT(AwtPrintControl::getCopiesID != NULL); 284 CHECK_NULL(AwtPrintControl::getCopiesID); 285 286 AwtPrintControl::getCollateID = 287 env->GetMethodID(cls, "getCollateAttrib","()I"); 288 DASSERT(AwtPrintControl::getCollateID != NULL); 289 CHECK_NULL(AwtPrintControl::getCollateID); 290 291 AwtPrintControl::getOrientID = 292 env->GetMethodID(cls, "getOrientAttrib", "()I"); 293 DASSERT(AwtPrintControl::getOrientID != NULL); 294 CHECK_NULL(AwtPrintControl::getOrientID); 295 296 AwtPrintControl::getFromPageID = 297 env->GetMethodID(cls, "getFromPageAttrib", "()I"); 298 DASSERT(AwtPrintControl::getFromPageID != NULL); 299 CHECK_NULL(AwtPrintControl::getFromPageID); 300 301 AwtPrintControl::getToPageID = 302 env->GetMethodID(cls, "getToPageAttrib", "()I"); 303 DASSERT(AwtPrintControl::getToPageID != NULL); 304 CHECK_NULL(AwtPrintControl::getToPageID); 305 306 AwtPrintControl::getMinPageID = 307 env->GetMethodID(cls, "getMinPageAttrib", "()I"); 308 DASSERT(AwtPrintControl::getMinPageID != NULL); 309 CHECK_NULL(AwtPrintControl::getMinPageID); 310 311 AwtPrintControl::getMaxPageID = 312 env->GetMethodID(cls, "getMaxPageAttrib", "()I"); 313 DASSERT(AwtPrintControl::getMaxPageID != NULL); 314 CHECK_NULL(AwtPrintControl::getMaxPageID); 315 316 AwtPrintControl::getDestID = 317 env->GetMethodID(cls, "getDestAttrib", "()Z"); 318 DASSERT(AwtPrintControl::getDestID != NULL); 319 CHECK_NULL(AwtPrintControl::getDestID); 320 321 AwtPrintControl::getQualityID = 322 env->GetMethodID(cls, "getQualityAttrib", "()I"); 323 DASSERT(AwtPrintControl::getQualityID != NULL); 324 CHECK_NULL(AwtPrintControl::getQualityID); 325 326 AwtPrintControl::getColorID = 327 env->GetMethodID(cls, "getColorAttrib", "()I"); 328 DASSERT(AwtPrintControl::getColorID != NULL); 329 CHECK_NULL(AwtPrintControl::getColorID); 330 331 AwtPrintControl::getSidesID = 332 env->GetMethodID(cls, "getSidesAttrib", "()I"); 333 DASSERT(AwtPrintControl::getSidesID != NULL); 334 CHECK_NULL(AwtPrintControl::getSidesID); 335 336 AwtPrintControl::getPrinterID = 337 env->GetMethodID(cls, "getPrinterAttrib", "()Ljava/lang/String;"); 338 DASSERT(AwtPrintControl::getPrinterID != NULL); 339 CHECK_NULL(AwtPrintControl::getPrinterID); 340 341 AwtPrintControl::getWin32MediaID = 342 env->GetMethodID(cls, "getWin32MediaAttrib", "()[I"); 343 DASSERT(AwtPrintControl::getWin32MediaID != NULL); 344 CHECK_NULL(AwtPrintControl::getWin32MediaID); 345 346 AwtPrintControl::setWin32MediaID = 347 env->GetMethodID(cls, "setWin32MediaAttrib", "(III)V"); 348 DASSERT(AwtPrintControl::setWin32MediaID != NULL); 349 CHECK_NULL(AwtPrintControl::setWin32MediaID); 350 351 AwtPrintControl::getWin32MediaTrayID = 352 env->GetMethodID(cls, "getMediaTrayAttrib", "()I"); 353 DASSERT(AwtPrintControl::getWin32MediaTrayID != NULL); 354 CHECK_NULL(AwtPrintControl::getWin32MediaTrayID); 355 356 AwtPrintControl::setWin32MediaTrayID = 357 env->GetMethodID(cls, "setMediaTrayAttrib", "(I)V"); 358 DASSERT(AwtPrintControl::setWin32MediaTrayID != NULL); 359 CHECK_NULL(AwtPrintControl::setWin32MediaTrayID); 360 361 AwtPrintControl::getSelectID = 362 env->GetMethodID(cls, "getSelectAttrib", "()I"); 363 DASSERT(AwtPrintControl::getSelectID != NULL); 364 CHECK_NULL(AwtPrintControl::getSelectID); 365 366 AwtPrintControl::getPrintToFileEnabledID = 367 env->GetMethodID(cls, "getPrintToFileEnabled", "()Z"); 368 DASSERT(AwtPrintControl::getPrintToFileEnabledID != NULL); 369 CHECK_NULL(AwtPrintControl::getPrintToFileEnabledID); 370 371 AwtPrintControl::setNativeAttID = 372 env->GetMethodID(cls, "setNativeAttributes", "(III)V"); 373 DASSERT(AwtPrintControl::setNativeAttID != NULL); 374 CHECK_NULL(AwtPrintControl::setNativeAttID); 375 376 AwtPrintControl::setRangeCopiesID = 377 env->GetMethodID(cls, "setRangeCopiesAttribute", "(IIZI)V"); 378 DASSERT(AwtPrintControl::setRangeCopiesID != NULL); 379 CHECK_NULL(AwtPrintControl::setRangeCopiesID); 380 381 AwtPrintControl::setResID = 382 env->GetMethodID(cls, "setResolutionDPI", "(II)V"); 383 DASSERT(AwtPrintControl::setResID != NULL); 384 CHECK_NULL(AwtPrintControl::setResID); 385 386 AwtPrintControl::setPrinterID = 387 env->GetMethodID(cls, "setPrinterNameAttrib", "(Ljava/lang/String;)V"); 388 DASSERT(AwtPrintControl::setPrinterID != NULL); 389 CHECK_NULL(AwtPrintControl::setPrinterID); 390 391 AwtPrintControl::setJobAttributesID = 392 env->GetMethodID(cls, "setJobAttributes", 393 "(Ljavax/print/attribute/PrintRequestAttributeSet;IISSSSSSS)V"); 394 DASSERT(AwtPrintControl::setJobAttributesID != NULL); 395 CHECK_NULL(AwtPrintControl::setJobAttributesID); 396 397 CATCH_BAD_ALLOC; 398 } 399 400 BOOL CALLBACK PrintDlgHook(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam) 401 { 402 TRY; 403 404 if (iMsg == WM_INITDIALOG) { 405 SetForegroundWindow(hDlg); 406 return FALSE; 407 } 408 return FALSE; 409 410 CATCH_BAD_ALLOC_RET(TRUE); 411 } 412 413 BOOL AwtPrintControl::CreateDevModeAndDevNames(PRINTDLG *ppd, 414 LPTSTR pPrinterName, 415 LPTSTR pPortName) 416 { 417 DWORD cbNeeded = 0; 418 LPBYTE pPrinter = NULL; 419 BOOL retval = FALSE; 420 HANDLE hPrinter; 421 422 try { 423 if (!::OpenPrinter(pPrinterName, &hPrinter, NULL)) { 424 goto done; 425 } 426 VERIFY(::GetPrinter(hPrinter, 2, NULL, 0, &cbNeeded) == 0); 427 if (::GetLastError() != ERROR_INSUFFICIENT_BUFFER) { 428 goto done; 429 } 430 pPrinter = new BYTE[cbNeeded]; 431 if (!::GetPrinter(hPrinter, 2, pPrinter, cbNeeded, &cbNeeded)) { 432 goto done; 433 } 434 PRINTER_INFO_2 *info2 = (PRINTER_INFO_2 *)pPrinter; 435 436 // Create DEVMODE, if it exists. 437 if (info2->pDevMode != NULL) { 438 size_t devmodeSize = 439 sizeof(DEVMODE) + info2->pDevMode->dmDriverExtra; 440 ppd->hDevMode = ::GlobalAlloc(GHND, devmodeSize); 441 if (ppd->hDevMode == NULL) { 442 throw std::bad_alloc(); 443 } 444 DEVMODE *devmode = (DEVMODE *)::GlobalLock(ppd->hDevMode); 445 DASSERT(!::IsBadWritePtr(devmode, devmodeSize)); 446 memcpy(devmode, info2->pDevMode, devmodeSize); 447 VERIFY(::GlobalUnlock(ppd->hDevMode) == 0); 448 DASSERT(::GetLastError() == NO_ERROR); 449 } 450 451 // Create DEVNAMES. 452 if (pPortName != NULL) { 453 info2->pPortName = pPortName; 454 } else if (info2->pPortName != NULL) { 455 // pPortName may specify multiple ports. We only want one. 456 info2->pPortName = _tcstok(info2->pPortName, TEXT(",")); 457 } 458 459 size_t lenDriverName = ((info2->pDriverName != NULL) 460 ? _tcslen(info2->pDriverName) 461 : 0) + 1; 462 size_t lenPrinterName = ((pPrinterName != NULL) 463 ? _tcslen(pPrinterName) 464 : 0) + 1; 465 size_t lenOutputName = ((info2->pPortName != NULL) 466 ? _tcslen(info2->pPortName) 467 : 0) + 1; 468 size_t devnameSize= sizeof(DEVNAMES) + 469 lenDriverName*sizeof(TCHAR) + 470 lenPrinterName*sizeof(TCHAR) + 471 lenOutputName*sizeof(TCHAR); 472 473 ppd->hDevNames = ::GlobalAlloc(GHND, devnameSize); 474 if (ppd->hDevNames == NULL) { 475 throw std::bad_alloc(); 476 } 477 478 DEVNAMES *devnames = 479 (DEVNAMES *)::GlobalLock(ppd->hDevNames); 480 DASSERT(!IsBadWritePtr(devnames, devnameSize)); 481 LPTSTR lpcDevnames = (LPTSTR)devnames; 482 483 // note: all sizes are in characters, not in bytes 484 devnames->wDriverOffset = sizeof(DEVNAMES)/sizeof(TCHAR); 485 devnames->wDeviceOffset = 486 static_cast<WORD>(sizeof(DEVNAMES)/sizeof(TCHAR) + lenDriverName); 487 devnames->wOutputOffset = 488 static_cast<WORD>(sizeof(DEVNAMES)/sizeof(TCHAR) + lenDriverName + lenPrinterName); 489 if (info2->pDriverName != NULL) { 490 _tcscpy_s(lpcDevnames + devnames->wDriverOffset, devnameSize - devnames->wDriverOffset, info2->pDriverName); 491 } else { 492 *(lpcDevnames + devnames->wDriverOffset) = _T('\0'); 493 } 494 if (pPrinterName != NULL) { 495 _tcscpy_s(lpcDevnames + devnames->wDeviceOffset, devnameSize - devnames->wDeviceOffset, pPrinterName); 496 } else { 497 *(lpcDevnames + devnames->wDeviceOffset) = _T('\0'); 498 } 499 if (info2->pPortName != NULL) { 500 _tcscpy_s(lpcDevnames + devnames->wOutputOffset, devnameSize - devnames->wOutputOffset, info2->pPortName); 501 } else { 502 *(lpcDevnames + devnames->wOutputOffset) = _T('\0'); 503 } 504 VERIFY(::GlobalUnlock(ppd->hDevNames) == 0); 505 DASSERT(::GetLastError() == NO_ERROR); 506 } catch (std::bad_alloc&) { 507 if (ppd->hDevNames != NULL) { 508 VERIFY(::GlobalFree(ppd->hDevNames) == NULL); 509 ppd->hDevNames = NULL; 510 } 511 if (ppd->hDevMode != NULL) { 512 VERIFY(::GlobalFree(ppd->hDevMode) == NULL); 513 ppd->hDevMode = NULL; 514 } 515 delete [] pPrinter; 516 VERIFY(::ClosePrinter(hPrinter)); 517 hPrinter = NULL; 518 throw; 519 } 520 521 retval = TRUE; 522 523 done: 524 delete [] pPrinter; 525 if (hPrinter) { 526 VERIFY(::ClosePrinter(hPrinter)); 527 hPrinter = NULL; 528 } 529 530 return retval; 531 } 532 533 534 WORD AwtPrintControl::getNearestMatchingPaper(LPTSTR printer, LPTSTR port, 535 double origWid, double origHgt, 536 double* newWid, double *newHgt) { 537 const double epsilon = 0.50; 538 const double tolerance = (1.0 * 72.0); // # inches * 72 539 int numPaperSizes = 0; 540 WORD *papers = NULL; 541 POINT *paperSizes = NULL; 542 543 if ((printer== NULL) || (port == NULL)) { 544 return 0; 545 } 546 547 SAVE_CONTROLWORD 548 numPaperSizes = (int)DeviceCapabilities(printer, port, DC_PAPERSIZE, 549 NULL, NULL); 550 551 if (numPaperSizes > 0) { 552 papers = (WORD*)SAFE_SIZE_ARRAY_ALLOC(safe_Malloc, sizeof(WORD), numPaperSizes); 553 paperSizes = (POINT *)SAFE_SIZE_ARRAY_ALLOC(safe_Malloc, sizeof(*paperSizes), 554 numPaperSizes); 555 556 DWORD result1 = DeviceCapabilities(printer, port, 557 DC_PAPERS, (LPTSTR) papers, NULL); 558 559 DWORD result2 = DeviceCapabilities(printer, port, 560 DC_PAPERSIZE, (LPTSTR) paperSizes, 561 NULL); 562 563 // REMIND: cache in papers and paperSizes 564 if (result1 == -1 || result2 == -1 ) { 565 free((LPTSTR) papers); 566 papers = NULL; 567 free((LPTSTR) paperSizes); 568 paperSizes = NULL; 569 } 570 } 571 RESTORE_CONTROLWORD 572 573 double closestWid = 0.0; 574 double closestHgt = 0.0; 575 WORD closestMatch = 0; 576 577 if (paperSizes != NULL) { 578 579 /* Paper sizes are in 0.1mm units. Convert to 1/72" 580 * For each paper size, compute the difference from the paper size 581 * passed in. Use a least-squares difference, so paper much different 582 * in x or y should score poorly 583 */ 584 double diffw = origWid; 585 double diffh = origHgt; 586 double least_square = diffw * diffw + diffh * diffh; 587 double tmp_ls; 588 double widpts, hgtpts; 589 590 for (int i=0;i<numPaperSizes;i++) { 591 widpts = paperSizes[i].x * LOMETRIC_TO_POINTS; 592 hgtpts = paperSizes[i].y * LOMETRIC_TO_POINTS; 593 594 if ((fabs(origWid - widpts) < epsilon) && 595 (fabs(origHgt - hgtpts) < epsilon)) { 596 closestWid = origWid; 597 closestHgt = origHgt; 598 closestMatch = papers[i]; 599 break; 600 } 601 602 diffw = fabs(widpts - origWid); 603 diffh = fabs(hgtpts - origHgt); 604 tmp_ls = diffw * diffw + diffh * diffh; 605 if ((diffw < tolerance) && (diffh < tolerance) && 606 (tmp_ls < least_square)) { 607 least_square = tmp_ls; 608 closestWid = widpts; 609 closestHgt = hgtpts; 610 closestMatch = papers[i]; 611 } 612 } 613 } 614 615 if (closestWid > 0) { 616 *newWid = closestWid; 617 } 618 if (closestHgt > 0) { 619 *newHgt = closestHgt; 620 } 621 622 if (papers != NULL) { 623 free((LPTSTR)papers); 624 } 625 626 if (paperSizes != NULL) { 627 free((LPTSTR)paperSizes); 628 } 629 630 return closestMatch; 631 } 632 633 /* 634 * Copy settings into a print dialog & any devmode 635 */ 636 BOOL AwtPrintControl::InitPrintDialog(JNIEnv *env, 637 jobject printCtrl, PRINTDLG &pd) { 638 HWND hwndOwner = NULL; 639 jobject dialogOwner = 640 env->GetObjectField(printCtrl, AwtPrintControl::dialogOwnerPeerID); 641 if (dialogOwner != NULL) { 642 AwtComponent *dialogOwnerComp = 643 (AwtComponent *)JNI_GET_PDATA(dialogOwner); 644 645 hwndOwner = dialogOwnerComp->GetHWnd(); 646 env->DeleteLocalRef(dialogOwner); 647 dialogOwner = NULL; 648 } 649 jobject mdh = NULL; 650 jobject dest = NULL; 651 jobject select = NULL; 652 jobject dialog = NULL; 653 LPTSTR printName = NULL; 654 LPTSTR portName = NULL; 655 656 // If the user didn't specify a printer, then this call returns the 657 // name of the default printer. 658 jstring printerName = (jstring) 659 env->CallObjectMethod(printCtrl, AwtPrintControl::getPrinterID); 660 661 if (printerName != NULL) { 662 663 pd.hDevMode = AwtPrintControl::getPrintHDMode(env, printCtrl); 664 pd.hDevNames = AwtPrintControl::getPrintHDName(env, printCtrl); 665 666 LPTSTR getName = (LPTSTR)JNU_GetStringPlatformChars(env, 667 printerName, NULL); 668 if (getName == NULL) { 669 env->DeleteLocalRef(printerName); 670 throw std::bad_alloc(); 671 } 672 673 BOOL samePrinter = FALSE; 674 675 // check if given printername is same as the currently saved printer 676 if (pd.hDevNames != NULL ) { 677 678 DEVNAMES *devnames = (DEVNAMES *)::GlobalLock(pd.hDevNames); 679 if (devnames != NULL) { 680 LPTSTR lpdevnames = (LPTSTR)devnames; 681 printName = lpdevnames+devnames->wDeviceOffset; 682 683 if (!_tcscmp(printName, getName)) { 684 685 samePrinter = TRUE; 686 printName = _tcsdup(lpdevnames+devnames->wDeviceOffset); 687 portName = _tcsdup(lpdevnames+devnames->wOutputOffset); 688 689 } 690 } 691 ::GlobalUnlock(pd.hDevNames); 692 } 693 694 if (!samePrinter) { 695 LPTSTR foundPrinter = NULL; 696 LPTSTR foundPort = NULL; 697 DWORD cbBuf = 0; 698 VERIFY(AwtPrintControl::FindPrinter(NULL, NULL, &cbBuf, 699 NULL, NULL)); 700 LPBYTE buffer = new BYTE[cbBuf]; 701 702 if (AwtPrintControl::FindPrinter(printerName, buffer, &cbBuf, 703 &foundPrinter, &foundPort) && 704 (foundPrinter != NULL) && (foundPort != NULL)) { 705 706 printName = _tcsdup(foundPrinter); 707 portName = _tcsdup(foundPort); 708 709 if (!AwtPrintControl::CreateDevModeAndDevNames(&pd, 710 foundPrinter, foundPort)) { 711 delete [] buffer; 712 if (printName != NULL) { 713 free(printName); 714 } 715 if (portName != NULL) { 716 free(portName); 717 } 718 env->DeleteLocalRef(printerName); 719 return FALSE; 720 } 721 722 DASSERT(pd.hDevNames != NULL); 723 } else { 724 delete [] buffer; 725 if (printName != NULL) { 726 free(printName); 727 } 728 if (portName != NULL) { 729 free(portName); 730 } 731 env->DeleteLocalRef(printerName); 732 return FALSE; 733 } 734 735 delete [] buffer; 736 } 737 env->DeleteLocalRef(printerName); 738 // PrintDlg may change the values of hDevMode and hDevNames so we 739 // re-initialize our saved handles. 740 AwtPrintControl::setPrintHDMode(env, printCtrl, NULL); 741 AwtPrintControl::setPrintHDName(env, printCtrl, NULL); 742 } else { 743 744 // There is no default printer. This means that there are no 745 // printers installed at all. 746 747 if (printName != NULL) { 748 free(printName); 749 } 750 if (portName != NULL) { 751 free(portName); 752 } 753 // Returning TRUE means try to display the native print dialog 754 // which will either display an error message or prompt the 755 // user to install a printer. 756 return TRUE; 757 } 758 759 // Now, set-up the struct for the real calls to ::PrintDlg and ::CreateDC 760 761 pd.hwndOwner = hwndOwner; 762 pd.Flags = PD_ENABLEPRINTHOOK | PD_RETURNDC | PD_USEDEVMODECOPIESANDCOLLATE; 763 pd.lpfnPrintHook = (LPPRINTHOOKPROC)PrintDlgHook; 764 765 pd.nFromPage = (WORD)env->CallIntMethod(printCtrl, 766 AwtPrintControl::getFromPageID); 767 pd.nToPage = (WORD)env->CallIntMethod(printCtrl, 768 AwtPrintControl::getToPageID); 769 pd.nMinPage = (WORD)env->CallIntMethod(printCtrl, 770 AwtPrintControl::getMinPageID); 771 jint maxPage = env->CallIntMethod(printCtrl, 772 AwtPrintControl::getMaxPageID); 773 pd.nMaxPage = (maxPage <= (jint)((WORD)-1)) ? (WORD)maxPage : (WORD)-1; 774 // In the event that the application displays the dialog before 775 // installing a Printable, but sets a page range, then max page will be 1 776 // since the default state of a PrinterJob is an empty "Book" Pageable. 777 // Windows pops up an error dialog in such a case which isn't very 778 // forthcoming about the exact problem. 779 // So if we detect this fix up such a problem here. 780 if (pd.nMinPage > pd.nFromPage) pd.nMinPage = pd.nFromPage; 781 if (pd.nMaxPage < pd.nToPage) pd.nMaxPage = pd.nToPage; 782 if (pd.nToPage > pd.nFromPage && (pd.nFromPage > pd.nMinPage || pd.nToPage < pd.nMaxPage)) { 783 pd.Flags |= PD_PAGENUMS; 784 } 785 786 if (env->CallBooleanMethod(printCtrl, 787 AwtPrintControl::getDestID)) { 788 pd.Flags |= PD_PRINTTOFILE; 789 } 790 791 jint selectType = env->CallIntMethod(printCtrl, 792 AwtPrintControl::getSelectID); 793 794 // selectType identifies whether No selection (2D) or 795 // SunPageSelection (AWT) 796 if (selectType != 0) { 797 pd.Flags |= selectType; 798 } 799 800 if (!env->CallBooleanMethod(printCtrl, 801 AwtPrintControl::getPrintToFileEnabledID)) { 802 pd.Flags |= PD_DISABLEPRINTTOFILE; 803 } 804 805 if (pd.hDevMode != NULL) { 806 DEVMODE *devmode = (DEVMODE *)::GlobalLock(pd.hDevMode); 807 DASSERT(!IsBadWritePtr(devmode, sizeof(DEVMODE))); 808 809 WORD copies = (WORD)env->CallIntMethod(printCtrl, 810 AwtPrintControl::getCopiesID); 811 if (copies > 0) { 812 devmode->dmFields |= DM_COPIES; 813 devmode->dmCopies = copies; 814 } 815 816 jint orient = env->CallIntMethod(printCtrl, 817 AwtPrintControl::getOrientID); 818 if (orient == 0) { // PageFormat.LANDSCAPE == 0 819 devmode->dmFields |= DM_ORIENTATION; 820 devmode->dmOrientation = DMORIENT_LANDSCAPE; 821 } else if (orient == 1) { // PageFormat.PORTRAIT == 1 822 devmode->dmFields |= DM_ORIENTATION; 823 devmode->dmOrientation = DMORIENT_PORTRAIT; 824 } 825 826 // -1 means unset, so we'll accept the printer default. 827 int collate = env->CallIntMethod(printCtrl, 828 AwtPrintControl::getCollateID); 829 if (collate == 1) { 830 devmode->dmFields |= DM_COLLATE; 831 devmode->dmCollate = DMCOLLATE_TRUE; 832 } else if (collate == 0) { 833 devmode->dmFields |= DM_COLLATE; 834 devmode->dmCollate = DMCOLLATE_FALSE; 835 } 836 837 int quality = env->CallIntMethod(printCtrl, 838 AwtPrintControl::getQualityID); 839 if (quality) { 840 devmode->dmFields |= DM_PRINTQUALITY; 841 devmode->dmPrintQuality = quality; 842 } 843 844 int color = env->CallIntMethod(printCtrl, 845 AwtPrintControl::getColorID); 846 if (color) { 847 devmode->dmFields |= DM_COLOR; 848 devmode->dmColor = color; 849 } 850 851 int sides = env->CallIntMethod(printCtrl, 852 AwtPrintControl::getSidesID); 853 if (sides) { 854 devmode->dmFields |= DM_DUPLEX; 855 devmode->dmDuplex = (int)sides; 856 } 857 858 jintArray obj = (jintArray)env->CallObjectMethod(printCtrl, 859 AwtPrintControl::getWin32MediaID); 860 jboolean isCopy; 861 jint *wid_ht = env->GetIntArrayElements(obj, 862 &isCopy); 863 864 double newWid = 0.0, newHt = 0.0; 865 if (wid_ht != NULL && wid_ht[0] != 0 && wid_ht[1] != 0) { 866 devmode->dmFields |= DM_PAPERSIZE; 867 devmode->dmPaperSize = AwtPrintControl::getNearestMatchingPaper( 868 printName, 869 portName, 870 (double)wid_ht[0], 871 (double)wid_ht[1], 872 &newWid, &newHt); 873 874 } 875 env->ReleaseIntArrayElements(obj, wid_ht, 0); 876 ::GlobalUnlock(pd.hDevMode); 877 devmode = NULL; 878 } 879 880 if (printName != NULL) { 881 free(printName); 882 } 883 if (portName != NULL) { 884 free(portName); 885 } 886 887 return TRUE; 888 } 889 890 891 /* 892 * Copy settings from print dialog & any devmode back into attributes 893 * or properties. 894 */ 895 extern "C" { 896 extern void setCapabilities(JNIEnv *env, jobject WPrinterJob, HDC hdc); 897 } 898 BOOL AwtPrintControl::UpdateAttributes(JNIEnv *env, 899 jobject printCtrl, PRINTDLG &pd) { 900 901 DEVNAMES *devnames = NULL; 902 DEVMODE *devmode = NULL; 903 unsigned int copies = 1; 904 DWORD pdFlags = pd.Flags; 905 DWORD dmFields = 0, dmValues = 0; 906 bool newDC = false; 907 908 // This call ensures that default PrintService gets updated for the 909 // case where initially, there weren't any printers. 910 env->CallObjectMethod(printCtrl, AwtPrintControl::getPrinterID); 911 912 if (pd.hDevMode != NULL) { 913 devmode = (DEVMODE *)::GlobalLock(pd.hDevMode); 914 DASSERT(!IsBadReadPtr(devmode, sizeof(DEVMODE))); 915 } 916 917 if (devmode != NULL) { 918 /* Query the settings we understand and are interested in. 919 * For the flags that are set in dmFields, where the values 920 * are a simple enumeration, set the same bits in a clean dmFields 921 * variable, and set bits in a dmValues variable to indicate the 922 * selected value. These can all be passed up to Java in one 923 * call to sync up the Java view of this. 924 */ 925 926 if (devmode->dmFields & DM_COPIES) { 927 dmFields |= DM_COPIES; 928 copies = devmode->dmCopies; 929 if (pd.nCopies == 1) { 930 env->SetBooleanField(printCtrl, 931 driverDoesMultipleCopiesID, 932 JNI_TRUE); 933 } else { 934 copies = pd.nCopies; 935 } 936 } 937 938 if (devmode->dmFields & DM_PAPERSIZE) { 939 env->CallVoidMethod(printCtrl, AwtPrintControl::setWin32MediaID, 940 devmode->dmPaperSize, devmode->dmPaperWidth, 941 devmode->dmPaperLength); 942 943 } 944 945 if (devmode->dmFields & DM_DEFAULTSOURCE) { 946 env->CallVoidMethod(printCtrl, 947 AwtPrintControl::setWin32MediaTrayID, 948 devmode->dmDefaultSource); 949 } 950 951 if (devmode->dmFields & DM_COLOR) { 952 dmFields |= DM_COLOR; 953 if (devmode->dmColor == DMCOLOR_COLOR) { 954 dmValues |= SET_COLOR; 955 } 956 } 957 958 if (devmode->dmFields & DM_ORIENTATION) { 959 dmFields |= DM_ORIENTATION; 960 if (devmode->dmOrientation == DMORIENT_LANDSCAPE) { 961 dmValues |= SET_ORIENTATION; 962 } 963 } 964 965 if (devmode->dmFields & DM_COLLATE) { 966 dmFields |= DM_COLLATE; 967 if (devmode->dmCollate == DMCOLLATE_TRUE) { 968 pdFlags |= PD_COLLATE; 969 env->SetBooleanField(printCtrl, 970 driverDoesCollationID, 971 JNI_TRUE); 972 } else { 973 pdFlags &= ~PD_COLLATE; 974 } 975 } 976 977 if (devmode->dmFields & DM_PRINTQUALITY) { 978 /* value < 0 indicates quality setting. 979 * value > 0 indicates X resolution. In that case 980 * hopefully we will also find y-resolution specified. 981 * If its not, assume its the same as x-res. 982 * Maybe Java code should try to reconcile this against 983 * the printers claimed set of supported resolutions. 984 */ 985 if (devmode->dmPrintQuality < 0) { 986 if (dmFields |= DM_PRINTQUALITY) { 987 if (devmode->dmPrintQuality == DMRES_HIGH) { 988 dmValues |= SET_RES_HIGH; 989 } else if ((devmode->dmPrintQuality == DMRES_LOW) || 990 (devmode->dmPrintQuality == DMRES_DRAFT)) { 991 dmValues |= SET_RES_LOW; 992 } else if (devmode->dmPrintQuality == DMRES_MEDIUM) { 993 /* default */ 994 } 995 } 996 } else { 997 int xRes = devmode->dmPrintQuality; 998 int yRes = (devmode->dmFields & DM_YRESOLUTION) ? 999 devmode->dmYResolution : devmode->dmPrintQuality; 1000 env->CallVoidMethod(printCtrl, AwtPrintControl::setResID, 1001 xRes, yRes); 1002 } 1003 } 1004 1005 if (devmode->dmFields & DM_DUPLEX) { 1006 dmFields |= DM_DUPLEX; 1007 if (devmode->dmDuplex == DMDUP_HORIZONTAL) { 1008 dmValues |= SET_DUP_HORIZONTAL; 1009 } else if (devmode->dmDuplex == DMDUP_VERTICAL) { 1010 dmValues |= SET_DUP_VERTICAL; 1011 } 1012 } 1013 1014 1015 ::GlobalUnlock(pd.hDevMode); 1016 devmode = NULL; 1017 } else { 1018 copies = pd.nCopies; 1019 } 1020 1021 if (pd.hDevNames != NULL) { 1022 DEVNAMES *devnames = (DEVNAMES*)::GlobalLock(pd.hDevNames); 1023 DASSERT(!IsBadReadPtr(devnames, sizeof(DEVNAMES))); 1024 LPTSTR lpcNames = (LPTSTR)devnames; 1025 LPTSTR pbuf = (_tcslen(lpcNames + devnames->wDeviceOffset) == 0 ? 1026 TEXT("") : lpcNames + devnames->wDeviceOffset); 1027 if (pbuf != NULL) { 1028 jstring jstr = JNU_NewStringPlatform(env, pbuf); 1029 env->CallVoidMethod(printCtrl, 1030 AwtPrintControl::setPrinterID, 1031 jstr); 1032 env->DeleteLocalRef(jstr); 1033 } 1034 pbuf = (_tcslen(lpcNames + devnames->wOutputOffset) == 0 ? 1035 TEXT("") : lpcNames + devnames->wOutputOffset); 1036 if (pbuf != NULL) { 1037 if (wcscmp(pbuf, L"FILE:") == 0) { 1038 pdFlags |= PD_PRINTTOFILE; 1039 } 1040 } 1041 ::GlobalUnlock(pd.hDevNames); 1042 devnames = NULL; 1043 } 1044 1045 1046 env->CallVoidMethod(printCtrl, AwtPrintControl::setNativeAttID, 1047 pdFlags, dmFields, dmValues); 1048 1049 1050 // copies & range are always set so no need to check for any flags 1051 env->CallVoidMethod(printCtrl, AwtPrintControl::setRangeCopiesID, 1052 pd.nFromPage, pd.nToPage, (pdFlags & PD_PAGENUMS), 1053 copies); 1054 1055 // repeated calls to printDialog should not leak handles 1056 HDC oldDC = AwtPrintControl::getPrintDC(env, printCtrl); 1057 if (pd.hDC != oldDC) { 1058 if (oldDC != NULL) { 1059 ::DeleteDC(oldDC); 1060 } 1061 AwtPrintControl::setPrintDC(env, printCtrl, pd.hDC); 1062 newDC = true; 1063 } 1064 // Need to update WPrinterJob with device resolution settings for 1065 // new or changed DC. 1066 setCapabilities(env, printCtrl, pd.hDC); 1067 1068 HGLOBAL oldG = AwtPrintControl::getPrintHDMode(env, printCtrl); 1069 if (pd.hDevMode != oldG) { 1070 AwtPrintControl::setPrintHDMode(env, printCtrl, pd.hDevMode); 1071 } 1072 1073 oldG = AwtPrintControl::getPrintHDName(env, printCtrl); 1074 if (pd.hDevNames != oldG) { 1075 AwtPrintControl::setPrintHDName(env, printCtrl, pd.hDevNames); 1076 } 1077 1078 return newDC; 1079 } 1080 1081 1082 BOOL AwtPrintControl::getDevmode( HANDLE hPrinter, 1083 LPTSTR printerName, 1084 LPDEVMODE *pDevMode) { 1085 1086 if (hPrinter == NULL || printerName == NULL || pDevMode == NULL) { 1087 return FALSE; 1088 } 1089 1090 SAVE_CONTROLWORD 1091 1092 DWORD dwNeeded = ::DocumentProperties(NULL, hPrinter, printerName, 1093 NULL, NULL, 0); 1094 1095 RESTORE_CONTROLWORD 1096 1097 if (dwNeeded <= 0) { 1098 *pDevMode = NULL; 1099 return FALSE; 1100 } 1101 1102 *pDevMode = (LPDEVMODE)GlobalAlloc(GPTR, dwNeeded); 1103 1104 if (*pDevMode == NULL) { 1105 return FALSE; 1106 } 1107 1108 DWORD dwRet = ::DocumentProperties(NULL, 1109 hPrinter, 1110 printerName, 1111 *pDevMode, 1112 NULL, 1113 DM_OUT_BUFFER); 1114 1115 RESTORE_CONTROLWORD 1116 1117 if (dwRet != IDOK) { 1118 /* if failure, cleanup and return failure */ 1119 GlobalFree(pDevMode); 1120 *pDevMode = NULL; 1121 return FALSE; 1122 } 1123 1124 return TRUE; 1125 }