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