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