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