1 /*
   2  * Copyright (c) 1999, 2020, 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         JNU_ReleaseStringPlatformChars(env, printerName, getName);
 700 
 701         if (!samePrinter) {
 702             LPTSTR foundPrinter = NULL;
 703             LPTSTR foundPort = NULL;
 704             DWORD cbBuf = 0;
 705             VERIFY(AwtPrintControl::FindPrinter(NULL, NULL, &cbBuf,
 706                                                 NULL, NULL));
 707             LPBYTE buffer = new BYTE[cbBuf];
 708 
 709             if (AwtPrintControl::FindPrinter(printerName, buffer, &cbBuf,
 710                                              &foundPrinter, &foundPort) &&
 711                 (foundPrinter != NULL) && (foundPort != NULL)) {
 712 
 713                 printName = _tcsdup(foundPrinter);
 714                 portName = _tcsdup(foundPort);
 715 
 716                 if (!AwtPrintControl::CreateDevModeAndDevNames(&pd,
 717                                                    foundPrinter, foundPort)) {
 718                     delete [] buffer;
 719                     if (printName != NULL) {
 720                       free(printName);
 721                     }
 722                     if (portName != NULL) {
 723                       free(portName);
 724                     }
 725                     env->DeleteLocalRef(printerName);
 726                     return FALSE;
 727                 }
 728 
 729                 DASSERT(pd.hDevNames != NULL);
 730             } else {
 731                 delete [] buffer;
 732                 if (printName != NULL) {
 733                   free(printName);
 734                 }
 735                 if (portName != NULL) {
 736                   free(portName);
 737                 }
 738                 env->DeleteLocalRef(printerName);
 739                 return FALSE;
 740             }
 741 
 742             delete [] buffer;
 743         }
 744         env->DeleteLocalRef(printerName);
 745         // PrintDlg may change the values of hDevMode and hDevNames so we
 746         // re-initialize our saved handles.
 747         AwtPrintControl::setPrintHDMode(env, printCtrl, NULL);
 748         AwtPrintControl::setPrintHDName(env, printCtrl, NULL);
 749     } else {
 750 
 751         // There is no default printer. This means that there are no
 752         // printers installed at all.
 753 
 754         if (printName != NULL) {
 755           free(printName);
 756         }
 757         if (portName != NULL) {
 758           free(portName);
 759         }
 760         // Returning TRUE means try to display the native print dialog
 761         // which will either display an error message or prompt the
 762         // user to install a printer.
 763         return TRUE;
 764     }
 765 
 766     // Now, set-up the struct for the real calls to ::PrintDlg and ::CreateDC
 767 
 768     pd.hwndOwner = hwndOwner;
 769     pd.Flags = PD_ENABLEPRINTHOOK | PD_RETURNDC | PD_USEDEVMODECOPIESANDCOLLATE;
 770     pd.lpfnPrintHook = (LPPRINTHOOKPROC)PrintDlgHook;
 771 
 772     pd.nFromPage = (WORD)env->CallIntMethod(printCtrl,
 773                                             AwtPrintControl::getFromPageID);
 774     pd.nToPage = (WORD)env->CallIntMethod(printCtrl,
 775                                           AwtPrintControl::getToPageID);
 776     pd.nMinPage = (WORD)env->CallIntMethod(printCtrl,
 777                                            AwtPrintControl::getMinPageID);
 778     jint maxPage = env->CallIntMethod(printCtrl,
 779                                       AwtPrintControl::getMaxPageID);
 780 
 781     jint selectType = env->CallIntMethod(printCtrl,
 782                                          AwtPrintControl::getSelectID);
 783 
 784     pd.nMaxPage = (maxPage <= (jint)((WORD)-1)) ? (WORD)maxPage : (WORD)-1;
 785     // In the event that the application displays the dialog before
 786     // installing a Printable, but sets a page range, then max page will be 1
 787     // since the default state of a PrinterJob is an empty "Book" Pageable.
 788     // Windows pops up an error dialog in such a case which isn't very
 789     // forthcoming about the exact problem.
 790     // So if we detect this fix up such a problem here.
 791     if (pd.nMinPage > pd.nFromPage) pd.nMinPage = pd.nFromPage;
 792     if (pd.nMaxPage < pd.nToPage) pd.nMaxPage = pd.nToPage;
 793     if (selectType != 0 && (pd.nFromPage > pd.nMinPage || pd.nToPage < pd.nMaxPage)) {
 794         if (selectType == PD_SELECTION) {
 795             pd.Flags |= PD_SELECTION;
 796         } else {
 797             pd.Flags |= PD_PAGENUMS;
 798         }
 799     }
 800 
 801     if (env->CallBooleanMethod(printCtrl,
 802                                AwtPrintControl::getDestID)) {
 803       pd.Flags |= PD_PRINTTOFILE;
 804     }
 805 
 806     // selectType identifies whether No selection (2D) or
 807     // SunPageSelection (AWT)
 808     if (selectType != 0) {
 809       pd.Flags |= selectType;
 810     }
 811 
 812     if (!env->CallBooleanMethod(printCtrl,
 813                                 AwtPrintControl::getPrintToFileEnabledID)) {
 814       pd.Flags |= PD_DISABLEPRINTTOFILE;
 815     }
 816 
 817     if (pd.hDevMode != NULL) {
 818       DEVMODE *devmode = (DEVMODE *)::GlobalLock(pd.hDevMode);
 819       DASSERT(!IsBadWritePtr(devmode, sizeof(DEVMODE)));
 820 
 821       WORD copies = (WORD)env->CallIntMethod(printCtrl,
 822                                              AwtPrintControl::getCopiesID);
 823       if (copies > 0) {
 824           devmode->dmFields |= DM_COPIES;
 825           devmode->dmCopies = copies;
 826       }
 827 
 828       jint orient = env->CallIntMethod(printCtrl,
 829                                        AwtPrintControl::getOrientID);
 830       if (orient == 0) {  // PageFormat.LANDSCAPE == 0
 831         devmode->dmFields |= DM_ORIENTATION;
 832         devmode->dmOrientation = DMORIENT_LANDSCAPE;
 833       } else if (orient == 1) { // PageFormat.PORTRAIT == 1
 834         devmode->dmFields |= DM_ORIENTATION;
 835         devmode->dmOrientation = DMORIENT_PORTRAIT;
 836       }
 837 
 838       // -1 means unset, so we'll accept the printer default.
 839       int collate = env->CallIntMethod(printCtrl,
 840                                        AwtPrintControl::getCollateID);
 841       if (collate == 1) {
 842         devmode->dmFields |= DM_COLLATE;
 843         devmode->dmCollate = DMCOLLATE_TRUE;
 844       } else if (collate == 0) {
 845         devmode->dmFields |= DM_COLLATE;
 846         devmode->dmCollate = DMCOLLATE_FALSE;
 847       }
 848 
 849       int quality = env->CallIntMethod(printCtrl,
 850                                        AwtPrintControl::getQualityID);
 851       if (quality) {
 852         devmode->dmFields |= DM_PRINTQUALITY;
 853         devmode->dmPrintQuality = quality;
 854       }
 855 
 856       int color = env->CallIntMethod(printCtrl,
 857                                      AwtPrintControl::getColorID);
 858       if (color) {
 859         devmode->dmFields |= DM_COLOR;
 860         devmode->dmColor = color;
 861       }
 862 
 863       int sides = env->CallIntMethod(printCtrl,
 864                                      AwtPrintControl::getSidesID);
 865       if (sides) {
 866         devmode->dmFields |= DM_DUPLEX;
 867         devmode->dmDuplex = (int)sides;
 868       }
 869 
 870       jintArray obj = (jintArray)env->CallObjectMethod(printCtrl,
 871                                        AwtPrintControl::getWin32MediaID);
 872       jboolean isCopy;
 873       jint *wid_ht = env->GetIntArrayElements(obj,
 874                                               &isCopy);
 875 
 876       double newWid = 0.0, newHt = 0.0;
 877       if (wid_ht != NULL && wid_ht[0] != 0 && wid_ht[1] != 0) {
 878         devmode->dmFields |= DM_PAPERSIZE;
 879         devmode->dmPaperSize = AwtPrintControl::getNearestMatchingPaper(
 880                                              printName,
 881                                              portName,
 882                                              (double)wid_ht[0],
 883                                              (double)wid_ht[1],
 884                                              &newWid, &newHt);
 885 
 886       }
 887       env->ReleaseIntArrayElements(obj, wid_ht, 0);
 888       ::GlobalUnlock(pd.hDevMode);
 889       devmode = NULL;
 890     }
 891 
 892     if (printName != NULL) {
 893       free(printName);
 894     }
 895     if (portName != NULL) {
 896       free(portName);
 897     }
 898 
 899     return TRUE;
 900 }
 901 
 902 
 903 /*
 904  * Copy settings from print dialog & any devmode back into attributes
 905  * or properties.
 906  */
 907 extern "C" {
 908 extern void setCapabilities(JNIEnv *env, jobject WPrinterJob, HDC hdc);
 909 }
 910 BOOL AwtPrintControl::UpdateAttributes(JNIEnv *env,
 911                                        jobject printCtrl, PRINTDLG &pd) {
 912 
 913     DEVNAMES *devnames = NULL;
 914     DEVMODE *devmode = NULL;
 915     unsigned int copies = 1;
 916     DWORD pdFlags = pd.Flags;
 917     DWORD dmFields = 0, dmValues = 0;
 918     bool newDC = false;
 919 
 920     // This call ensures that default PrintService gets updated for the
 921     // case where initially, there weren't any printers.
 922     env->CallObjectMethod(printCtrl, AwtPrintControl::getPrinterID);
 923 
 924     if (pd.hDevMode != NULL) {
 925         devmode = (DEVMODE *)::GlobalLock(pd.hDevMode);
 926         DASSERT(!IsBadReadPtr(devmode, sizeof(DEVMODE)));
 927     }
 928 
 929     if (devmode != NULL) {
 930         /* Query the settings we understand and are interested in.
 931          * For the flags that are set in dmFields, where the values
 932          * are a simple enumeration, set the same bits in a clean dmFields
 933          * variable, and set bits in a dmValues variable to indicate the
 934          * selected value. These can all be passed up to Java in one
 935          * call to sync up the Java view of this.
 936          */
 937 
 938         if (devmode->dmFields & DM_COPIES) {
 939             dmFields |= DM_COPIES;
 940             copies = devmode->dmCopies;
 941             if (pd.nCopies == 1) {
 942                 env->SetBooleanField(printCtrl,
 943                                      driverDoesMultipleCopiesID,
 944                                      JNI_TRUE);
 945             } else {
 946               copies = pd.nCopies;
 947             }
 948         }
 949 
 950         if (devmode->dmFields & DM_PAPERSIZE) {
 951             env->CallVoidMethod(printCtrl, AwtPrintControl::setWin32MediaID,
 952                                 devmode->dmPaperSize, devmode->dmPaperWidth,
 953                                 devmode->dmPaperLength);
 954 
 955         }
 956 
 957         if (devmode->dmFields & DM_DEFAULTSOURCE) {
 958             env->CallVoidMethod(printCtrl,
 959                                 AwtPrintControl::setWin32MediaTrayID,
 960                                 devmode->dmDefaultSource);
 961         }
 962 
 963         if (devmode->dmFields & DM_COLOR) {
 964             dmFields |= DM_COLOR;
 965             if (devmode->dmColor == DMCOLOR_COLOR) {
 966                 dmValues |= SET_COLOR;
 967             }
 968         }
 969 
 970         if (devmode->dmFields & DM_ORIENTATION) {
 971             dmFields |= DM_ORIENTATION;
 972             if (devmode->dmOrientation == DMORIENT_LANDSCAPE) {
 973                 dmValues |= SET_ORIENTATION;
 974             }
 975         }
 976 
 977         if (devmode->dmFields & DM_COLLATE) {
 978             dmFields |= DM_COLLATE;
 979             if (devmode->dmCollate == DMCOLLATE_TRUE) {
 980                 pdFlags |= PD_COLLATE;
 981                 env->SetBooleanField(printCtrl,
 982                                      driverDoesCollationID,
 983                                      JNI_TRUE);
 984             } else {
 985                 pdFlags &= ~PD_COLLATE;
 986             }
 987         }
 988 
 989         if (devmode->dmFields & DM_PRINTQUALITY) {
 990             /* value < 0 indicates quality setting.
 991              * value > 0 indicates X resolution. In that case
 992              * hopefully we will also find y-resolution specified.
 993              * If its not, assume its the same as x-res.
 994              * Maybe Java code should try to reconcile this against
 995              * the printers claimed set of supported resolutions.
 996              */
 997             if (devmode->dmPrintQuality < 0) {
 998                 if (dmFields |= DM_PRINTQUALITY) {
 999                     if (devmode->dmPrintQuality == DMRES_HIGH) {
1000                         dmValues |= SET_RES_HIGH;
1001                     } else if ((devmode->dmPrintQuality == DMRES_LOW) ||
1002                                (devmode->dmPrintQuality == DMRES_DRAFT)) {
1003                         dmValues |= SET_RES_LOW;
1004                     } else if (devmode->dmPrintQuality == DMRES_MEDIUM) {
1005                         /* default */
1006                     }
1007                 }
1008             } else {
1009                 int xRes = devmode->dmPrintQuality;
1010 
1011                 /* For some printers, printer quality can specify 1200IQ
1012                  * In this case, dmPrintQuality comes out 600 and
1013                  * dmYResolution comes out 2, similarly for 2400IQ
1014                  * dmPrintQuality comes out 600 and dmYResolution comes out 4
1015                  * which is not a valid resolution
1016                  * so for IQ setting, we modify y-resolution only when it is
1017                  * greater than 10.
1018                  */
1019                 int yRes = (devmode->dmFields & DM_YRESOLUTION) &&
1020                            (devmode->dmYResolution > 10) ?
1021                            devmode->dmYResolution : devmode->dmPrintQuality;
1022 
1023                 env->CallVoidMethod(printCtrl, AwtPrintControl::setResID,
1024                                     xRes, yRes);
1025             }
1026         }
1027 
1028         if (devmode->dmFields & DM_DUPLEX) {
1029             dmFields |= DM_DUPLEX;
1030             if (devmode->dmDuplex == DMDUP_HORIZONTAL) {
1031               dmValues |= SET_DUP_HORIZONTAL;
1032             } else if (devmode->dmDuplex == DMDUP_VERTICAL) {
1033                 dmValues |= SET_DUP_VERTICAL;
1034             }
1035         }
1036 
1037 
1038         ::GlobalUnlock(pd.hDevMode);
1039         devmode = NULL;
1040     } else {
1041         copies = pd.nCopies;
1042     }
1043 
1044     if (pd.hDevNames != NULL) {
1045         DEVNAMES *devnames = (DEVNAMES*)::GlobalLock(pd.hDevNames);
1046         DASSERT(!IsBadReadPtr(devnames, sizeof(DEVNAMES)));
1047         LPTSTR lpcNames = (LPTSTR)devnames;
1048         LPTSTR pbuf = (_tcslen(lpcNames + devnames->wDeviceOffset) == 0 ?
1049                       TEXT("") : lpcNames + devnames->wDeviceOffset);
1050         if (pbuf != NULL) {
1051             jstring jstr = JNU_NewStringPlatform(env, pbuf);
1052             env->CallVoidMethod(printCtrl,
1053                                 AwtPrintControl::setPrinterID,
1054                                 jstr);
1055             env->DeleteLocalRef(jstr);
1056         }
1057         pbuf = (_tcslen(lpcNames + devnames->wOutputOffset) == 0 ?
1058                       TEXT("") : lpcNames + devnames->wOutputOffset);
1059         if (pbuf != NULL) {
1060             if (wcscmp(pbuf, L"FILE:") == 0) {
1061                 pdFlags |= PD_PRINTTOFILE;
1062             }
1063         }
1064         ::GlobalUnlock(pd.hDevNames);
1065         devnames = NULL;
1066     }
1067 
1068 
1069     env->CallVoidMethod(printCtrl, AwtPrintControl::setNativeAttID,
1070                         pdFlags,  dmFields, dmValues);
1071 
1072 
1073     // copies  & range are always set so no need to check for any flags
1074     env->CallVoidMethod(printCtrl, AwtPrintControl::setRangeCopiesID,
1075                         pd.nFromPage, pd.nToPage, (pdFlags & PD_PAGENUMS),
1076                         copies);
1077 
1078     // repeated calls to printDialog should not leak handles
1079     HDC oldDC = AwtPrintControl::getPrintDC(env, printCtrl);
1080     if (pd.hDC != oldDC) {
1081         if (oldDC != NULL) {
1082             ::DeleteDC(oldDC);
1083         }
1084         AwtPrintControl::setPrintDC(env, printCtrl, pd.hDC);
1085         newDC = true;
1086     }
1087     // Need to update WPrinterJob with device resolution settings for
1088     // new or changed DC.
1089     setCapabilities(env, printCtrl, pd.hDC);
1090 
1091     HGLOBAL oldG = AwtPrintControl::getPrintHDMode(env, printCtrl);
1092     if (pd.hDevMode != oldG) {
1093         AwtPrintControl::setPrintHDMode(env, printCtrl, pd.hDevMode);
1094     }
1095 
1096     oldG = AwtPrintControl::getPrintHDName(env, printCtrl);
1097     if (pd.hDevNames != oldG) {
1098         AwtPrintControl::setPrintHDName(env, printCtrl, pd.hDevNames);
1099     }
1100 
1101     return newDC;
1102 }
1103 
1104 
1105 BOOL AwtPrintControl::getDevmode( HANDLE hPrinter,
1106                                  LPTSTR printerName,
1107                                  LPDEVMODE *pDevMode) {
1108 
1109     if (hPrinter == NULL || printerName == NULL || pDevMode == NULL) {
1110       return FALSE;
1111     }
1112 
1113     SAVE_CONTROLWORD
1114 
1115     DWORD dwNeeded = ::DocumentProperties(NULL, hPrinter, printerName,
1116                                         NULL, NULL, 0);
1117 
1118     RESTORE_CONTROLWORD
1119 
1120     if (dwNeeded <= 0) {
1121         *pDevMode = NULL;
1122         return FALSE;
1123     }
1124 
1125     *pDevMode = (LPDEVMODE)GlobalAlloc(GPTR, dwNeeded);
1126 
1127     if (*pDevMode == NULL) {
1128         return FALSE;
1129     }
1130 
1131     DWORD dwRet = ::DocumentProperties(NULL,
1132                                        hPrinter,
1133                                        printerName,
1134                                        *pDevMode,
1135                                        NULL,
1136                                        DM_OUT_BUFFER);
1137 
1138     RESTORE_CONTROLWORD
1139 
1140     if (dwRet != IDOK)  {
1141         /* if failure, cleanup and return failure */
1142         GlobalFree(*pDevMode);
1143         *pDevMode = NULL;
1144         return FALSE;
1145     }
1146 
1147     return TRUE;
1148 }