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