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