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