1 /*
   2  * Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 #include "awt.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_PrintServiceLookupProvider_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 static jobjectArray getPrinterNames(JNIEnv *env, DWORD flags) {
 122     TRY;
 123 
 124     DWORD cbNeeded = 0;
 125     DWORD cReturned = 0;
 126     LPBYTE pPrinterEnum = NULL;
 127 
 128     jstring utf_str;
 129     jclass clazz = env->FindClass("java/lang/String");
 130     if (clazz == NULL) {
 131         return NULL;
 132     }
 133     jobjectArray nameArray;
 134 
 135     try {
 136         ::EnumPrinters(flags,
 137                        NULL, 4, NULL, 0, &cbNeeded, &cReturned);
 138         pPrinterEnum = new BYTE[cbNeeded];
 139         ::EnumPrinters(flags,
 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 JNIEXPORT jobjectArray JNICALL
 175 Java_sun_print_PrintServiceLookupProvider_getAllPrinterNames(JNIEnv *env,
 176                                                              jobject peer)
 177 {
 178     return getPrinterNames(env, PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS);
 179 }
 180 
 181 JNIEXPORT jobjectArray JNICALL
 182 Java_sun_print_PrintServiceLookupProvider_getRemotePrintersNames(JNIEnv *env,
 183                                                                  jobject peer)
 184 {
 185     return getPrinterNames(env, PRINTER_ENUM_CONNECTIONS);
 186 }
 187 
 188 
 189 JNIEXPORT jlong JNICALL
 190 Java_sun_print_PrintServiceLookupProvider_notifyFirstPrinterChange(JNIEnv *env,
 191                                                                 jobject peer,
 192                                                                 jstring printer) {
 193     HANDLE hPrinter;
 194 
 195     LPTSTR printerName = NULL;
 196     if (printer != NULL) {
 197         printerName = (LPTSTR)JNU_GetStringPlatformChars(env,
 198                                                          printer,
 199                                                          NULL);
 200         JNU_ReleaseStringPlatformChars(env, printer, printerName);
 201     }
 202 
 203     // printerName - "Win NT/2K/XP: If NULL, it indicates the local printer
 204     // server" - MSDN.   Win9x : OpenPrinter returns 0.
 205     BOOL ret = OpenPrinter(printerName, &hPrinter, NULL);
 206     if (!ret) {
 207       return (jlong)-1;
 208     }
 209 
 210     // PRINTER_CHANGE_PRINTER = PRINTER_CHANGE_ADD_PRINTER |
 211     //                          PRINTER_CHANGE_SET_PRINTER |
 212     //                          PRINTER_CHANGE_DELETE_PRINTER |
 213     //                          PRINTER_CHANGE_FAILED_CONNECTION_PRINTER
 214     HANDLE chgObj = FindFirstPrinterChangeNotification(hPrinter,
 215                                                        PRINTER_CHANGE_PRINTER,
 216                                                        0,
 217                                                        NULL);
 218     return (chgObj == INVALID_HANDLE_VALUE) ? (jlong)-1 : (jlong)chgObj;
 219 }
 220 
 221 
 222 
 223 JNIEXPORT void JNICALL
 224 Java_sun_print_PrintServiceLookupProvider_notifyClosePrinterChange(JNIEnv *env,
 225                                                                 jobject peer,
 226                                                                 jlong chgObject) {
 227     FindClosePrinterChangeNotification((HANDLE)chgObject);
 228 }
 229 
 230 
 231 JNIEXPORT jint JNICALL
 232 Java_sun_print_PrintServiceLookupProvider_notifyPrinterChange(JNIEnv *env,
 233                                                            jobject peer,
 234                                                            jlong chgObject) {
 235     DWORD dwChange;
 236 
 237     DWORD ret = WaitForSingleObject((HANDLE)chgObject, INFINITE);
 238     if (ret == WAIT_OBJECT_0) {
 239         return(FindNextPrinterChangeNotification((HANDLE)chgObject,
 240                                                   &dwChange, NULL, NULL));
 241     } else {
 242         return 0;
 243     }
 244 }
 245 
 246 
 247 JNIEXPORT jfloatArray JNICALL
 248 Java_sun_print_Win32PrintService_getMediaPrintableArea(JNIEnv *env,
 249                                                   jobject peer,
 250                                                   jstring printer,
 251                                                   jint  papersize)
 252 {
 253     TRY;
 254 
 255     LPTSTR printerName = (LPTSTR)JNU_GetStringPlatformChars(env,
 256                                                             printer, NULL);
 257     if (printerName == NULL) {
 258         return NULL;
 259     }
 260 
 261     jfloatArray printableArray = NULL;
 262 
 263     SAVE_CONTROLWORD
 264     HDC pdc = CreateDC(TEXT("WINSPOOL"), printerName, NULL, NULL);
 265     RESTORE_CONTROLWORD
 266     if (pdc) {
 267         HANDLE hPrinter;
 268         /* Start by opening the printer */
 269         if (!::OpenPrinter(printerName, &hPrinter, NULL)) {
 270             JNU_ReleaseStringPlatformChars(env, printer, printerName);
 271             return printableArray;
 272         }
 273 
 274         PDEVMODE pDevMode;
 275 
 276         if (!AwtPrintControl::getDevmode(hPrinter, printerName, &pDevMode)) {
 277             /* if failure, cleanup and return failure */
 278 
 279             if (pDevMode != NULL) {
 280                 ::GlobalFree(pDevMode);
 281             }
 282             DeleteDC(pdc);
 283             ::ClosePrinter(hPrinter);
 284             JNU_ReleaseStringPlatformChars(env, printer, printerName);
 285             return printableArray;
 286         }
 287 
 288         pDevMode->dmFields |= (DM_PAPERSIZE | DM_ORIENTATION);
 289         pDevMode->dmPaperSize = (short)papersize;
 290         pDevMode->dmOrientation = DMORIENT_PORTRAIT;
 291         ::ResetDC(pdc, pDevMode);
 292         RESTORE_CONTROLWORD
 293 
 294         int left = GetDeviceCaps(pdc, PHYSICALOFFSETX);
 295         int top = GetDeviceCaps(pdc, PHYSICALOFFSETY);
 296         int width = GetDeviceCaps(pdc, HORZRES);
 297         int height = GetDeviceCaps(pdc, VERTRES);
 298 
 299         int resx = GetDeviceCaps(pdc, LOGPIXELSX);
 300         int resy = GetDeviceCaps(pdc, LOGPIXELSY);
 301 
 302         printableArray=env->NewFloatArray(4);
 303         if (printableArray != NULL) {
 304             jfloat *iPrintables =
 305                 env->GetFloatArrayElements(printableArray, NULL);
 306             if (iPrintables != NULL) {
 307                 iPrintables[0] = (float)left/resx;
 308                 iPrintables[1] = (float)top/resy;
 309                 iPrintables[2] = (float)width/resx;
 310                 iPrintables[3] = (float)height/resy;
 311                 env->ReleaseFloatArrayElements(printableArray, iPrintables, 0);
 312             }
 313         }
 314         GlobalFree(pDevMode);
 315         DeleteDC(pdc);
 316     }
 317 
 318     JNU_ReleaseStringPlatformChars(env, printer, printerName);
 319 
 320     return printableArray;
 321 
 322     CATCH_BAD_ALLOC_RET(NULL);
 323 }
 324 
 325 jintArray getIDs(JNIEnv *env, jstring printer, jstring port, int dm_id)
 326 {
 327 
 328   LPTSTR printerName = (LPTSTR)JNU_GetStringPlatformChars(env, printer, NULL);
 329   LPTSTR printerPort = (LPTSTR)JNU_GetStringPlatformChars(env, port, NULL);
 330 
 331   if (printerName == NULL || printerPort == NULL) {
 332       if (printerName != NULL) {
 333           JNU_ReleaseStringPlatformChars(env, printer, printerName);
 334       }
 335       if (printerPort != NULL) {
 336           JNU_ReleaseStringPlatformChars(env, port, printerPort);
 337       }
 338       return NULL;
 339   }
 340 
 341   SAVE_CONTROLWORD
 342   int numIDs = ::DeviceCapabilities(printerName, printerPort, dm_id,
 343                                     NULL, NULL);
 344   RESTORE_CONTROLWORD
 345 
 346   jintArray idArray = NULL;
 347   if (numIDs > 0) {
 348       idArray = env->NewIntArray(numIDs);
 349       if (idArray != NULL) {
 350           jint *jpcIndices = env->GetIntArrayElements(idArray, NULL);
 351           if (jpcIndices != NULL) {
 352               jint *saveFormats = jpcIndices;
 353               LPTSTR buf = NULL;
 354               try {
 355                   buf = (LPTSTR)new char[numIDs * sizeof(WORD)];
 356               } catch (std::bad_alloc&) {
 357                   buf = NULL;
 358               }
 359               if (buf != NULL) {
 360                   if (::DeviceCapabilities(printerName, printerPort,
 361                                            dm_id, buf, NULL) != -1) {
 362                       WORD *id = (WORD *)buf;
 363                       for (int i = 0; i < numIDs; i++, id++) {
 364                           jpcIndices[i] = *id;
 365                       }
 366                   }
 367                   RESTORE_CONTROLWORD
 368                   delete[] buf;
 369               }
 370               env->ReleaseIntArrayElements(idArray, saveFormats, 0);
 371           }
 372       }
 373   }
 374 
 375   JNU_ReleaseStringPlatformChars(env, printer, printerName);
 376   JNU_ReleaseStringPlatformChars(env, port, printerPort);
 377   return idArray;
 378 }
 379 
 380 JNIEXPORT jintArray JNICALL
 381 Java_sun_print_Win32PrintService_getAllMediaIDs(JNIEnv *env,
 382                                                 jobject peer,
 383                                                 jstring printer,
 384                                                 jstring port)
 385 {
 386     return getIDs(env, printer, port, DC_PAPERS);
 387 }
 388 
 389 
 390 JNIEXPORT jintArray JNICALL
 391 Java_sun_print_Win32PrintService_getAllMediaTrays(JNIEnv *env,
 392                                                   jobject peer,
 393                                                   jstring printer,
 394                                                   jstring port)
 395 {
 396     return getIDs(env, printer, port, DC_BINS);
 397 }
 398 
 399 
 400 JNIEXPORT jintArray JNICALL
 401 Java_sun_print_Win32PrintService_getAllMediaSizes(JNIEnv *env,
 402                                                   jobject peer,
 403                                                   jstring printer,
 404                                                   jstring port)
 405 {
 406   LPTSTR printerName = (LPTSTR)JNU_GetStringPlatformChars(env, printer, NULL);
 407   LPTSTR printerPort = (LPTSTR)JNU_GetStringPlatformChars(env, port, NULL);
 408 
 409   if (printerName == NULL || printerPort == NULL) {
 410       if (printerName != NULL) {
 411           JNU_ReleaseStringPlatformChars(env, printer, printerName);
 412       }
 413       if (printerPort != NULL) {
 414           JNU_ReleaseStringPlatformChars(env, port, printerPort);
 415       }
 416       return NULL;
 417   }
 418 
 419   SAVE_CONTROLWORD
 420   int nPapers = ::DeviceCapabilities(printerName, printerPort, DC_PAPERSIZE,
 421                                      NULL, NULL) ;
 422   RESTORE_CONTROLWORD
 423 
 424   jintArray mediaArray = NULL;
 425   jint *saveFormats = NULL;
 426 
 427   if (nPapers > 0) {
 428       mediaArray = env->NewIntArray(nPapers*2);
 429       if (mediaArray != NULL) {
 430           jint *jpcIndices = env->GetIntArrayElements(mediaArray, NULL);
 431           if (jpcIndices != NULL) {
 432               saveFormats = jpcIndices;
 433               LPTSTR buf = NULL;
 434               try {
 435                   buf = (LPTSTR)new char[nPapers * sizeof(POINT)];
 436               } catch (std::bad_alloc&) {
 437                   buf = NULL;
 438               }
 439               if (buf != NULL) {
 440                   if (::DeviceCapabilities(printerName, printerPort,
 441                                            DC_PAPERSIZE, buf, NULL) != -1) {
 442                       POINT *pDim = (POINT *)buf;
 443                       for (int i = 0; i < nPapers; i++) {
 444                           jpcIndices[i*2] = (pDim+i)->x;
 445                           jpcIndices[i*2+1] = (pDim+i)->y;
 446                       }
 447                   }
 448                   RESTORE_CONTROLWORD
 449                   delete[] buf;
 450               }
 451               env->ReleaseIntArrayElements(mediaArray, saveFormats, 0);
 452               saveFormats = NULL;
 453           }
 454       }
 455   }
 456 
 457   JNU_ReleaseStringPlatformChars(env, printer, printerName);
 458   JNU_ReleaseStringPlatformChars(env, port, printerPort);
 459   if (mediaArray != NULL && saveFormats != NULL) {
 460       env->ReleaseIntArrayElements(mediaArray, saveFormats, 0);
 461   }
 462   return mediaArray;
 463 
 464 }
 465 
 466 
 467 jobjectArray getAllDCNames(JNIEnv *env, jobject peer, jstring printer,
 468                  jstring port, unsigned int dc_id, unsigned int buf_len)
 469 {
 470 
 471   LPTSTR printerName = (LPTSTR)JNU_GetStringPlatformChars(env, printer, NULL);
 472   LPTSTR printerPort = (LPTSTR)JNU_GetStringPlatformChars(env, port, NULL);
 473 
 474   if (printerName == NULL || printerPort == NULL) {
 475       if (printerName != NULL) {
 476           JNU_ReleaseStringPlatformChars(env, printer, printerName);
 477       }
 478       if (printerPort != NULL) {
 479           JNU_ReleaseStringPlatformChars(env, port, printerPort);
 480       }
 481       return NULL;
 482   }
 483 
 484   jstring utf_str;
 485   jobjectArray names = NULL;
 486   LPTSTR buf = NULL;
 487   SAVE_CONTROLWORD
 488   int cReturned = ::DeviceCapabilities(printerName, printerPort,
 489                                          dc_id, NULL, NULL);
 490   RESTORE_CONTROLWORD
 491   if (cReturned <= 0) {
 492       JNU_ReleaseStringPlatformChars(env, printer, printerName);
 493       JNU_ReleaseStringPlatformChars(env, port, printerPort);
 494       return NULL;
 495   }
 496 
 497   try {
 498       buf = (LPTSTR)new char[cReturned * buf_len * sizeof(TCHAR)];
 499   } catch (std::bad_alloc&) {
 500       buf = NULL;
 501   }
 502   if (buf == NULL) {
 503       JNU_ReleaseStringPlatformChars(env, printer, printerName);
 504       JNU_ReleaseStringPlatformChars(env, port, printerPort);
 505       JNU_ThrowOutOfMemoryError(env, "OutOfMemoryError");
 506      return NULL;
 507   }
 508 
 509   cReturned = ::DeviceCapabilities(printerName, printerPort,
 510                                    dc_id, buf, NULL);
 511   RESTORE_CONTROLWORD
 512 
 513   JNU_ReleaseStringPlatformChars(env, printer, printerName);
 514   JNU_ReleaseStringPlatformChars(env, port, printerPort);
 515 
 516   if (cReturned > 0) {
 517       jclass cls = env->FindClass("java/lang/String");
 518       if (cls != NULL) {
 519           names = env->NewObjectArray(cReturned, cls, NULL);
 520       }
 521       if (names == NULL || cls == NULL) {
 522           delete[] buf;
 523           return names;
 524       }
 525 
 526       for (int i = 0; i < cReturned; i++) {
 527           utf_str = JNU_NewStringPlatform(env, buf+(buf_len*i));
 528             if (utf_str == NULL) {
 529                 delete[] buf;
 530                 return names;
 531             }
 532             env->SetObjectArrayElement(names, i, utf_str);
 533             env->DeleteLocalRef(utf_str);
 534         }
 535     }
 536     delete[] buf;
 537     return names;
 538 
 539 }
 540 
 541 
 542 JNIEXPORT jobjectArray JNICALL
 543 Java_sun_print_Win32PrintService_getAllMediaNames(JNIEnv *env,
 544                                                   jobject peer,
 545                                                   jstring printer,
 546                                                   jstring port)
 547 {
 548   return getAllDCNames(env, peer, printer, port, DC_PAPERNAMES, PAPERNAME_LENGTH);
 549 }
 550 
 551 
 552 JNIEXPORT jobjectArray JNICALL
 553 Java_sun_print_Win32PrintService_getAllMediaTrayNames(JNIEnv *env,
 554                                                   jobject peer,
 555                                                   jstring printer,
 556                                                   jstring port)
 557 {
 558   return getAllDCNames(env, peer, printer, port, DC_BINNAMES, TRAYNAME_LENGTH);
 559 }
 560 
 561 
 562 JNIEXPORT jint JNICALL
 563 Java_sun_print_Win32PrintService_getCopiesSupported(JNIEnv *env,
 564                                                     jobject peer,
 565                                                     jstring printer,
 566                                                     jstring port)
 567 {
 568   LPTSTR printerName = (LPTSTR)JNU_GetStringPlatformChars(env, printer, NULL);
 569   LPTSTR printerPort = (LPTSTR)JNU_GetStringPlatformChars(env, port, NULL);
 570 
 571   if (printerName == NULL || printerPort == NULL) {
 572       if (printerName != NULL) {
 573           JNU_ReleaseStringPlatformChars(env, printer, printerName);
 574       }
 575       if (printerPort != NULL) {
 576           JNU_ReleaseStringPlatformChars(env, port, printerPort);
 577       }
 578       return 1;
 579   }
 580 
 581   SAVE_CONTROLWORD
 582   int numCopies = ::DeviceCapabilities(printerName, printerPort,
 583                                        DC_COPIES,   NULL, NULL);
 584   RESTORE_CONTROLWORD
 585 
 586   if (numCopies == -1)
 587     return 1; // default
 588 
 589   JNU_ReleaseStringPlatformChars(env, printer, printerName);
 590   JNU_ReleaseStringPlatformChars(env, port, printerPort);
 591 
 592   return numCopies;
 593 }
 594 
 595 
 596 /*
 597 PostScript Drivers return wrong support info for the following code:
 598 
 599  DWORD dmFields = (::DeviceCapabilities(printerName,
 600                                          NULL, DC_FIELDS,   NULL, NULL)) ;
 601 
 602   if ((dmFields & DM_YRESOLUTION) )
 603     isSupported = true;
 604 
 605 Returns not supported even if it supports resolution. Therefore, we use the
 606 function _getAllResolutions.
 607 */
 608 JNIEXPORT jintArray JNICALL
 609 Java_sun_print_Win32PrintService_getAllResolutions(JNIEnv *env,
 610                                                    jobject peer,
 611                                                    jstring printer,
 612                                                    jstring port)
 613 {
 614   LPTSTR printerName = (LPTSTR)JNU_GetStringPlatformChars(env, printer, NULL);
 615   LPTSTR printerPort = (LPTSTR)JNU_GetStringPlatformChars(env, port, NULL);
 616 
 617  if (printerName == NULL || printerPort == NULL) {
 618       if (printerName != NULL) {
 619           JNU_ReleaseStringPlatformChars(env, printer, printerName);
 620       }
 621       if (printerPort != NULL) {
 622           JNU_ReleaseStringPlatformChars(env, port, printerPort);
 623       }
 624       return NULL;
 625   }
 626 
 627   SAVE_CONTROLWORD
 628   int nResolutions = ::DeviceCapabilities(printerName, printerPort,
 629                                           DC_ENUMRESOLUTIONS, NULL, NULL);
 630   RESTORE_CONTROLWORD
 631 
 632   jintArray resolutionArray = NULL;
 633   if (nResolutions > 0) {
 634     resolutionArray = env->NewIntArray(nResolutions*2);
 635     if (resolutionArray != NULL) {
 636         jint *jpcIndices = env->GetIntArrayElements(resolutionArray, NULL);
 637         if (jpcIndices != NULL) {
 638             jint *saveFormats = jpcIndices;
 639             LPTSTR resBuf = NULL;
 640             try {
 641                 resBuf = (LPTSTR)new char[nResolutions * sizeof(LONG) * 2];
 642             } catch (std::bad_alloc&) {
 643                 resBuf = NULL;
 644             }
 645             if (resBuf != NULL) {
 646                 if (::DeviceCapabilities(printerName, printerPort,
 647                                          DC_ENUMRESOLUTIONS, resBuf,
 648                                          NULL) != -1) {
 649                     LONG *pResolution = (LONG *)resBuf;
 650                     for (int i = 0; i < nResolutions; i++) {
 651                         jpcIndices[i*2] = *pResolution++;
 652                         jpcIndices[i*2+1] = *pResolution++;
 653                     }
 654                 }
 655                 RESTORE_CONTROLWORD
 656                 delete[] resBuf;
 657             }
 658             env->ReleaseIntArrayElements(resolutionArray, saveFormats, 0);
 659         }
 660     }
 661   }
 662 
 663   JNU_ReleaseStringPlatformChars(env, printer, printerName);
 664   JNU_ReleaseStringPlatformChars(env, port, printerPort);
 665   return resolutionArray;
 666 }
 667 
 668 
 669 static BOOL IsDCPostscript( HDC hDC )
 670 {
 671     int         nEscapeCode;
 672     CHAR        szTechnology[MAX_PATH] = "";
 673 
 674     // If it supports POSTSCRIPT_PASSTHROUGH, it must be PS.
 675     nEscapeCode = POSTSCRIPT_PASSTHROUGH;
 676     if( ::ExtEscape( hDC, QUERYESCSUPPORT, sizeof(int),
 677                      (LPCSTR)&nEscapeCode, 0, NULL ) > 0 )
 678         return TRUE;
 679 
 680     // If it doesn't support GETTECHNOLOGY, we won't be able to tell.
 681     nEscapeCode = GETTECHNOLOGY;
 682     if( ::ExtEscape( hDC, QUERYESCSUPPORT, sizeof(int),
 683                      (LPCSTR)&nEscapeCode, 0, NULL ) <= 0 )
 684         return FALSE;
 685 
 686     // Get the technology string and check if the word "postscript" is in it.
 687     if( ::ExtEscape( hDC, GETTECHNOLOGY, 0, NULL, MAX_PATH,
 688                      (LPSTR)szTechnology ) <= 0 )
 689         return FALSE;
 690     _strupr_s(szTechnology, MAX_PATH);
 691     if(!strstr( szTechnology, "POSTSCRIPT" ) == NULL )
 692         return TRUE;
 693 
 694     // The word "postscript" was not found and it didn't support
 695     //   POSTSCRIPT_PASSTHROUGH, so it's not a PS printer.
 696         return FALSE;
 697 }
 698 
 699 
 700 JNIEXPORT jstring JNICALL
 701 Java_sun_print_Win32PrintService_getPrinterPort(JNIEnv *env,
 702                                                 jobject peer,
 703                                                 jstring printer)
 704 {
 705 
 706   if (printer == NULL) {
 707     return NULL;
 708   }
 709 
 710   jstring jPort;
 711   LPTSTR printerName = NULL, printerPort = TEXT("LPT1");
 712   LPBYTE buffer = NULL;
 713   DWORD cbBuf = 0;
 714 
 715   try {
 716     VERIFY(AwtPrintControl::FindPrinter(NULL, NULL, &cbBuf, NULL, NULL));
 717     buffer = new BYTE[cbBuf];
 718     AwtPrintControl::FindPrinter(printer, buffer, &cbBuf,
 719                                       &printerName, &printerPort);
 720   } catch (std::bad_alloc&) {
 721     delete [] buffer;
 722     JNU_ThrowOutOfMemoryError(env, "OutOfMemoryError");
 723     return NULL;
 724   }
 725 
 726   if (printerPort == NULL) {
 727     printerPort = TEXT("LPT1");
 728   }
 729   jPort = JNU_NewStringPlatform(env, printerPort);
 730   delete [] buffer;
 731   return jPort;
 732 
 733 }
 734 
 735 
 736 JNIEXPORT jint JNICALL
 737 Java_sun_print_Win32PrintService_getCapabilities(JNIEnv *env,
 738                                                  jobject peer,
 739                                                  jstring printer,
 740                                                  jstring port)
 741 {
 742   LPTSTR printerName = (LPTSTR)JNU_GetStringPlatformChars(env, printer, NULL);
 743   LPTSTR printerPort = (LPTSTR)JNU_GetStringPlatformChars(env, port, NULL);
 744 
 745   if (printerName == NULL || printerPort == NULL) {
 746       if (printerName != NULL) {
 747           JNU_ReleaseStringPlatformChars(env, printer, printerName);
 748       }
 749       if (printerPort != NULL) {
 750           JNU_ReleaseStringPlatformChars(env, port, printerPort);
 751       }
 752       return NULL;
 753   }
 754 
 755   // 0x1000 is a flag to indicate that getCapabilities has already been called.
 756   // 0x0001 is a flag for color support and supported is the default.
 757   jint ret = 0x1001;
 758   DWORD dmFields;
 759 
 760   // get Duplex
 761   SAVE_CONTROLWORD
 762   DWORD isDuplex = (::DeviceCapabilities(printerName, printerPort,
 763                                          DC_DUPLEX,   NULL, NULL)) ;
 764 
 765   /*
 766     Check if duplexer is installed either physically or manually thru the
 767     printer setting dialog by checking if DM_DUPLEX is set.
 768   */
 769   dmFields = (::DeviceCapabilities(printerName, printerPort,
 770                                    DC_FIELDS,   NULL, NULL)) ;
 771 
 772   if ((dmFields & DM_DUPLEX) && isDuplex) {
 773       ret |= 0x0002;
 774   }
 775 
 776   // get Collation
 777   if ((dmFields & DM_COLLATE) ) {
 778       ret |= 0x0004;
 779   }
 780 
 781   // get Print Quality
 782   if ((dmFields & DM_PRINTQUALITY) ) {
 783       ret |= 0x0008;
 784   }
 785 
 786   HDC pdc = CreateDC(TEXT("WINSPOOL"), printerName, NULL, NULL);
 787   if (pdc != NULL) {
 788       // get Color
 789       int bpp = GetDeviceCaps(pdc, BITSPIXEL);
 790       int nColors = GetDeviceCaps(pdc, NUMCOLORS);
 791 
 792       if (!(dmFields & DM_COLOR) || ((bpp == 1)
 793                                      && ((nColors == 2) || (nColors == 256)))) {
 794           ret &= ~0x0001;
 795       }
 796 
 797       // check support for PostScript
 798       if (IsDCPostscript(pdc)) {
 799             ret |= 0x0010;
 800       }
 801 
 802       DeleteDC(pdc);
 803   }
 804 
 805   RESTORE_CONTROLWORD
 806   JNU_ReleaseStringPlatformChars(env, printer, printerName);
 807   JNU_ReleaseStringPlatformChars(env, port, printerPort);
 808   return ret;
 809 }
 810 
 811 
 812 #define GETDEFAULT_ERROR        -50
 813 #define NDEFAULT 9
 814 
 815 JNIEXPORT jintArray JNICALL
 816 Java_sun_print_Win32PrintService_getDefaultSettings(JNIEnv *env,
 817                                                     jobject peer,
 818                                                     jstring printer,
 819                                                     jstring port)
 820 {
 821   HANDLE      hPrinter;
 822   LPDEVMODE   pDevMode = NULL;
 823 
 824   LPTSTR printerName = (LPTSTR)JNU_GetStringPlatformChars(env, printer, NULL);
 825   LPTSTR printerPort = (LPTSTR)JNU_GetStringPlatformChars(env, port, NULL);
 826 
 827   if (printerName == NULL || printerPort == NULL) {
 828       if (printerName != NULL) {
 829           JNU_ReleaseStringPlatformChars(env, printer, printerName);
 830       }
 831       if (printerPort != NULL) {
 832           JNU_ReleaseStringPlatformChars(env, port, printerPort);
 833       }
 834       return NULL;
 835   }
 836 
 837   jint* defIndices = NULL;
 838   jintArray defaultArray = env->NewIntArray(NDEFAULT);
 839   if (defaultArray != NULL) {
 840       defIndices = env->GetIntArrayElements(defaultArray, NULL);
 841   }
 842   if (defIndices == NULL) {
 843       JNU_ReleaseStringPlatformChars(env, printer, printerName);
 844       JNU_ReleaseStringPlatformChars(env, port, printerPort);
 845       return NULL;
 846   }
 847 
 848   jint *saveFormats = defIndices;
 849 
 850   for (int i=0; i < NDEFAULT; i++) {
 851       defIndices[i] = GETDEFAULT_ERROR;
 852   }
 853 
 854   /* Start by opening the printer */
 855   if (!::OpenPrinter(printerName, &hPrinter, NULL)) {
 856       env->ReleaseIntArrayElements(defaultArray, saveFormats, 0);
 857       JNU_ReleaseStringPlatformChars(env, printer, printerName);
 858       JNU_ReleaseStringPlatformChars(env, port, printerPort);
 859       return defaultArray;
 860   }
 861 
 862   if (!AwtPrintControl::getDevmode(hPrinter, printerName, &pDevMode)) {
 863       /* if failure, cleanup and return failure */
 864       if (pDevMode != NULL) {
 865           ::GlobalFree(pDevMode);
 866       }
 867       ::ClosePrinter(hPrinter);
 868       env->ReleaseIntArrayElements(defaultArray, saveFormats, 0);
 869       JNU_ReleaseStringPlatformChars(env, printer, printerName);
 870       JNU_ReleaseStringPlatformChars(env, port, printerPort);
 871       return defaultArray;
 872   }
 873 
 874   /* Have seen one driver which reports a default paper id which is not
 875    * one of their supported paper ids. If what is returned is not
 876    * a supported paper, use one of the supported sizes instead.
 877    *
 878    */
 879   if (pDevMode->dmFields & DM_PAPERSIZE) {
 880       defIndices[0] = pDevMode->dmPaperSize;
 881 
 882       SAVE_CONTROLWORD
 883 
 884       int numSizes = ::DeviceCapabilities(printerName, printerPort,
 885                                           DC_PAPERS, NULL, NULL);
 886       if (numSizes > 0) {
 887           LPTSTR papers;
 888           try {
 889               papers = (LPTSTR)SAFE_SIZE_ARRAY_ALLOC(safe_Malloc, numSizes, sizeof(WORD));
 890           } catch (const std::bad_alloc&) {
 891               papers = NULL;
 892           }
 893 
 894           if (papers != NULL &&
 895               ::DeviceCapabilities(printerName, printerPort,
 896                                    DC_PAPERS, papers, NULL) != -1) {
 897               int present = 0;
 898               for (int i=0;i<numSizes;i++) {
 899                   if (papers[i] == pDevMode->dmPaperSize) {
 900                       present = 1;
 901                   }
 902               }
 903               if (!present) {
 904                   defIndices[0] = papers[0];
 905               }
 906           }
 907           // If DeviceCapabilities fails, then also free paper allocation
 908           if (papers != NULL) {
 909               free((char*)papers);
 910           }
 911       }
 912       RESTORE_CONTROLWORD
 913   }
 914 
 915   if (pDevMode->dmFields & DM_MEDIATYPE) {
 916       defIndices[1] = pDevMode->dmMediaType;
 917   }
 918 
 919   /*
 920    * For some printer like Brother HL-2240D series
 921    * pDevMode->dmYResolution is not set in pDevMode->dmFields
 922    * even though pDevMode->dmYResolution is populated
 923    * via ::DocumentProperties API, so for this case
 924    * we populate the resolution index in default array
 925    */
 926   if (pDevMode->dmFields & DM_YRESOLUTION || pDevMode->dmYResolution > 0) {
 927       defIndices[2]  = pDevMode->dmYResolution;
 928   }
 929 
 930   /*
 931    * For some printer like Brother HL-2240D series
 932    * pDevMode->dmPrintQuality is not set in pDevMode->dmFields
 933    * even though pDevMode->dmPrintQuality is populated
 934    * via ::DocumentProperties API, so for this case
 935    * we populate the print quality index in default array
 936    */
 937   if (pDevMode->dmFields & DM_PRINTQUALITY || pDevMode->dmPrintQuality != 0) {
 938       defIndices[3] = pDevMode->dmPrintQuality;
 939   }
 940 
 941   if (pDevMode->dmFields & DM_COPIES) {
 942       defIndices[4] = pDevMode->dmCopies;
 943   }
 944 
 945   if (pDevMode->dmFields & DM_ORIENTATION) {
 946       defIndices[5] = pDevMode->dmOrientation;
 947   }
 948 
 949   if (pDevMode->dmFields & DM_DUPLEX) {
 950       defIndices[6] = pDevMode->dmDuplex;
 951   }
 952 
 953   if (pDevMode->dmFields & DM_COLLATE) {
 954       defIndices[7] = pDevMode->dmCollate;
 955   }
 956 
 957   if (pDevMode->dmFields & DM_COLOR) {
 958       defIndices[8] = pDevMode->dmColor;
 959   }
 960 
 961   GlobalFree(pDevMode);
 962   ::ClosePrinter(hPrinter);
 963 
 964   env->ReleaseIntArrayElements(defaultArray, saveFormats, 0);
 965 
 966   JNU_ReleaseStringPlatformChars(env, printer, printerName);
 967   JNU_ReleaseStringPlatformChars(env, port, printerPort);
 968 
 969   return defaultArray;
 970 }
 971 
 972 
 973 JNIEXPORT jint JNICALL
 974 Java_sun_print_Win32PrintService_getJobStatus(JNIEnv *env,
 975                                           jobject peer,
 976                                           jstring printer,
 977                                           jint type)
 978 {
 979     HANDLE hPrinter;
 980     DWORD  cByteNeeded;
 981     DWORD  cByteUsed;
 982     PRINTER_INFO_2 *pPrinterInfo = NULL;
 983     int ret=0;
 984 
 985     LPTSTR printerName = (LPTSTR)JNU_GetStringPlatformChars(env, printer, NULL);
 986     if (printerName == NULL) {
 987         return -1;
 988     }
 989 
 990     // Start by opening the printer
 991     if (!::OpenPrinter(printerName, &hPrinter, NULL)) {
 992         JNU_ReleaseStringPlatformChars(env, printer, printerName);
 993         return -1;
 994     }
 995 
 996     if (!::GetPrinter(hPrinter, 2, NULL, 0, &cByteNeeded)) {
 997         if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
 998             ::ClosePrinter(hPrinter);
 999             JNU_ReleaseStringPlatformChars(env, printer, printerName);
1000             return -1;
1001         }
1002     }
1003 
1004     pPrinterInfo = (PRINTER_INFO_2 *)::GlobalAlloc(GPTR, cByteNeeded);
1005     if (!(pPrinterInfo)) {
1006         /* failure to allocate memory */
1007         ::ClosePrinter(hPrinter);
1008         JNU_ReleaseStringPlatformChars(env, printer, printerName);
1009         return -1;
1010     }
1011 
1012     /* get the printer info */
1013     if (!::GetPrinter(hPrinter,
1014                       2,
1015                       (LPBYTE)pPrinterInfo,
1016                       cByteNeeded,
1017                       &cByteUsed))
1018         {
1019             /* failure to access the printer */
1020             ::GlobalFree(pPrinterInfo);
1021             pPrinterInfo = NULL;
1022             ::ClosePrinter(hPrinter);
1023             JNU_ReleaseStringPlatformChars(env, printer, printerName);
1024             return -1;
1025         }
1026 
1027     if (type == GETJOBCOUNT) {
1028         ret = pPrinterInfo->cJobs;
1029     } else if (type == ACCEPTJOB) {
1030         if (pPrinterInfo->Status & PRINTER_STATUS_PENDING_DELETION) {
1031             ret = 0;
1032         }
1033         else {
1034             ret = 1;
1035         }
1036     }
1037 
1038     ::GlobalFree(pPrinterInfo);
1039     ::ClosePrinter(hPrinter);
1040     JNU_ReleaseStringPlatformChars(env, printer, printerName);
1041     return ret;
1042 }
1043 
1044 
1045 static jfieldID getIdOfLongField(JNIEnv *env, jobject self,
1046                                  const char *fieldName) {
1047   jclass myClass = env->GetObjectClass(self);
1048   jfieldID fieldId = env->GetFieldID(myClass, fieldName, "J");
1049   DASSERT(fieldId != 0);
1050   return fieldId;
1051 }
1052 
1053 
1054 static inline HANDLE getHPrinter(JNIEnv *env, jobject self) {
1055   jfieldID fieldId = getIdOfLongField(env, self, HPRINTER_STR);
1056   if (fieldId == (jfieldID)0) {
1057       return (HANDLE)NULL;
1058   }
1059   return (HANDLE)(env->GetLongField(self, fieldId));
1060 }
1061 
1062 
1063 JNIEXPORT jboolean JNICALL
1064 Java_sun_print_Win32PrintJob_startPrintRawData(JNIEnv *env,
1065                                                jobject peer,
1066                                                jstring printer,
1067                                                jstring jobname)
1068 {
1069   HANDLE      hPrinter;
1070   DOC_INFO_1  DocInfo;
1071   LPTSTR printerName = (LPTSTR)JNU_GetStringPlatformChars(env, printer, NULL);
1072   if (printerName == NULL) {
1073       return false;
1074   }
1075   DASSERT(jobname != NULL);
1076   LPTSTR lpJobName = (LPTSTR)JNU_GetStringPlatformChars(env, jobname, NULL);
1077   LPTSTR jname = _tcsdup(lpJobName);
1078   JNU_ReleaseStringPlatformChars(env, jobname, lpJobName);
1079 
1080   // Start by opening the printer
1081   if (!::OpenPrinter(printerName, &hPrinter, NULL)) {
1082     JNU_ReleaseStringPlatformChars(env, printer, printerName);
1083     free((LPTSTR)jname);
1084     return false;
1085   }
1086 
1087   JNU_ReleaseStringPlatformChars(env, printer, printerName);
1088 
1089   // Fill in the structure with info about this "document."
1090   DocInfo.pDocName = jname;
1091   DocInfo.pOutputFile = NULL;
1092   DocInfo.pDatatype = TEXT("RAW");
1093 
1094   // Inform the spooler the document is beginning.
1095   if( (::StartDocPrinter(hPrinter, 1, (LPBYTE)&DocInfo)) == 0 ) {
1096     ::ClosePrinter( hPrinter );
1097     free((LPTSTR)jname);
1098     return false;
1099   }
1100 
1101   free((LPTSTR)jname);
1102 
1103   // Start a page.
1104   if( ! ::StartPagePrinter( hPrinter ) ) {
1105     ::EndDocPrinter( hPrinter );
1106     ::ClosePrinter( hPrinter );
1107     return false;
1108   }
1109 
1110   // store handle
1111   jfieldID fieldId = getIdOfLongField(env, peer, HPRINTER_STR);
1112   if (fieldId == (jfieldID)0) {
1113       return false;
1114   } else {
1115       env->SetLongField(peer, fieldId, reinterpret_cast<jlong>(hPrinter));
1116       return true;
1117   }
1118 }
1119 
1120 
1121 JNIEXPORT jboolean JNICALL
1122 Java_sun_print_Win32PrintJob_printRawData(JNIEnv *env,
1123                                           jobject peer,
1124                                           jbyteArray dataArray,
1125                                           jint count)
1126 {
1127   jboolean  ret=true;
1128   jint      dwBytesWritten;
1129   jbyte*    data = NULL;
1130 
1131   // retrieve handle
1132   HANDLE    hPrinter = getHPrinter(env, peer);
1133   if (hPrinter == NULL) {
1134     return false;
1135   }
1136 
1137   try {
1138     data=(jbyte *)env->GetPrimitiveArrayCritical(dataArray, 0);
1139     if (data == NULL) {
1140         return false;
1141     }
1142 
1143     // Send the data to the printer.
1144     if( ! ::WritePrinter(hPrinter, data, count,(LPDWORD)&dwBytesWritten)) {
1145       env->ReleasePrimitiveArrayCritical(dataArray, data, 0);
1146       return false;
1147     }
1148 
1149     // Check to see if correct number of bytes were written.
1150     if( dwBytesWritten != count ) {
1151       ret = false;
1152     }
1153 
1154   } catch (...) {
1155     if (data != NULL) {
1156       env->ReleasePrimitiveArrayCritical(dataArray, data, 0);
1157     }
1158     JNU_ThrowInternalError(env, "Problem in Win32PrintJob_printRawData");
1159     return false;
1160   }
1161 
1162   env->ReleasePrimitiveArrayCritical(dataArray, data, 0);
1163   return ret;
1164 }
1165 
1166 
1167 JNIEXPORT jboolean JNICALL
1168 Java_sun_print_Win32PrintJob_endPrintRawData(JNIEnv *env,
1169                                           jobject peer)
1170 {
1171   // retrieve handle
1172   HANDLE hPrinter = getHPrinter(env, peer);
1173   if (hPrinter == NULL) {
1174     return false;
1175   }
1176 
1177   if ((::EndPagePrinter(hPrinter) != 0) &&
1178       (::EndDocPrinter(hPrinter) != 0) &&
1179       (::ClosePrinter(hPrinter) != 0)) {
1180     return true;
1181   } else {
1182     return false;
1183   }
1184 }
1185 
1186 } /* extern "C" */