1 /*
   2  * Copyright (c) 2000, 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.h"
  27 
  28 #include "stdhdrs.h"
  29 #include <commdlg.h>
  30 #include <winspool.h>
  31 #include <limits.h>
  32 #include <float.h>
  33 
  34 #include "awt_Toolkit.h"
  35 #include "awt_PrintControl.h"
  36 
  37 /* values for parameter "type" of XXX_getJobStatus() */
  38 #define GETJOBCOUNT  1
  39 #define ACCEPTJOB    2
  40 
  41 static const char *HPRINTER_STR = "hPrintJob";
  42 
  43 /* constants for DeviceCapability buffer lengths */
  44 #define PAPERNAME_LENGTH 64
  45 #define TRAYNAME_LENGTH 24
  46 
  47 static BOOL IsSupportedLevel(HANDLE hPrinter, DWORD dwLevel) {
  48     BOOL isSupported = FALSE;
  49     DWORD cbBuf = 0;
  50     LPBYTE pPrinter = NULL;
  51 
  52     DASSERT(hPrinter != NULL);
  53 
  54     VERIFY(::GetPrinter(hPrinter, dwLevel, NULL, 0, &cbBuf) == 0);
  55     if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
  56         pPrinter = new BYTE[cbBuf];
  57         if (::GetPrinter(hPrinter, dwLevel, pPrinter, cbBuf, &cbBuf)) {
  58             isSupported = TRUE;
  59         }
  60         delete[] pPrinter;
  61     }
  62 
  63     return isSupported;
  64 }
  65 
  66 
  67 extern "C" {
  68 
  69 JNIEXPORT jstring JNICALL
  70 Java_sun_print_PrintServiceLookupProvider_getDefaultPrinterName(JNIEnv *env,
  71                                                              jobject peer)
  72 {
  73     TRY;
  74 
  75     TCHAR cBuffer[250];
  76     OSVERSIONINFO osv;
  77     PRINTER_INFO_2 *ppi2 = NULL;
  78     DWORD dwNeeded = 0;
  79     DWORD dwReturned = 0;
  80     LPTSTR pPrinterName = NULL;
  81     jstring jPrinterName;
  82 
  83     // What version of Windows are you running?
  84     osv.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  85     GetVersionEx(&osv);
  86 
  87     // If Windows 2000, XP, Vista
  88     if (osv.dwPlatformId == VER_PLATFORM_WIN32_NT) {
  89 
  90        // Retrieve the default string from Win.ini (the registry).
  91        // String will be in form "printername,drivername,portname".
  92 
  93        if (GetProfileString(TEXT("windows"), TEXT("device"), TEXT(",,,"),
  94                             cBuffer, 250) <= 0) {
  95            return NULL;
  96        }
  97        // Copy printer name into passed-in buffer...
  98        int index = 0;
  99        int len = lstrlen(cBuffer);
 100        while ((index < len) && cBuffer[index] != _T(',')) {
 101               index++;
 102        }
 103        if (index==0) {
 104          return NULL;
 105        }
 106 
 107        pPrinterName = (LPTSTR)GlobalAlloc(GPTR, (index+1)*sizeof(TCHAR));
 108        lstrcpyn(pPrinterName, cBuffer, index+1);
 109        jPrinterName = JNU_NewStringPlatform(env, pPrinterName);
 110        GlobalFree(pPrinterName);
 111        return jPrinterName;
 112     } else {
 113         return NULL;
 114     }
 115 
 116     CATCH_BAD_ALLOC_RET(NULL);
 117 }
 118 
 119 JNIEXPORT jobjectArray JNICALL
 120 Java_sun_print_PrintServiceLookupProvider_getAllPrinterNames(JNIEnv *env,
 121                                                           jobject peer)
 122 {
 123     TRY;
 124 
 125     DWORD cbNeeded = 0;
 126     DWORD cReturned = 0;
 127     LPBYTE pPrinterEnum = NULL;
 128 
 129     jstring utf_str;
 130     jclass clazz = env->FindClass("java/lang/String");
 131     if (clazz == NULL) {
 132         return NULL;
 133     }
 134     jobjectArray nameArray;
 135 
 136     try {
 137         ::EnumPrinters(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS,
 138                        NULL, 4, NULL, 0, &cbNeeded, &cReturned);
 139         pPrinterEnum = new BYTE[cbNeeded];
 140         ::EnumPrinters(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS,
 141                        NULL, 4, pPrinterEnum, cbNeeded, &cbNeeded,
 142                        &cReturned);
 143 
 144         if (cReturned > 0) {
 145             nameArray = env->NewObjectArray(cReturned, clazz, NULL);
 146             if (nameArray == NULL) {
 147                 throw std::bad_alloc();
 148             }
 149         } else {
 150             nameArray = NULL;
 151         }
 152 
 153 
 154         for (DWORD i = 0; i < cReturned; i++) {
 155             PRINTER_INFO_4 *info4 = (PRINTER_INFO_4 *)
 156                 (pPrinterEnum + i * sizeof(PRINTER_INFO_4));
 157             utf_str = JNU_NewStringPlatform(env, info4->pPrinterName);
 158             if (utf_str == NULL) {
 159                 throw std::bad_alloc();
 160             }
 161             env->SetObjectArrayElement(nameArray, i, utf_str);
 162             env->DeleteLocalRef(utf_str);
 163         }
 164     } catch (std::bad_alloc&) {
 165         delete [] pPrinterEnum;
 166         throw;
 167     }
 168 
 169     delete [] pPrinterEnum;
 170     return nameArray;
 171 
 172     CATCH_BAD_ALLOC_RET(NULL);
 173 }
 174 
 175 JNIEXPORT jlong JNICALL
 176 Java_sun_print_PrintServiceLookupProvider_GetRemotePrintersCount(JNIEnv *env,
 177                                                            jobject peer) {
 178     DWORD cbNeeded = 0;
 179     DWORD cReturned = 0;
 180 
 181     ::EnumPrinters(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS,
 182                        NULL, 4, NULL, 0, &cbNeeded, &cReturned);
 183 
 184     return (cbNeeded/sizeof(PRINTER_INFO_4));
 185 }
 186 
 187 JNIEXPORT jfloatArray JNICALL
 188 Java_sun_print_Win32PrintService_getMediaPrintableArea(JNIEnv *env,
 189                                                   jobject peer,
 190                                                   jstring printer,
 191                                                   jint  papersize)
 192 {
 193     TRY;
 194 
 195     LPTSTR printerName = (LPTSTR)JNU_GetStringPlatformChars(env,
 196                                                             printer, NULL);
 197     if (printerName == NULL) {
 198         return NULL;
 199     }
 200 
 201     jfloatArray printableArray = NULL;
 202 
 203     SAVE_CONTROLWORD
 204     HDC pdc = CreateDC(TEXT("WINSPOOL"), printerName, NULL, NULL);
 205     RESTORE_CONTROLWORD
 206     if (pdc) {
 207         HANDLE hPrinter;
 208         /* Start by opening the printer */
 209         if (!::OpenPrinter(printerName, &hPrinter, NULL)) {
 210             JNU_ReleaseStringPlatformChars(env, printer, printerName);
 211             return printableArray;
 212         }
 213 
 214         PDEVMODE pDevMode;
 215 
 216         if (!AwtPrintControl::getDevmode(hPrinter, printerName, &pDevMode)) {
 217             /* if failure, cleanup and return failure */
 218 
 219             if (pDevMode != NULL) {
 220                 ::GlobalFree(pDevMode);
 221             }
 222             DeleteDC(pdc);
 223             ::ClosePrinter(hPrinter);
 224             JNU_ReleaseStringPlatformChars(env, printer, printerName);
 225             return printableArray;
 226         }
 227 
 228         pDevMode->dmFields |= (DM_PAPERSIZE | DM_ORIENTATION);
 229         pDevMode->dmPaperSize = (short)papersize;
 230         pDevMode->dmOrientation = DMORIENT_PORTRAIT;
 231         ::ResetDC(pdc, pDevMode);
 232         RESTORE_CONTROLWORD
 233 
 234         int left = GetDeviceCaps(pdc, PHYSICALOFFSETX);
 235         int top = GetDeviceCaps(pdc, PHYSICALOFFSETY);
 236         int width = GetDeviceCaps(pdc, HORZRES);
 237         int height = GetDeviceCaps(pdc, VERTRES);
 238 
 239         int resx = GetDeviceCaps(pdc, LOGPIXELSX);
 240         int resy = GetDeviceCaps(pdc, LOGPIXELSY);
 241 
 242         printableArray=env->NewFloatArray(4);
 243         if (printableArray != NULL) {
 244             jfloat *iPrintables =
 245                 env->GetFloatArrayElements(printableArray, NULL);
 246             if (iPrintables != NULL) {
 247                 iPrintables[0] = (float)left/resx;
 248                 iPrintables[1] = (float)top/resy;
 249                 iPrintables[2] = (float)width/resx;
 250                 iPrintables[3] = (float)height/resy;
 251                 env->ReleaseFloatArrayElements(printableArray, iPrintables, 0);
 252             }
 253         }
 254         GlobalFree(pDevMode);
 255         DeleteDC(pdc);
 256     }
 257 
 258     JNU_ReleaseStringPlatformChars(env, printer, printerName);
 259 
 260     return printableArray;
 261 
 262     CATCH_BAD_ALLOC_RET(NULL);
 263 }
 264 
 265 jintArray getIDs(JNIEnv *env, jstring printer, jstring port, int dm_id)
 266 {
 267 
 268   LPTSTR printerName = (LPTSTR)JNU_GetStringPlatformChars(env, printer, NULL);
 269   LPTSTR printerPort = (LPTSTR)JNU_GetStringPlatformChars(env, port, NULL);
 270 
 271   if (printerName == NULL || printerPort == NULL) {
 272       if (printerName != NULL) {
 273           JNU_ReleaseStringPlatformChars(env, printer, printerName);
 274       }
 275       if (printerPort != NULL) {
 276           JNU_ReleaseStringPlatformChars(env, port, printerPort);
 277       }
 278       return NULL;
 279   }
 280 
 281   SAVE_CONTROLWORD
 282   int numIDs = ::DeviceCapabilities(printerName, printerPort, dm_id,
 283                                     NULL, NULL);
 284   RESTORE_CONTROLWORD
 285 
 286   jintArray idArray = NULL;
 287   if (numIDs > 0) {
 288       idArray = env->NewIntArray(numIDs);
 289       if (idArray != NULL) {
 290           jint *jpcIndices = env->GetIntArrayElements(idArray, NULL);
 291           if (jpcIndices != NULL) {
 292               jint *saveFormats = jpcIndices;
 293               LPTSTR buf = NULL;
 294               try {
 295                   buf = (LPTSTR)new char[numIDs * sizeof(WORD)];
 296               } catch (std::bad_alloc&) {
 297                   buf = NULL;
 298               }
 299               if (buf != NULL) {
 300                   if (::DeviceCapabilities(printerName, printerPort,
 301                                            dm_id, buf, NULL) != -1) {
 302                       WORD *id = (WORD *)buf;
 303                       for (int i = 0; i < numIDs; i++, id++) {
 304                           jpcIndices[i] = *id;
 305                       }
 306                   }
 307                   RESTORE_CONTROLWORD
 308                   delete[] buf;
 309               }
 310               env->ReleaseIntArrayElements(idArray, saveFormats, 0);
 311           }
 312       }
 313   }
 314 
 315   JNU_ReleaseStringPlatformChars(env, printer, printerName);
 316   JNU_ReleaseStringPlatformChars(env, port, printerPort);
 317   return idArray;
 318 }
 319 
 320 JNIEXPORT jintArray JNICALL
 321 Java_sun_print_Win32PrintService_getAllMediaIDs(JNIEnv *env,
 322                                                 jobject peer,
 323                                                 jstring printer,
 324                                                 jstring port)
 325 {
 326     return getIDs(env, printer, port, DC_PAPERS);
 327 }
 328 
 329 
 330 JNIEXPORT jintArray JNICALL
 331 Java_sun_print_Win32PrintService_getAllMediaTrays(JNIEnv *env,
 332                                                   jobject peer,
 333                                                   jstring printer,
 334                                                   jstring port)
 335 {
 336     return getIDs(env, printer, port, DC_BINS);
 337 }
 338 
 339 
 340 JNIEXPORT jintArray JNICALL
 341 Java_sun_print_Win32PrintService_getAllMediaSizes(JNIEnv *env,
 342                                                   jobject peer,
 343                                                   jstring printer,
 344                                                   jstring port)
 345 {
 346   LPTSTR printerName = (LPTSTR)JNU_GetStringPlatformChars(env, printer, NULL);
 347   LPTSTR printerPort = (LPTSTR)JNU_GetStringPlatformChars(env, port, NULL);
 348 
 349   if (printerName == NULL || printerPort == NULL) {
 350       if (printerName != NULL) {
 351           JNU_ReleaseStringPlatformChars(env, printer, printerName);
 352       }
 353       if (printerPort != NULL) {
 354           JNU_ReleaseStringPlatformChars(env, port, printerPort);
 355       }
 356       return NULL;
 357   }
 358 
 359   SAVE_CONTROLWORD
 360   int nPapers = ::DeviceCapabilities(printerName, printerPort, DC_PAPERSIZE,
 361                                      NULL, NULL) ;
 362   RESTORE_CONTROLWORD
 363 
 364   jintArray mediaArray = NULL;
 365   jint *saveFormats = NULL;
 366 
 367   if (nPapers > 0) {
 368       mediaArray = env->NewIntArray(nPapers*2);
 369       if (mediaArray != NULL) {
 370           jint *jpcIndices = env->GetIntArrayElements(mediaArray, NULL);
 371           if (jpcIndices != NULL) {
 372               saveFormats = jpcIndices;
 373               LPTSTR buf = NULL;
 374               try {
 375                   buf = (LPTSTR)new char[nPapers * sizeof(POINT)];
 376               } catch (std::bad_alloc&) {
 377                   buf = NULL;
 378               }
 379               if (buf != NULL) {
 380                   if (::DeviceCapabilities(printerName, printerPort,
 381                                            DC_PAPERSIZE, buf, NULL) != -1) {
 382                       POINT *pDim = (POINT *)buf;
 383                       for (int i = 0; i < nPapers; i++) {
 384                           jpcIndices[i*2] = (pDim+i)->x;
 385                           jpcIndices[i*2+1] = (pDim+i)->y;
 386                       }
 387                   }
 388                   RESTORE_CONTROLWORD
 389                   delete[] buf;
 390               }
 391               env->ReleaseIntArrayElements(mediaArray, saveFormats, 0);
 392               saveFormats = NULL;
 393           }
 394       }
 395   }
 396 
 397   JNU_ReleaseStringPlatformChars(env, printer, printerName);
 398   JNU_ReleaseStringPlatformChars(env, port, printerPort);
 399   if (mediaArray != NULL && saveFormats != NULL) {
 400       env->ReleaseIntArrayElements(mediaArray, saveFormats, 0);
 401   }
 402   return mediaArray;
 403 
 404 }
 405 
 406 
 407 jobjectArray getAllDCNames(JNIEnv *env, jobject peer, jstring printer,
 408                  jstring port, unsigned int dc_id, unsigned int buf_len)
 409 {
 410 
 411   LPTSTR printerName = (LPTSTR)JNU_GetStringPlatformChars(env, printer, NULL);
 412   LPTSTR printerPort = (LPTSTR)JNU_GetStringPlatformChars(env, port, NULL);
 413 
 414   if (printerName == NULL || printerPort == NULL) {
 415       if (printerName != NULL) {
 416           JNU_ReleaseStringPlatformChars(env, printer, printerName);
 417       }
 418       if (printerPort != NULL) {
 419           JNU_ReleaseStringPlatformChars(env, port, printerPort);
 420       }
 421       return NULL;
 422   }
 423 
 424   jstring utf_str;
 425   jobjectArray names = NULL;
 426   LPTSTR buf = NULL;
 427   SAVE_CONTROLWORD
 428   int cReturned = ::DeviceCapabilities(printerName, printerPort,
 429                                          dc_id, NULL, NULL);
 430   RESTORE_CONTROLWORD
 431   if (cReturned <= 0) {
 432       JNU_ReleaseStringPlatformChars(env, printer, printerName);
 433       JNU_ReleaseStringPlatformChars(env, port, printerPort);
 434       return NULL;
 435   }
 436 
 437   try {
 438       buf = (LPTSTR)new char[cReturned * buf_len * sizeof(TCHAR)];
 439   } catch (std::bad_alloc&) {
 440       buf = NULL;
 441   }
 442   if (buf == NULL) {
 443       JNU_ReleaseStringPlatformChars(env, printer, printerName);
 444       JNU_ReleaseStringPlatformChars(env, port, printerPort);
 445       JNU_ThrowOutOfMemoryError(env, "OutOfMemoryError");
 446      return NULL;
 447   }
 448 
 449   cReturned = ::DeviceCapabilities(printerName, printerPort,
 450                                    dc_id, buf, NULL);
 451   RESTORE_CONTROLWORD
 452 
 453   JNU_ReleaseStringPlatformChars(env, printer, printerName);
 454   JNU_ReleaseStringPlatformChars(env, port, printerPort);
 455 
 456   if (cReturned > 0) {
 457       jclass cls = env->FindClass("java/lang/String");
 458       if (cls != NULL) {
 459           names = env->NewObjectArray(cReturned, cls, NULL);
 460       }
 461       if (names == NULL || cls == NULL) {
 462           delete[] buf;
 463           return names;
 464       }
 465 
 466       for (int i = 0; i < cReturned; i++) {
 467           utf_str = JNU_NewStringPlatform(env, buf+(buf_len*i));
 468             if (utf_str == NULL) {
 469                 delete[] buf;
 470                 return names;
 471             }
 472             env->SetObjectArrayElement(names, i, utf_str);
 473             env->DeleteLocalRef(utf_str);
 474         }
 475     }
 476     delete[] buf;
 477     return names;
 478 
 479 }
 480 
 481 
 482 JNIEXPORT jobjectArray JNICALL
 483 Java_sun_print_Win32PrintService_getAllMediaNames(JNIEnv *env,
 484                                                   jobject peer,
 485                                                   jstring printer,
 486                                                   jstring port)
 487 {
 488   return getAllDCNames(env, peer, printer, port, DC_PAPERNAMES, PAPERNAME_LENGTH);
 489 }
 490 
 491 
 492 JNIEXPORT jobjectArray JNICALL
 493 Java_sun_print_Win32PrintService_getAllMediaTrayNames(JNIEnv *env,
 494                                                   jobject peer,
 495                                                   jstring printer,
 496                                                   jstring port)
 497 {
 498   return getAllDCNames(env, peer, printer, port, DC_BINNAMES, TRAYNAME_LENGTH);
 499 }
 500 
 501 
 502 JNIEXPORT jint JNICALL
 503 Java_sun_print_Win32PrintService_getCopiesSupported(JNIEnv *env,
 504                                                     jobject peer,
 505                                                     jstring printer,
 506                                                     jstring port)
 507 {
 508   LPTSTR printerName = (LPTSTR)JNU_GetStringPlatformChars(env, printer, NULL);
 509   LPTSTR printerPort = (LPTSTR)JNU_GetStringPlatformChars(env, port, NULL);
 510 
 511   if (printerName == NULL || printerPort == NULL) {
 512       if (printerName != NULL) {
 513           JNU_ReleaseStringPlatformChars(env, printer, printerName);
 514       }
 515       if (printerPort != NULL) {
 516           JNU_ReleaseStringPlatformChars(env, port, printerPort);
 517       }
 518       return 1;
 519   }
 520 
 521   SAVE_CONTROLWORD
 522   int numCopies = ::DeviceCapabilities(printerName, printerPort,
 523                                        DC_COPIES,   NULL, NULL);
 524   RESTORE_CONTROLWORD
 525 
 526   if (numCopies == -1)
 527     return 1; // default
 528 
 529   JNU_ReleaseStringPlatformChars(env, printer, printerName);
 530   JNU_ReleaseStringPlatformChars(env, port, printerPort);
 531 
 532   return numCopies;
 533 }
 534 
 535 
 536 /*
 537 PostScript Drivers return wrong support info for the following code:
 538 
 539  DWORD dmFields = (::DeviceCapabilities(printerName,
 540                                          NULL, DC_FIELDS,   NULL, NULL)) ;
 541 
 542   if ((dmFields & DM_YRESOLUTION) )
 543     isSupported = true;
 544 
 545 Returns not supported even if it supports resolution. Therefore, we use the
 546 function _getAllResolutions.
 547 */
 548 JNIEXPORT jintArray JNICALL
 549 Java_sun_print_Win32PrintService_getAllResolutions(JNIEnv *env,
 550                                                    jobject peer,
 551                                                    jstring printer,
 552                                                    jstring port)
 553 {
 554   LPTSTR printerName = (LPTSTR)JNU_GetStringPlatformChars(env, printer, NULL);
 555   LPTSTR printerPort = (LPTSTR)JNU_GetStringPlatformChars(env, port, NULL);
 556 
 557  if (printerName == NULL || printerPort == NULL) {
 558       if (printerName != NULL) {
 559           JNU_ReleaseStringPlatformChars(env, printer, printerName);
 560       }
 561       if (printerPort != NULL) {
 562           JNU_ReleaseStringPlatformChars(env, port, printerPort);
 563       }
 564       return NULL;
 565   }
 566 
 567   SAVE_CONTROLWORD
 568   int nResolutions = ::DeviceCapabilities(printerName, printerPort,
 569                                           DC_ENUMRESOLUTIONS, NULL, NULL);
 570   RESTORE_CONTROLWORD
 571 
 572   jintArray resolutionArray = NULL;
 573   if (nResolutions > 0) {
 574     resolutionArray = env->NewIntArray(nResolutions*2);
 575     if (resolutionArray != NULL) {
 576         jint *jpcIndices = env->GetIntArrayElements(resolutionArray, NULL);
 577         if (jpcIndices != NULL) {
 578             jint *saveFormats = jpcIndices;
 579             LPTSTR resBuf = NULL;
 580             try {
 581                 resBuf = (LPTSTR)new char[nResolutions * sizeof(LONG) * 2];
 582             } catch (std::bad_alloc&) {
 583                 resBuf = NULL;
 584             }
 585             if (resBuf != NULL) {
 586                 if (::DeviceCapabilities(printerName, printerPort,
 587                                          DC_ENUMRESOLUTIONS, resBuf,
 588                                          NULL) != -1) {
 589                     LONG *pResolution = (LONG *)resBuf;
 590                     for (int i = 0; i < nResolutions; i++) {
 591                         jpcIndices[i*2] = *pResolution++;
 592                         jpcIndices[i*2+1] = *pResolution++;
 593                     }
 594                 }
 595                 RESTORE_CONTROLWORD
 596                 delete[] resBuf;
 597             }
 598             env->ReleaseIntArrayElements(resolutionArray, saveFormats, 0);
 599         }
 600     }
 601   }
 602 
 603   JNU_ReleaseStringPlatformChars(env, printer, printerName);
 604   JNU_ReleaseStringPlatformChars(env, printer, printerPort);
 605   return resolutionArray;
 606 }
 607 
 608 
 609 static BOOL IsDCPostscript( HDC hDC )
 610 {
 611     int         nEscapeCode;
 612     CHAR        szTechnology[MAX_PATH] = "";
 613 
 614     // If it supports POSTSCRIPT_PASSTHROUGH, it must be PS.
 615     nEscapeCode = POSTSCRIPT_PASSTHROUGH;
 616     if( ::ExtEscape( hDC, QUERYESCSUPPORT, sizeof(int),
 617                      (LPCSTR)&nEscapeCode, 0, NULL ) > 0 )
 618         return TRUE;
 619 
 620     // If it doesn't support GETTECHNOLOGY, we won't be able to tell.
 621     nEscapeCode = GETTECHNOLOGY;
 622     if( ::ExtEscape( hDC, QUERYESCSUPPORT, sizeof(int),
 623                      (LPCSTR)&nEscapeCode, 0, NULL ) <= 0 )
 624         return FALSE;
 625 
 626     // Get the technology string and check if the word "postscript" is in it.
 627     if( ::ExtEscape( hDC, GETTECHNOLOGY, 0, NULL, MAX_PATH,
 628                      (LPSTR)szTechnology ) <= 0 )
 629         return FALSE;
 630     _strupr_s(szTechnology, MAX_PATH);
 631     if(!strstr( szTechnology, "POSTSCRIPT" ) == NULL )
 632         return TRUE;
 633 
 634     // The word "postscript" was not found and it didn't support
 635     //   POSTSCRIPT_PASSTHROUGH, so it's not a PS printer.
 636         return FALSE;
 637 }
 638 
 639 
 640 JNIEXPORT jstring JNICALL
 641 Java_sun_print_Win32PrintService_getPrinterPort(JNIEnv *env,
 642                                                 jobject peer,
 643                                                 jstring printer)
 644 {
 645 
 646   if (printer == NULL) {
 647     return NULL;
 648   }
 649 
 650   jstring jPort;
 651   LPTSTR printerName = NULL, printerPort = TEXT("LPT1");
 652   LPBYTE buffer = NULL;
 653   DWORD cbBuf = 0;
 654 
 655   try {
 656     VERIFY(AwtPrintControl::FindPrinter(NULL, NULL, &cbBuf, NULL, NULL));
 657     buffer = new BYTE[cbBuf];
 658     AwtPrintControl::FindPrinter(printer, buffer, &cbBuf,
 659                                       &printerName, &printerPort);
 660   } catch (std::bad_alloc&) {
 661     delete [] buffer;
 662     JNU_ThrowOutOfMemoryError(env, "OutOfMemoryError");
 663     return NULL;
 664   }
 665 
 666   if (printerPort == NULL) {
 667     printerPort = TEXT("LPT1");
 668   }
 669   jPort = JNU_NewStringPlatform(env, printerPort);
 670   delete [] buffer;
 671   return jPort;
 672 
 673 }
 674 
 675 
 676 JNIEXPORT jint JNICALL
 677 Java_sun_print_Win32PrintService_getCapabilities(JNIEnv *env,
 678                                                  jobject peer,
 679                                                  jstring printer,
 680                                                  jstring port)
 681 {
 682   LPTSTR printerName = (LPTSTR)JNU_GetStringPlatformChars(env, printer, NULL);
 683   LPTSTR printerPort = (LPTSTR)JNU_GetStringPlatformChars(env, port, NULL);
 684 
 685   if (printerName == NULL || printerPort == NULL) {
 686       if (printerName != NULL) {
 687           JNU_ReleaseStringPlatformChars(env, printer, printerName);
 688       }
 689       if (printerPort != NULL) {
 690           JNU_ReleaseStringPlatformChars(env, port, printerPort);
 691       }
 692       return NULL;
 693   }
 694 
 695   // 0x1000 is a flag to indicate that getCapabilities has already been called.
 696   // 0x0001 is a flag for color support and supported is the default.
 697   jint ret = 0x1001;
 698   DWORD dmFields;
 699 
 700   // get Duplex
 701   SAVE_CONTROLWORD
 702   DWORD isDuplex = (::DeviceCapabilities(printerName, printerPort,
 703                                          DC_DUPLEX,   NULL, NULL)) ;
 704 
 705   /*
 706     Check if duplexer is installed either physically or manually thru the
 707     printer setting dialog by checking if DM_DUPLEX is set.
 708   */
 709   dmFields = (::DeviceCapabilities(printerName, printerPort,
 710                                    DC_FIELDS,   NULL, NULL)) ;
 711 
 712   if ((dmFields & DM_DUPLEX) && isDuplex) {
 713       ret |= 0x0002;
 714   }
 715 
 716   // get Collation
 717   if ((dmFields & DM_COLLATE) ) {
 718       ret |= 0x0004;
 719   }
 720 
 721   // get Print Quality
 722   if ((dmFields & DM_PRINTQUALITY) ) {
 723       ret |= 0x0008;
 724   }
 725 
 726   HDC pdc = CreateDC(TEXT("WINSPOOL"), printerName, NULL, NULL);
 727   if (pdc != NULL) {
 728       // get Color
 729       int bpp = GetDeviceCaps(pdc, BITSPIXEL);
 730       int nColors = GetDeviceCaps(pdc, NUMCOLORS);
 731 
 732       if (!(dmFields & DM_COLOR) || ((bpp == 1)
 733                                      && ((nColors == 2) || (nColors == 256)))) {
 734           ret &= ~0x0001;
 735       }
 736 
 737       // check support for PostScript
 738       if (IsDCPostscript(pdc)) {
 739             ret |= 0x0010;
 740       }
 741 
 742       DeleteDC(pdc);
 743   }
 744 
 745   RESTORE_CONTROLWORD
 746   JNU_ReleaseStringPlatformChars(env, printer, printerName);
 747   JNU_ReleaseStringPlatformChars(env, printer, printerPort);
 748   return ret;
 749 }
 750 
 751 
 752 #define GETDEFAULT_ERROR        -50
 753 #define NDEFAULT 9
 754 
 755 JNIEXPORT jintArray JNICALL
 756 Java_sun_print_Win32PrintService_getDefaultSettings(JNIEnv *env,
 757                                                     jobject peer,
 758                                                     jstring printer,
 759                                                     jstring port)
 760 {
 761   HANDLE      hPrinter;
 762   LPDEVMODE   pDevMode = NULL;
 763 
 764   LPTSTR printerName = (LPTSTR)JNU_GetStringPlatformChars(env, printer, NULL);
 765   LPTSTR printerPort = (LPTSTR)JNU_GetStringPlatformChars(env, port, NULL);
 766 
 767   if (printerName == NULL || printerPort == NULL) {
 768       if (printerName != NULL) {
 769           JNU_ReleaseStringPlatformChars(env, printer, printerName);
 770       }
 771       if (printerPort != NULL) {
 772           JNU_ReleaseStringPlatformChars(env, port, printerPort);
 773       }
 774       return NULL;
 775   }
 776 
 777   jint* defIndices = NULL;
 778   jintArray defaultArray = env->NewIntArray(NDEFAULT);
 779   if (defaultArray != NULL) {
 780       defIndices = env->GetIntArrayElements(defaultArray, NULL);
 781   }
 782   if (defIndices == NULL) {
 783       JNU_ReleaseStringPlatformChars(env, printer, printerName);
 784       JNU_ReleaseStringPlatformChars(env, port, printerPort);
 785       return NULL;
 786   }
 787 
 788   jint *saveFormats = defIndices;
 789 
 790   for (int i=0; i < NDEFAULT; i++) {
 791       defIndices[i] = GETDEFAULT_ERROR;
 792   }
 793 
 794   /* Start by opening the printer */
 795   if (!::OpenPrinter(printerName, &hPrinter, NULL)) {
 796       env->ReleaseIntArrayElements(defaultArray, saveFormats, 0);
 797       JNU_ReleaseStringPlatformChars(env, printer, printerName);
 798       JNU_ReleaseStringPlatformChars(env, port, printerPort);
 799       return defaultArray;
 800   }
 801 
 802   if (!AwtPrintControl::getDevmode(hPrinter, printerName, &pDevMode)) {
 803       /* if failure, cleanup and return failure */
 804       if (pDevMode != NULL) {
 805           ::GlobalFree(pDevMode);
 806       }
 807       ::ClosePrinter(hPrinter);
 808       env->ReleaseIntArrayElements(defaultArray, saveFormats, 0);
 809       JNU_ReleaseStringPlatformChars(env, printer, printerName);
 810       JNU_ReleaseStringPlatformChars(env, port, printerPort);
 811       return defaultArray;
 812   }
 813 
 814   /* Have seen one driver which reports a default paper id which is not
 815    * one of their supported paper ids. If what is returned is not
 816    * a supported paper, use one of the supported sizes instead.
 817    *
 818    */
 819   if (pDevMode->dmFields & DM_PAPERSIZE) {
 820       defIndices[0] = pDevMode->dmPaperSize;
 821 
 822       SAVE_CONTROLWORD
 823 
 824       int numSizes = ::DeviceCapabilities(printerName, printerPort,
 825                                           DC_PAPERS, NULL, NULL);
 826       if (numSizes > 0) {
 827           LPTSTR papers = (LPTSTR)SAFE_SIZE_ARRAY_ALLOC(safe_Malloc, numSizes, sizeof(WORD));
 828           if (papers != NULL &&
 829               ::DeviceCapabilities(printerName, printerPort,
 830                                    DC_PAPERS, papers, NULL) != -1) {
 831               int present = 0;
 832               for (int i=0;i<numSizes;i++) {
 833                   if (papers[i] == pDevMode->dmPaperSize) {
 834                       present = 1;
 835                   }
 836               }
 837               if (!present) {
 838                   defIndices[0] = papers[0];
 839               }
 840               if (papers != NULL) {
 841                   free((char*)papers);
 842               }
 843           }
 844       }
 845       RESTORE_CONTROLWORD
 846   }
 847 
 848   if (pDevMode->dmFields & DM_MEDIATYPE) {
 849       defIndices[1] = pDevMode->dmMediaType;
 850   }
 851 
 852   /*
 853    * For some printer like Brother HL-2240D series
 854    * pDevMode->dmYResolution is not set in pDevMode->dmFields
 855    * even though pDevMode->dmYResolution is populated
 856    * via ::DocumentProperties API, so for this case
 857    * we populate the resolution index in default array
 858    */
 859   if (pDevMode->dmFields & DM_YRESOLUTION || pDevMode->dmYResolution > 0) {
 860       defIndices[2]  = pDevMode->dmYResolution;
 861   }
 862 
 863   /*
 864    * For some printer like Brother HL-2240D series
 865    * pDevMode->dmPrintQuality is not set in pDevMode->dmFields
 866    * even though pDevMode->dmPrintQuality is populated
 867    * via ::DocumentProperties API, so for this case
 868    * we populate the print quality index in default array
 869    */
 870   if (pDevMode->dmFields & DM_PRINTQUALITY || pDevMode->dmPrintQuality != 0) {
 871       defIndices[3] = pDevMode->dmPrintQuality;
 872   }
 873 
 874   if (pDevMode->dmFields & DM_COPIES) {
 875       defIndices[4] = pDevMode->dmCopies;
 876   }
 877 
 878   if (pDevMode->dmFields & DM_ORIENTATION) {
 879       defIndices[5] = pDevMode->dmOrientation;
 880   }
 881 
 882   if (pDevMode->dmFields & DM_DUPLEX) {
 883       defIndices[6] = pDevMode->dmDuplex;
 884   }
 885 
 886   if (pDevMode->dmFields & DM_COLLATE) {
 887       defIndices[7] = pDevMode->dmCollate;
 888   }
 889 
 890   if (pDevMode->dmFields & DM_COLOR) {
 891       defIndices[8] = pDevMode->dmColor;
 892   }
 893 
 894   GlobalFree(pDevMode);
 895   ::ClosePrinter(hPrinter);
 896 
 897   env->ReleaseIntArrayElements(defaultArray, saveFormats, 0);
 898 
 899   JNU_ReleaseStringPlatformChars(env, printer, printerName);
 900   JNU_ReleaseStringPlatformChars(env, port, printerPort);
 901 
 902   return defaultArray;
 903 }
 904 
 905 
 906 JNIEXPORT jint JNICALL
 907 Java_sun_print_Win32PrintService_getJobStatus(JNIEnv *env,
 908                                           jobject peer,
 909                                           jstring printer,
 910                                           jint type)
 911 {
 912     HANDLE hPrinter;
 913     DWORD  cByteNeeded;
 914     DWORD  cByteUsed;
 915     PRINTER_INFO_2 *pPrinterInfo = NULL;
 916     int ret=0;
 917 
 918     LPTSTR printerName = (LPTSTR)JNU_GetStringPlatformChars(env, printer, NULL);
 919     if (printerName == NULL) {
 920         return -1;
 921     }
 922 
 923     // Start by opening the printer
 924     if (!::OpenPrinter(printerName, &hPrinter, NULL)) {
 925         JNU_ReleaseStringPlatformChars(env, printer, printerName);
 926         return -1;
 927     }
 928 
 929     if (!::GetPrinter(hPrinter, 2, NULL, 0, &cByteNeeded)) {
 930         if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
 931             ::ClosePrinter(hPrinter);
 932             JNU_ReleaseStringPlatformChars(env, printer, printerName);
 933             return -1;
 934         }
 935     }
 936 
 937     pPrinterInfo = (PRINTER_INFO_2 *)::GlobalAlloc(GPTR, cByteNeeded);
 938     if (!(pPrinterInfo)) {
 939         /* failure to allocate memory */
 940         ::ClosePrinter(hPrinter);
 941         JNU_ReleaseStringPlatformChars(env, printer, printerName);
 942         return -1;
 943     }
 944 
 945     /* get the printer info */
 946     if (!::GetPrinter(hPrinter,
 947                       2,
 948                       (LPBYTE)pPrinterInfo,
 949                       cByteNeeded,
 950                       &cByteUsed))
 951         {
 952             /* failure to access the printer */
 953             ::GlobalFree(pPrinterInfo);
 954             pPrinterInfo = NULL;
 955             ::ClosePrinter(hPrinter);
 956             JNU_ReleaseStringPlatformChars(env, printer, printerName);
 957             return -1;
 958         }
 959 
 960     if (type == GETJOBCOUNT) {
 961         ret = pPrinterInfo->cJobs;
 962     } else if (type == ACCEPTJOB) {
 963         if (pPrinterInfo->Status & PRINTER_STATUS_PENDING_DELETION) {
 964             ret = 0;
 965         }
 966         else {
 967             ret = 1;
 968         }
 969     }
 970 
 971     ::GlobalFree(pPrinterInfo);
 972     ::ClosePrinter(hPrinter);
 973     JNU_ReleaseStringPlatformChars(env, printer, printerName);
 974     return ret;
 975 }
 976 
 977 
 978 static jfieldID getIdOfLongField(JNIEnv *env, jobject self,
 979                                  const char *fieldName) {
 980   jclass myClass = env->GetObjectClass(self);
 981   jfieldID fieldId = env->GetFieldID(myClass, fieldName, "J");
 982   DASSERT(fieldId != 0);
 983   return fieldId;
 984 }
 985 
 986 
 987 static inline HANDLE getHPrinter(JNIEnv *env, jobject self) {
 988   jfieldID fieldId = getIdOfLongField(env, self, HPRINTER_STR);
 989   if (fieldId == (jfieldID)0) {
 990       return (HANDLE)NULL;
 991   }
 992   return (HANDLE)(env->GetLongField(self, fieldId));
 993 }
 994 
 995 
 996 JNIEXPORT jboolean JNICALL
 997 Java_sun_print_Win32PrintJob_startPrintRawData(JNIEnv *env,
 998                                                jobject peer,
 999                                                jstring printer,
1000                                                jstring jobname)
1001 {
1002   HANDLE      hPrinter;
1003   DOC_INFO_1  DocInfo;
1004   LPTSTR printerName = (LPTSTR)JNU_GetStringPlatformChars(env, printer, NULL);
1005   if (printerName == NULL) {
1006       return false;
1007   }
1008   DASSERT(jobname != NULL);
1009   LPTSTR lpJobName = (LPTSTR)JNU_GetStringPlatformChars(env, jobname, NULL);
1010   LPTSTR jname = _tcsdup(lpJobName);
1011   JNU_ReleaseStringPlatformChars(env, jobname, lpJobName);
1012 
1013   // Start by opening the printer
1014   if (!::OpenPrinter(printerName, &hPrinter, NULL)) {
1015     JNU_ReleaseStringPlatformChars(env, printer, printerName);
1016     free((LPTSTR)jname);
1017     return false;
1018   }
1019 
1020   JNU_ReleaseStringPlatformChars(env, printer, printerName);
1021 
1022   // Fill in the structure with info about this "document."
1023   DocInfo.pDocName = jname;
1024   DocInfo.pOutputFile = NULL;
1025   DocInfo.pDatatype = TEXT("RAW");
1026 
1027   // Inform the spooler the document is beginning.
1028   if( (::StartDocPrinter(hPrinter, 1, (LPBYTE)&DocInfo)) == 0 ) {
1029     ::ClosePrinter( hPrinter );
1030     free((LPTSTR)jname);
1031     return false;
1032   }
1033 
1034   free((LPTSTR)jname);
1035 
1036   // Start a page.
1037   if( ! ::StartPagePrinter( hPrinter ) ) {
1038     ::EndDocPrinter( hPrinter );
1039     ::ClosePrinter( hPrinter );
1040     return false;
1041   }
1042 
1043   // store handle
1044   jfieldID fieldId = getIdOfLongField(env, peer, HPRINTER_STR);
1045   if (fieldId == (jfieldID)0) {
1046       return false;
1047   } else {
1048       env->SetLongField(peer, fieldId, reinterpret_cast<jlong>(hPrinter));
1049       return true;
1050   }
1051 }
1052 
1053 
1054 JNIEXPORT jboolean JNICALL
1055 Java_sun_print_Win32PrintJob_printRawData(JNIEnv *env,
1056                                           jobject peer,
1057                                           jbyteArray dataArray,
1058                                           jint count)
1059 {
1060   jboolean  ret=true;
1061   jint      dwBytesWritten;
1062   jbyte*    data = NULL;
1063 
1064   // retrieve handle
1065   HANDLE    hPrinter = getHPrinter(env, peer);
1066   if (hPrinter == NULL) {
1067     return false;
1068   }
1069 
1070   try {
1071     data=(jbyte *)env->GetPrimitiveArrayCritical(dataArray, 0);
1072     if (data == NULL) {
1073         return false;
1074     }
1075 
1076     // Send the data to the printer.
1077     if( ! ::WritePrinter(hPrinter, data, count,(LPDWORD)&dwBytesWritten)) {
1078       env->ReleasePrimitiveArrayCritical(dataArray, data, 0);
1079       return false;
1080     }
1081 
1082     // Check to see if correct number of bytes were written.
1083     if( dwBytesWritten != count ) {
1084       ret = false;
1085     }
1086 
1087   } catch (...) {
1088     if (data != NULL) {
1089       env->ReleasePrimitiveArrayCritical(dataArray, data, 0);
1090     }
1091     JNU_ThrowInternalError(env, "Problem in Win32PrintJob_printRawData");
1092     return false;
1093   }
1094 
1095   env->ReleasePrimitiveArrayCritical(dataArray, data, 0);
1096   return ret;
1097 }
1098 
1099 
1100 JNIEXPORT jboolean JNICALL
1101 Java_sun_print_Win32PrintJob_endPrintRawData(JNIEnv *env,
1102                                           jobject peer)
1103 {
1104   // retrieve handle
1105   HANDLE hPrinter = getHPrinter(env, peer);
1106   if (hPrinter == NULL) {
1107     return false;
1108   }
1109 
1110   if ((::EndPagePrinter(hPrinter) != 0) &&
1111       (::EndDocPrinter(hPrinter) != 0) &&
1112       (::ClosePrinter(hPrinter) != 0)) {
1113     return true;
1114   } else {
1115     return false;
1116   }
1117 }
1118 
1119 } /* extern "C" */