1 /*
   2  * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 #include "awt.h"
  27 
  28 #include "stdhdrs.h"
  29 #include <commdlg.h>
  30 #include <winspool.h>
  31 #include <limits.h>
  32 #include <float.h>
  33 
  34 #include "awt_Toolkit.h"
  35 #include "awt_PrintControl.h"
  36 
  37 /* values for parameter "type" of XXX_getJobStatus() */
  38 #define GETJOBCOUNT  1
  39 #define ACCEPTJOB    2
  40 
  41 static const char *HPRINTER_STR = "hPrintJob";
  42 
  43 /* constants for DeviceCapability buffer lengths */
  44 #define PAPERNAME_LENGTH 64
  45 #define TRAYNAME_LENGTH 24
  46 
  47 
  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 JNIEXPORT jobjectArray JNICALL
 122 Java_sun_print_PrintServiceLookupProvider_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     if (clazz == NULL) {
 134         return NULL;
 135     }
 136     jobjectArray nameArray;
 137 
 138     try {
 139         ::EnumPrinters(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS,
 140                        NULL, 4, NULL, 0, &cbNeeded, &cReturned);
 141         pPrinterEnum = new BYTE[cbNeeded];
 142         ::EnumPrinters(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS,
 143                        NULL, 4, pPrinterEnum, cbNeeded, &cbNeeded,
 144                        &cReturned);
 145 
 146         if (cReturned > 0) {
 147             nameArray = env->NewObjectArray(cReturned, clazz, NULL);
 148             if (nameArray == NULL) {
 149                 throw std::bad_alloc();
 150             }
 151         } else {
 152             nameArray = NULL;
 153         }
 154 
 155 
 156         for (DWORD i = 0; i < cReturned; i++) {
 157             PRINTER_INFO_4 *info4 = (PRINTER_INFO_4 *)
 158                 (pPrinterEnum + i * sizeof(PRINTER_INFO_4));
 159             utf_str = JNU_NewStringPlatform(env, info4->pPrinterName);
 160             if (utf_str == NULL) {
 161                 throw std::bad_alloc();
 162             }
 163             env->SetObjectArrayElement(nameArray, i, utf_str);
 164             env->DeleteLocalRef(utf_str);
 165         }
 166     } catch (std::bad_alloc&) {
 167         delete [] pPrinterEnum;
 168         throw;
 169     }
 170 
 171     delete [] pPrinterEnum;
 172     return nameArray;
 173 
 174     CATCH_BAD_ALLOC_RET(NULL);
 175 }
 176 
 177 
 178 JNIEXPORT jlong JNICALL
 179 Java_sun_print_PrintServiceLookupProvider_notifyFirstPrinterChange(JNIEnv *env,
 180                                                                 jobject peer,
 181                                                                 jstring printer) {
 182     HANDLE hPrinter;
 183 
 184     LPTSTR printerName = NULL;
 185     if (printer != NULL) {
 186         printerName = (LPTSTR)JNU_GetStringPlatformChars(env,
 187                                                          printer,
 188                                                          NULL);
 189         JNU_ReleaseStringPlatformChars(env, printer, printerName);
 190     }
 191 
 192     // printerName - "Win NT/2K/XP: If NULL, it indicates the local printer
 193     // server" - MSDN.   Win9x : OpenPrinter returns 0.
 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, printer, 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, printer, 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 = (LPTSTR)SAFE_SIZE_ARRAY_ALLOC(safe_Malloc, numSizes, sizeof(WORD));
 877           if (papers != NULL &&
 878               ::DeviceCapabilities(printerName, printerPort,
 879                                    DC_PAPERS, papers, NULL) != -1) {
 880               int present = 0;
 881               for (int i=0;i<numSizes;i++) {
 882                   if (papers[i] == pDevMode->dmPaperSize) {
 883                       present = 1;
 884                   }
 885               }
 886               if (!present) {
 887                   defIndices[0] = papers[0];
 888               }
 889               if (papers != NULL) {
 890                   free((char*)papers);
 891               }
 892           }
 893       }
 894       RESTORE_CONTROLWORD
 895   }
 896 
 897   if (pDevMode->dmFields & DM_MEDIATYPE) {
 898       defIndices[1] = pDevMode->dmMediaType;
 899   }
 900 
 901   /*
 902    * For some printer like Brother HL-2240D series
 903    * pDevMode->dmYResolution is not set in pDevMode->dmFields
 904    * even though pDevMode->dmYResolution is populated
 905    * via ::DocumentProperties API, so for this case
 906    * we populate the resolution index in default array
 907    */
 908   if (pDevMode->dmFields & DM_YRESOLUTION || pDevMode->dmYResolution > 0) {
 909       defIndices[2]  = pDevMode->dmYResolution;
 910   }
 911 
 912   /*
 913    * For some printer like Brother HL-2240D series
 914    * pDevMode->dmPrintQuality is not set in pDevMode->dmFields
 915    * even though pDevMode->dmPrintQuality is populated
 916    * via ::DocumentProperties API, so for this case
 917    * we populate the print quality index in default array
 918    */
 919   if (pDevMode->dmFields & DM_PRINTQUALITY || pDevMode->dmPrintQuality != 0) {
 920       defIndices[3] = pDevMode->dmPrintQuality;
 921   }
 922 
 923   if (pDevMode->dmFields & DM_COPIES) {
 924       defIndices[4] = pDevMode->dmCopies;
 925   }
 926 
 927   if (pDevMode->dmFields & DM_ORIENTATION) {
 928       defIndices[5] = pDevMode->dmOrientation;
 929   }
 930 
 931   if (pDevMode->dmFields & DM_DUPLEX) {
 932       defIndices[6] = pDevMode->dmDuplex;
 933   }
 934 
 935   if (pDevMode->dmFields & DM_COLLATE) {
 936       defIndices[7] = pDevMode->dmCollate;
 937   }
 938 
 939   if (pDevMode->dmFields & DM_COLOR) {
 940       defIndices[8] = pDevMode->dmColor;
 941   }
 942 
 943   GlobalFree(pDevMode);
 944   ::ClosePrinter(hPrinter);
 945 
 946   env->ReleaseIntArrayElements(defaultArray, saveFormats, 0);
 947 
 948   JNU_ReleaseStringPlatformChars(env, printer, printerName);
 949   JNU_ReleaseStringPlatformChars(env, port, printerPort);
 950 
 951   return defaultArray;
 952 }
 953 
 954 
 955 JNIEXPORT jint JNICALL
 956 Java_sun_print_Win32PrintService_getJobStatus(JNIEnv *env,
 957                                           jobject peer,
 958                                           jstring printer,
 959                                           jint type)
 960 {
 961     HANDLE hPrinter;
 962     DWORD  cByteNeeded;
 963     DWORD  cByteUsed;
 964     PRINTER_INFO_2 *pPrinterInfo = NULL;
 965     int ret=0;
 966 
 967     LPTSTR printerName = (LPTSTR)JNU_GetStringPlatformChars(env, printer, NULL);
 968     if (printerName == NULL) {
 969         return -1;
 970     }
 971 
 972     // Start by opening the printer
 973     if (!::OpenPrinter(printerName, &hPrinter, NULL)) {
 974         JNU_ReleaseStringPlatformChars(env, printer, printerName);
 975         return -1;
 976     }
 977 
 978     if (!::GetPrinter(hPrinter, 2, NULL, 0, &cByteNeeded)) {
 979         if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
 980             ::ClosePrinter(hPrinter);
 981             JNU_ReleaseStringPlatformChars(env, printer, printerName);
 982             return -1;
 983         }
 984     }
 985 
 986     pPrinterInfo = (PRINTER_INFO_2 *)::GlobalAlloc(GPTR, cByteNeeded);
 987     if (!(pPrinterInfo)) {
 988         /* failure to allocate memory */
 989         ::ClosePrinter(hPrinter);
 990         JNU_ReleaseStringPlatformChars(env, printer, printerName);
 991         return -1;
 992     }
 993 
 994     /* get the printer info */
 995     if (!::GetPrinter(hPrinter,
 996                       2,
 997                       (LPBYTE)pPrinterInfo,
 998                       cByteNeeded,
 999                       &cByteUsed))
1000         {
1001             /* failure to access the printer */
1002             ::GlobalFree(pPrinterInfo);
1003             pPrinterInfo = NULL;
1004             ::ClosePrinter(hPrinter);
1005             JNU_ReleaseStringPlatformChars(env, printer, printerName);
1006             return -1;
1007         }
1008 
1009     if (type == GETJOBCOUNT) {
1010         ret = pPrinterInfo->cJobs;
1011     } else if (type == ACCEPTJOB) {
1012         if (pPrinterInfo->Status & PRINTER_STATUS_PENDING_DELETION) {
1013             ret = 0;
1014         }
1015         else {
1016             ret = 1;
1017         }
1018     }
1019 
1020     ::GlobalFree(pPrinterInfo);
1021     ::ClosePrinter(hPrinter);
1022     JNU_ReleaseStringPlatformChars(env, printer, printerName);
1023     return ret;
1024 }
1025 
1026 
1027 static jfieldID getIdOfLongField(JNIEnv *env, jobject self,
1028                                  const char *fieldName) {
1029   jclass myClass = env->GetObjectClass(self);
1030   jfieldID fieldId = env->GetFieldID(myClass, fieldName, "J");
1031   DASSERT(fieldId != 0);
1032   return fieldId;
1033 }
1034 
1035 
1036 static inline HANDLE getHPrinter(JNIEnv *env, jobject self) {
1037   jfieldID fieldId = getIdOfLongField(env, self, HPRINTER_STR);
1038   if (fieldId == (jfieldID)0) {
1039       return (HANDLE)NULL;
1040   }
1041   return (HANDLE)(env->GetLongField(self, fieldId));
1042 }
1043 
1044 
1045 JNIEXPORT jboolean JNICALL
1046 Java_sun_print_Win32PrintJob_startPrintRawData(JNIEnv *env,
1047                                                jobject peer,
1048                                                jstring printer,
1049                                                jstring jobname)
1050 {
1051   HANDLE      hPrinter;
1052   DOC_INFO_1  DocInfo;
1053   LPTSTR printerName = (LPTSTR)JNU_GetStringPlatformChars(env, printer, NULL);
1054   if (printerName == NULL) {
1055       return false;
1056   }
1057   DASSERT(jobname != NULL);
1058   LPTSTR lpJobName = (LPTSTR)JNU_GetStringPlatformChars(env, jobname, NULL);
1059   LPTSTR jname = _tcsdup(lpJobName);
1060   JNU_ReleaseStringPlatformChars(env, jobname, lpJobName);
1061 
1062   // Start by opening the printer
1063   if (!::OpenPrinter(printerName, &hPrinter, NULL)) {
1064     JNU_ReleaseStringPlatformChars(env, printer, printerName);
1065     free((LPTSTR)jname);
1066     return false;
1067   }
1068 
1069   JNU_ReleaseStringPlatformChars(env, printer, printerName);
1070 
1071   // Fill in the structure with info about this "document."
1072   DocInfo.pDocName = jname;
1073   DocInfo.pOutputFile = NULL;
1074   DocInfo.pDatatype = TEXT("RAW");
1075 
1076   // Inform the spooler the document is beginning.
1077   if( (::StartDocPrinter(hPrinter, 1, (LPBYTE)&DocInfo)) == 0 ) {
1078     ::ClosePrinter( hPrinter );
1079     free((LPTSTR)jname);
1080     return false;
1081   }
1082 
1083   free((LPTSTR)jname);
1084 
1085   // Start a page.
1086   if( ! ::StartPagePrinter( hPrinter ) ) {
1087     ::EndDocPrinter( hPrinter );
1088     ::ClosePrinter( hPrinter );
1089     return false;
1090   }
1091 
1092   // store handle
1093   jfieldID fieldId = getIdOfLongField(env, peer, HPRINTER_STR);
1094   if (fieldId == (jfieldID)0) {
1095       return false;
1096   } else {
1097       env->SetLongField(peer, fieldId, reinterpret_cast<jlong>(hPrinter));
1098       return true;
1099   }
1100 }
1101 
1102 
1103 JNIEXPORT jboolean JNICALL
1104 Java_sun_print_Win32PrintJob_printRawData(JNIEnv *env,
1105                                           jobject peer,
1106                                           jbyteArray dataArray,
1107                                           jint count)
1108 {
1109   jboolean  ret=true;
1110   jint      dwBytesWritten;
1111   jbyte*    data = NULL;
1112 
1113   // retrieve handle
1114   HANDLE    hPrinter = getHPrinter(env, peer);
1115   if (hPrinter == NULL) {
1116     return false;
1117   }
1118 
1119   try {
1120     data=(jbyte *)env->GetPrimitiveArrayCritical(dataArray, 0);
1121     if (data == NULL) {
1122         return false;
1123     }
1124 
1125     // Send the data to the printer.
1126     if( ! ::WritePrinter(hPrinter, data, count,(LPDWORD)&dwBytesWritten)) {
1127       env->ReleasePrimitiveArrayCritical(dataArray, data, 0);
1128       return false;
1129     }
1130 
1131     // Check to see if correct number of bytes were written.
1132     if( dwBytesWritten != count ) {
1133       ret = false;
1134     }
1135 
1136   } catch (...) {
1137     if (data != NULL) {
1138       env->ReleasePrimitiveArrayCritical(dataArray, data, 0);
1139     }
1140     JNU_ThrowInternalError(env, "Problem in Win32PrintJob_printRawData");
1141     return false;
1142   }
1143 
1144   env->ReleasePrimitiveArrayCritical(dataArray, data, 0);
1145   return ret;
1146 }
1147 
1148 
1149 JNIEXPORT jboolean JNICALL
1150 Java_sun_print_Win32PrintJob_endPrintRawData(JNIEnv *env,
1151                                           jobject peer)
1152 {
1153   // retrieve handle
1154   HANDLE hPrinter = getHPrinter(env, peer);
1155   if (hPrinter == NULL) {
1156     return false;
1157   }
1158 
1159   if ((::EndPagePrinter(hPrinter) != 0) &&
1160       (::EndDocPrinter(hPrinter) != 0) &&
1161       (::ClosePrinter(hPrinter) != 0)) {
1162     return true;
1163   } else {
1164     return false;
1165   }
1166 }
1167 
1168 } /* extern "C" */