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