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     LPTSTR lpcPrinterName = (LPTSTR)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 }