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