1 /*
2 * Copyright (c) 1999, 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_Component.h"
27 #include "awt_PrintControl.h"
28 #include "awt.h"
29 #include "awt_PrintDialog.h"
30 #include <winspool.h>
31 #include <float.h>
32 #include <math.h>
33
34 #define ROUNDTOINT(x) ((int)((x)+0.5))
35 static const int DEFAULT_RES = 72;
36 static const double TENTHS_MM_TO_POINTS = 3.527777778;
37 static const double LOMETRIC_TO_POINTS = (72.0 / 254.0);
38
39
40 /* Values must match those defined in WPrinterJob.java */
41 static const DWORD SET_COLOR = 0x00000200;
42 static const DWORD SET_ORIENTATION = 0x00004000;
43 static const DWORD SET_DUP_VERTICAL = 0x00000010;
44 static const DWORD SET_DUP_HORIZONTAL = 0x00000020;
45 static const DWORD SET_RES_HIGH = 0x00000040;
46 static const DWORD SET_RES_LOW = 0x00000080;
47
48
49 /* These methods and fields are on sun.awt.windows.WPrinterJob */
50 jfieldID AwtPrintControl::dialogOwnerPeerID;
51 jmethodID AwtPrintControl::getPrintDCID;
52 jmethodID AwtPrintControl::setPrintDCID;
53 jmethodID AwtPrintControl::getDevmodeID;
54 jmethodID AwtPrintControl::setDevmodeID;
55 jmethodID AwtPrintControl::getDevnamesID;
56 jmethodID AwtPrintControl::setDevnamesID;
57 jfieldID AwtPrintControl::driverDoesMultipleCopiesID;
58 jfieldID AwtPrintControl::driverDoesCollationID;
59 jmethodID AwtPrintControl::getWin32MediaID;
60 jmethodID AwtPrintControl::setWin32MediaID;
61 jmethodID AwtPrintControl::getWin32MediaTrayID;
62 jmethodID AwtPrintControl::setWin32MediaTrayID;
63 jmethodID AwtPrintControl::getColorID;
64 jmethodID AwtPrintControl::getCopiesID;
65 jmethodID AwtPrintControl::getSelectID;
66 jmethodID AwtPrintControl::getDestID;
67 jmethodID AwtPrintControl::getDialogID;
68 jmethodID AwtPrintControl::getFromPageID;
69 jmethodID AwtPrintControl::getMaxPageID;
70 jmethodID AwtPrintControl::getMinPageID;
71 jmethodID AwtPrintControl::getCollateID;
72 jmethodID AwtPrintControl::getOrientID;
73 jmethodID AwtPrintControl::getQualityID;
74 jmethodID AwtPrintControl::getPrintToFileEnabledID;
75 jmethodID AwtPrintControl::getPrinterID;
76 jmethodID AwtPrintControl::setPrinterID;
77 jmethodID AwtPrintControl::getResID;
78 jmethodID AwtPrintControl::getSidesID;
79 jmethodID AwtPrintControl::getToPageID;
80 jmethodID AwtPrintControl::setToPageID;
81 jmethodID AwtPrintControl::setNativeAttID;
82 jmethodID AwtPrintControl::setRangeCopiesID;
83 jmethodID AwtPrintControl::setResID;
84 jmethodID AwtPrintControl::setJobAttributesID;
85
86
87 BOOL AwtPrintControl::IsSupportedLevel(HANDLE hPrinter, DWORD dwLevel) {
88 BOOL isSupported = FALSE;
89 DWORD cbBuf = 0;
90 LPBYTE pPrinter = NULL;
91
92 DASSERT(hPrinter != NULL);
93
94 VERIFY(::GetPrinter(hPrinter, dwLevel, NULL, 0, &cbBuf) == 0);
95 if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
96 pPrinter = new BYTE[cbBuf];
97 if (::GetPrinter(hPrinter, dwLevel, pPrinter, cbBuf, &cbBuf)) {
98 isSupported = TRUE;
99 }
100 delete[] pPrinter;
101 }
102
103 return isSupported;
104 }
105
106 BOOL AwtPrintControl::FindPrinter(jstring printerName, LPBYTE pPrinterEnum,
107 LPDWORD pcbBuf, LPTSTR * foundPrinter,
108 LPTSTR * foundPort)
109 {
110 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
111
112 DWORD cReturned = 0;
113
114 if (pPrinterEnum == NULL) {
115 // Compute size of buffer
116 DWORD cbNeeded = 0;
117 ::EnumPrinters(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS,
118 NULL, 2, NULL, 0, &cbNeeded, &cReturned);
119 ::EnumPrinters(PRINTER_ENUM_LOCAL,
120 NULL, 5, NULL, 0, pcbBuf, &cReturned);
121 if (cbNeeded > (*pcbBuf)) {
122 *pcbBuf = cbNeeded;
123 }
124 return TRUE;
125 }
126
127 DASSERT(printerName != NULL);
128
129 DWORD cbBuf = *pcbBuf, dummyWord = 0;
130
131 JavaStringBuffer printerNameBuf(env, printerName);
132 LPTSTR lpcPrinterName = (LPTSTR)printerNameBuf;
133 DASSERT(lpcPrinterName != NULL);
134
135 // For NT, first do a quick check of all remote and local printers.
136 // This only allows us to search by name, though. PRINTER_INFO_4
137 // doesn't support port searches. So, if the user has specified the
138 // printer name as "LPT1:" (even though this is actually a port
139 // name), we won't find the printer here.
140 if (!::EnumPrinters(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS,
141 NULL, 4, pPrinterEnum, cbBuf, &dummyWord, &cReturned)) {
142 return FALSE;
143 }
144
145 for (DWORD i = 0; i < cReturned; i++) {
146 PRINTER_INFO_4 *info4 = (PRINTER_INFO_4 *)
147 (pPrinterEnum + i * sizeof(PRINTER_INFO_4));
148 if (info4->pPrinterName != NULL &&
149 _tcsicmp(lpcPrinterName, info4->pPrinterName) == 0) {
150
151 // Fix for BugTraq Id 4281380.
152 // Get the port name since some drivers may require
153 // this name to be passed to ::DeviceCapabilities().
154 HANDLE hPrinter = NULL;
155 if (::OpenPrinter(info4->pPrinterName, &hPrinter, NULL)) {
156 // Fix for BugTraq Id 4286812.
157 // Some drivers don't support PRINTER_INFO_5.
158 // In this case we try PRINTER_INFO_2, and if that
159 // isn't supported as well return NULL port name.
160 try {
161 if (AwtPrintControl::IsSupportedLevel(hPrinter, 5)) {
162 VERIFY(::GetPrinter(hPrinter, 5, pPrinterEnum, cbBuf,
163 &dummyWord));
164 PRINTER_INFO_5 *info5 = (PRINTER_INFO_5 *)pPrinterEnum;
165 *foundPrinter = info5->pPrinterName;
166 // pPortName may specify multiple ports. We only want one.
167 *foundPort = (info5->pPortName != NULL)
168 ? _tcstok(info5->pPortName, TEXT(",")) : NULL;
169 } else if (AwtPrintControl::IsSupportedLevel(hPrinter, 2)) {
170 VERIFY(::GetPrinter(hPrinter, 2, pPrinterEnum, cbBuf,
171 &dummyWord));
172 PRINTER_INFO_2 *info2 = (PRINTER_INFO_2 *)pPrinterEnum;
173 *foundPrinter = info2->pPrinterName;
174 // pPortName may specify multiple ports. We only want one.
175 *foundPort = (info2->pPortName != NULL)
176 ? _tcstok(info2->pPortName, TEXT(",")) : NULL;
177 } else {
178 *foundPrinter = info4->pPrinterName;
179 // We failed to determine port name for the found printer.
180 *foundPort = NULL;
181 }
182 } catch (std::bad_alloc&) {
183 VERIFY(::ClosePrinter(hPrinter));
184 throw;
185 }
186
187 VERIFY(::ClosePrinter(hPrinter));
188
189 return TRUE;
190 }
191
192 return FALSE;
193 }
194 }
195
196 // We still haven't found the printer, /* or we're using 95/98. */
197 // PRINTER_INFO_5 supports both printer name and port name, so
198 // we'll test both. On NT, PRINTER_ENUM_LOCAL means just local
199 // printers. This is what we want, because we already tested all
200 // remote printer names above (and remote printer port names are
201 // the same as remote printer names). On 95/98, PRINTER_ENUM_LOCAL
202 // means both remote and local printers. This is also what we want
203 // because we haven't tested any printers yet.
204 if (!::EnumPrinters(PRINTER_ENUM_LOCAL,
205 NULL, 5, pPrinterEnum, cbBuf, &dummyWord, &cReturned)) {
206 return FALSE;
207 }
208
209 for (DWORD i = 0; i < cReturned; i++) {
210 PRINTER_INFO_5 *info5 = (PRINTER_INFO_5 *)
211 (pPrinterEnum + i * sizeof(PRINTER_INFO_5));
212 // pPortName can specify multiple ports. Test them one at
213 // a time.
214 if (info5->pPortName != NULL) {
215 LPTSTR port = _tcstok(info5->pPortName, TEXT(","));
216 while (port != NULL) {
217 if (_tcsicmp(lpcPrinterName, port) == 0) {
218 *foundPrinter = info5->pPrinterName;
219 *foundPort = port;
220 return TRUE;
221 }
222 port = _tcstok(NULL, TEXT(","));
223 }
224 }
225 }
226
227 return FALSE;
228 }
229
230
231 void AwtPrintControl::initIDs(JNIEnv *env, jclass cls)
232 {
233 TRY;
234
235 jclass cls = env->FindClass("sun/awt/windows/WPrinterJob");
236 CHECK_NULL(cls);
237
238 AwtPrintControl::dialogOwnerPeerID =
239 env->GetFieldID(cls, "dialogOwnerPeer", "Ljava/awt/peer/ComponentPeer;");
240 DASSERT(AwtPrintControl::dialogOwnerPeerID != NULL);
241 CHECK_NULL(AwtPrintControl::dialogOwnerPeerID);
242
243 AwtPrintControl::getPrintDCID = env->GetMethodID(cls, "getPrintDC", "()J");
244 DASSERT(AwtPrintControl::getPrintDCID != NULL);
245 CHECK_NULL(AwtPrintControl::getPrintDCID);
246
247 AwtPrintControl::setPrintDCID =
248 env->GetMethodID(cls, "setPrintDC", "(J)V");
249 DASSERT(AwtPrintControl::setPrintDCID != NULL);
250 CHECK_NULL(AwtPrintControl::setPrintDCID);
251
252 AwtPrintControl::getDevmodeID = env->GetMethodID(cls, "getDevMode", "()J");
253 DASSERT(AwtPrintControl::getDevmodeID != NULL);
254 CHECK_NULL(AwtPrintControl::getDevmodeID);
255
256 AwtPrintControl::setDevmodeID =
257 env->GetMethodID(cls, "setDevMode", "(J)V");
258 DASSERT(AwtPrintControl::setDevmodeID != NULL);
259 CHECK_NULL(AwtPrintControl::setDevmodeID);
260
261 AwtPrintControl::getDevnamesID =
262 env->GetMethodID(cls, "getDevNames", "()J");
263 DASSERT(AwtPrintControl::getDevnamesID != NULL);
264 CHECK_NULL(AwtPrintControl::getDevnamesID);
265
266 AwtPrintControl::setDevnamesID =
267 env->GetMethodID(cls, "setDevNames", "(J)V");
268 DASSERT(AwtPrintControl::setDevnamesID != NULL);
269 CHECK_NULL(AwtPrintControl::setDevnamesID);
270
271 AwtPrintControl::driverDoesMultipleCopiesID =
272 env->GetFieldID(cls, "driverDoesMultipleCopies", "Z");
273 DASSERT(AwtPrintControl::driverDoesMultipleCopiesID != NULL);
274 CHECK_NULL(AwtPrintControl::driverDoesMultipleCopiesID);
275
276 AwtPrintControl::driverDoesCollationID =
277 env->GetFieldID(cls, "driverDoesCollation", "Z");
278 DASSERT(AwtPrintControl::driverDoesCollationID != NULL);
279 CHECK_NULL(AwtPrintControl::driverDoesCollationID);
280
281 AwtPrintControl::getCopiesID =
282 env->GetMethodID(cls, "getCopiesAttrib", "()I");
283 DASSERT(AwtPrintControl::getCopiesID != NULL);
284 CHECK_NULL(AwtPrintControl::getCopiesID);
285
286 AwtPrintControl::getCollateID =
287 env->GetMethodID(cls, "getCollateAttrib","()I");
288 DASSERT(AwtPrintControl::getCollateID != NULL);
289 CHECK_NULL(AwtPrintControl::getCollateID);
290
291 AwtPrintControl::getOrientID =
292 env->GetMethodID(cls, "getOrientAttrib", "()I");
293 DASSERT(AwtPrintControl::getOrientID != NULL);
294 CHECK_NULL(AwtPrintControl::getOrientID);
295
296 AwtPrintControl::getFromPageID =
297 env->GetMethodID(cls, "getFromPageAttrib", "()I");
298 DASSERT(AwtPrintControl::getFromPageID != NULL);
299 CHECK_NULL(AwtPrintControl::getFromPageID);
300
301 AwtPrintControl::getToPageID =
302 env->GetMethodID(cls, "getToPageAttrib", "()I");
303 DASSERT(AwtPrintControl::getToPageID != NULL);
304 CHECK_NULL(AwtPrintControl::getToPageID);
305
306 AwtPrintControl::getMinPageID =
307 env->GetMethodID(cls, "getMinPageAttrib", "()I");
308 DASSERT(AwtPrintControl::getMinPageID != NULL);
309 CHECK_NULL(AwtPrintControl::getMinPageID);
310
311 AwtPrintControl::getMaxPageID =
312 env->GetMethodID(cls, "getMaxPageAttrib", "()I");
313 DASSERT(AwtPrintControl::getMaxPageID != NULL);
314 CHECK_NULL(AwtPrintControl::getMaxPageID);
315
316 AwtPrintControl::getDestID =
317 env->GetMethodID(cls, "getDestAttrib", "()Z");
318 DASSERT(AwtPrintControl::getDestID != NULL);
319 CHECK_NULL(AwtPrintControl::getDestID);
320
321 AwtPrintControl::getQualityID =
322 env->GetMethodID(cls, "getQualityAttrib", "()I");
323 DASSERT(AwtPrintControl::getQualityID != NULL);
324 CHECK_NULL(AwtPrintControl::getQualityID);
325
326 AwtPrintControl::getColorID =
327 env->GetMethodID(cls, "getColorAttrib", "()I");
328 DASSERT(AwtPrintControl::getColorID != NULL);
329 CHECK_NULL(AwtPrintControl::getColorID);
330
331 AwtPrintControl::getSidesID =
332 env->GetMethodID(cls, "getSidesAttrib", "()I");
333 DASSERT(AwtPrintControl::getSidesID != NULL);
334 CHECK_NULL(AwtPrintControl::getSidesID);
335
336 AwtPrintControl::getPrinterID =
337 env->GetMethodID(cls, "getPrinterAttrib", "()Ljava/lang/String;");
338 DASSERT(AwtPrintControl::getPrinterID != NULL);
339 CHECK_NULL(AwtPrintControl::getPrinterID);
340
341 AwtPrintControl::getWin32MediaID =
342 env->GetMethodID(cls, "getWin32MediaAttrib", "()[I");
343 DASSERT(AwtPrintControl::getWin32MediaID != NULL);
344 CHECK_NULL(AwtPrintControl::getWin32MediaID);
345
346 AwtPrintControl::setWin32MediaID =
347 env->GetMethodID(cls, "setWin32MediaAttrib", "(III)V");
348 DASSERT(AwtPrintControl::setWin32MediaID != NULL);
349 CHECK_NULL(AwtPrintControl::setWin32MediaID);
350
351 AwtPrintControl::getWin32MediaTrayID =
352 env->GetMethodID(cls, "getMediaTrayAttrib", "()I");
353 DASSERT(AwtPrintControl::getWin32MediaTrayID != NULL);
354 CHECK_NULL(AwtPrintControl::getWin32MediaTrayID);
355
356 AwtPrintControl::setWin32MediaTrayID =
357 env->GetMethodID(cls, "setMediaTrayAttrib", "(I)V");
358 DASSERT(AwtPrintControl::setWin32MediaTrayID != NULL);
359 CHECK_NULL(AwtPrintControl::setWin32MediaTrayID);
360
361 AwtPrintControl::getSelectID =
362 env->GetMethodID(cls, "getSelectAttrib", "()I");
363 DASSERT(AwtPrintControl::getSelectID != NULL);
364 CHECK_NULL(AwtPrintControl::getSelectID);
365
366 AwtPrintControl::getPrintToFileEnabledID =
367 env->GetMethodID(cls, "getPrintToFileEnabled", "()Z");
368 DASSERT(AwtPrintControl::getPrintToFileEnabledID != NULL);
369 CHECK_NULL(AwtPrintControl::getPrintToFileEnabledID);
370
371 AwtPrintControl::setNativeAttID =
372 env->GetMethodID(cls, "setNativeAttributes", "(III)V");
373 DASSERT(AwtPrintControl::setNativeAttID != NULL);
374 CHECK_NULL(AwtPrintControl::setNativeAttID);
375
376 AwtPrintControl::setRangeCopiesID =
377 env->GetMethodID(cls, "setRangeCopiesAttribute", "(IIZI)V");
378 DASSERT(AwtPrintControl::setRangeCopiesID != NULL);
379 CHECK_NULL(AwtPrintControl::setRangeCopiesID);
380
381 AwtPrintControl::setResID =
382 env->GetMethodID(cls, "setResolutionDPI", "(II)V");
383 DASSERT(AwtPrintControl::setResID != NULL);
384 CHECK_NULL(AwtPrintControl::setResID);
385
386 AwtPrintControl::setPrinterID =
387 env->GetMethodID(cls, "setPrinterNameAttrib", "(Ljava/lang/String;)V");
388 DASSERT(AwtPrintControl::setPrinterID != NULL);
389 CHECK_NULL(AwtPrintControl::setPrinterID);
390
391 AwtPrintControl::setJobAttributesID =
392 env->GetMethodID(cls, "setJobAttributes",
393 "(Ljavax/print/attribute/PrintRequestAttributeSet;IISSSSSSS)V");
394 DASSERT(AwtPrintControl::setJobAttributesID != NULL);
395 CHECK_NULL(AwtPrintControl::setJobAttributesID);
396
397 CATCH_BAD_ALLOC;
398 }
399
400 BOOL CALLBACK PrintDlgHook(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam)
401 {
402 TRY;
403
404 if (iMsg == WM_INITDIALOG) {
405 SetForegroundWindow(hDlg);
406 return FALSE;
407 }
408 return FALSE;
409
410 CATCH_BAD_ALLOC_RET(TRUE);
411 }
412
413 BOOL AwtPrintControl::CreateDevModeAndDevNames(PRINTDLG *ppd,
414 LPTSTR pPrinterName,
415 LPTSTR pPortName)
416 {
417 DWORD cbNeeded = 0;
418 LPBYTE pPrinter = NULL;
419 BOOL retval = FALSE;
420 HANDLE hPrinter;
421
422 try {
423 if (!::OpenPrinter(pPrinterName, &hPrinter, NULL)) {
424 goto done;
425 }
426 VERIFY(::GetPrinter(hPrinter, 2, NULL, 0, &cbNeeded) == 0);
427 if (::GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
428 goto done;
429 }
430 pPrinter = new BYTE[cbNeeded];
431 if (!::GetPrinter(hPrinter, 2, pPrinter, cbNeeded, &cbNeeded)) {
432 goto done;
433 }
434 PRINTER_INFO_2 *info2 = (PRINTER_INFO_2 *)pPrinter;
435
436 // Create DEVMODE, if it exists.
437 if (info2->pDevMode != NULL) {
438 size_t devmodeSize =
439 sizeof(DEVMODE) + info2->pDevMode->dmDriverExtra;
440 ppd->hDevMode = ::GlobalAlloc(GHND, devmodeSize);
441 if (ppd->hDevMode == NULL) {
442 throw std::bad_alloc();
443 }
444 DEVMODE *devmode = (DEVMODE *)::GlobalLock(ppd->hDevMode);
445 DASSERT(!::IsBadWritePtr(devmode, devmodeSize));
446 memcpy(devmode, info2->pDevMode, devmodeSize);
447 VERIFY(::GlobalUnlock(ppd->hDevMode) == 0);
448 DASSERT(::GetLastError() == NO_ERROR);
449 }
450
451 // Create DEVNAMES.
452 if (pPortName != NULL) {
453 info2->pPortName = pPortName;
454 } else if (info2->pPortName != NULL) {
455 // pPortName may specify multiple ports. We only want one.
456 info2->pPortName = _tcstok(info2->pPortName, TEXT(","));
457 }
458
459 size_t lenDriverName = ((info2->pDriverName != NULL)
460 ? _tcslen(info2->pDriverName)
461 : 0) + 1;
462 size_t lenPrinterName = ((pPrinterName != NULL)
463 ? _tcslen(pPrinterName)
464 : 0) + 1;
465 size_t lenOutputName = ((info2->pPortName != NULL)
466 ? _tcslen(info2->pPortName)
467 : 0) + 1;
468 size_t devnameSize= sizeof(DEVNAMES) +
469 lenDriverName*sizeof(TCHAR) +
470 lenPrinterName*sizeof(TCHAR) +
471 lenOutputName*sizeof(TCHAR);
472
473 ppd->hDevNames = ::GlobalAlloc(GHND, devnameSize);
474 if (ppd->hDevNames == NULL) {
475 throw std::bad_alloc();
476 }
477
478 DEVNAMES *devnames =
479 (DEVNAMES *)::GlobalLock(ppd->hDevNames);
480 DASSERT(!IsBadWritePtr(devnames, devnameSize));
481 LPTSTR lpcDevnames = (LPTSTR)devnames;
482
483 // note: all sizes are in characters, not in bytes
484 devnames->wDriverOffset = sizeof(DEVNAMES)/sizeof(TCHAR);
485 devnames->wDeviceOffset =
486 static_cast<WORD>(sizeof(DEVNAMES)/sizeof(TCHAR) + lenDriverName);
487 devnames->wOutputOffset =
488 static_cast<WORD>(sizeof(DEVNAMES)/sizeof(TCHAR) + lenDriverName + lenPrinterName);
489 if (info2->pDriverName != NULL) {
490 _tcscpy_s(lpcDevnames + devnames->wDriverOffset, devnameSize - devnames->wDriverOffset, info2->pDriverName);
491 } else {
492 *(lpcDevnames + devnames->wDriverOffset) = _T('\0');
493 }
494 if (pPrinterName != NULL) {
495 _tcscpy_s(lpcDevnames + devnames->wDeviceOffset, devnameSize - devnames->wDeviceOffset, pPrinterName);
496 } else {
497 *(lpcDevnames + devnames->wDeviceOffset) = _T('\0');
498 }
499 if (info2->pPortName != NULL) {
500 _tcscpy_s(lpcDevnames + devnames->wOutputOffset, devnameSize - devnames->wOutputOffset, info2->pPortName);
501 } else {
502 *(lpcDevnames + devnames->wOutputOffset) = _T('\0');
503 }
504 VERIFY(::GlobalUnlock(ppd->hDevNames) == 0);
505 DASSERT(::GetLastError() == NO_ERROR);
506 } catch (std::bad_alloc&) {
507 if (ppd->hDevNames != NULL) {
508 VERIFY(::GlobalFree(ppd->hDevNames) == NULL);
509 ppd->hDevNames = NULL;
510 }
511 if (ppd->hDevMode != NULL) {
512 VERIFY(::GlobalFree(ppd->hDevMode) == NULL);
513 ppd->hDevMode = NULL;
514 }
515 delete [] pPrinter;
516 VERIFY(::ClosePrinter(hPrinter));
517 hPrinter = NULL;
518 throw;
519 }
520
521 retval = TRUE;
522
523 done:
524 delete [] pPrinter;
525 if (hPrinter) {
526 VERIFY(::ClosePrinter(hPrinter));
527 hPrinter = NULL;
528 }
529
530 return retval;
531 }
532
533
534 WORD AwtPrintControl::getNearestMatchingPaper(LPTSTR printer, LPTSTR port,
535 double origWid, double origHgt,
536 double* newWid, double *newHgt) {
537 const double epsilon = 0.50;
538 const double tolerance = (1.0 * 72.0); // # inches * 72
539 int numPaperSizes = 0;
540 WORD *papers = NULL;
541 POINT *paperSizes = NULL;
542
543 if ((printer== NULL) || (port == NULL)) {
544 return 0;
545 }
546
547 SAVE_CONTROLWORD
548 numPaperSizes = (int)DeviceCapabilities(printer, port, DC_PAPERSIZE,
549 NULL, NULL);
550
551 if (numPaperSizes > 0) {
552 papers = (WORD*)SAFE_SIZE_ARRAY_ALLOC(safe_Malloc, sizeof(WORD), numPaperSizes);
553 paperSizes = (POINT *)SAFE_SIZE_ARRAY_ALLOC(safe_Malloc, sizeof(*paperSizes),
554 numPaperSizes);
555
556 DWORD result1 = DeviceCapabilities(printer, port,
557 DC_PAPERS, (LPTSTR) papers, NULL);
558
559 DWORD result2 = DeviceCapabilities(printer, port,
560 DC_PAPERSIZE, (LPTSTR) paperSizes,
561 NULL);
562
563 // REMIND: cache in papers and paperSizes
564 if (result1 == -1 || result2 == -1 ) {
565 free((LPTSTR) papers);
566 papers = NULL;
567 free((LPTSTR) paperSizes);
568 paperSizes = NULL;
569 }
570 }
571 RESTORE_CONTROLWORD
572
573 double closestWid = 0.0;
574 double closestHgt = 0.0;
575 WORD closestMatch = 0;
576
577 if (paperSizes != NULL) {
578
579 /* Paper sizes are in 0.1mm units. Convert to 1/72"
580 * For each paper size, compute the difference from the paper size
581 * passed in. Use a least-squares difference, so paper much different
582 * in x or y should score poorly
583 */
584 double diffw = origWid;
585 double diffh = origHgt;
586 double least_square = diffw * diffw + diffh * diffh;
587 double tmp_ls;
588 double widpts, hgtpts;
589
590 for (int i=0;i<numPaperSizes;i++) {
591 widpts = paperSizes[i].x * LOMETRIC_TO_POINTS;
592 hgtpts = paperSizes[i].y * LOMETRIC_TO_POINTS;
593
594 if ((fabs(origWid - widpts) < epsilon) &&
595 (fabs(origHgt - hgtpts) < epsilon)) {
596 closestWid = origWid;
597 closestHgt = origHgt;
598 closestMatch = papers[i];
599 break;
600 }
601
602 diffw = fabs(widpts - origWid);
603 diffh = fabs(hgtpts - origHgt);
604 tmp_ls = diffw * diffw + diffh * diffh;
605 if ((diffw < tolerance) && (diffh < tolerance) &&
606 (tmp_ls < least_square)) {
607 least_square = tmp_ls;
608 closestWid = widpts;
609 closestHgt = hgtpts;
610 closestMatch = papers[i];
611 }
612 }
613 }
614
615 if (closestWid > 0) {
616 *newWid = closestWid;
617 }
618 if (closestHgt > 0) {
619 *newHgt = closestHgt;
620 }
621
622 if (papers != NULL) {
623 free((LPTSTR)papers);
624 }
625
626 if (paperSizes != NULL) {
627 free((LPTSTR)paperSizes);
628 }
629
630 return closestMatch;
631 }
632
633 /*
634 * Copy settings into a print dialog & any devmode
635 */
636 BOOL AwtPrintControl::InitPrintDialog(JNIEnv *env,
637 jobject printCtrl, PRINTDLG &pd) {
638 HWND hwndOwner = NULL;
639 jobject dialogOwner =
640 env->GetObjectField(printCtrl, AwtPrintControl::dialogOwnerPeerID);
641 if (dialogOwner != NULL) {
642 AwtComponent *dialogOwnerComp =
643 (AwtComponent *)JNI_GET_PDATA(dialogOwner);
644
645 hwndOwner = dialogOwnerComp->GetHWnd();
646 env->DeleteLocalRef(dialogOwner);
647 dialogOwner = NULL;
648 }
649 jobject mdh = NULL;
650 jobject dest = NULL;
651 jobject select = NULL;
652 jobject dialog = NULL;
653 LPTSTR printName = NULL;
654 LPTSTR portName = NULL;
655
656 // If the user didn't specify a printer, then this call returns the
657 // name of the default printer.
658 jstring printerName = (jstring)
659 env->CallObjectMethod(printCtrl, AwtPrintControl::getPrinterID);
660
661 if (printerName != NULL) {
662
663 pd.hDevMode = AwtPrintControl::getPrintHDMode(env, printCtrl);
664 pd.hDevNames = AwtPrintControl::getPrintHDName(env, printCtrl);
665
666 LPTSTR getName = (LPTSTR)JNU_GetStringPlatformChars(env,
667 printerName, NULL);
668 if (getName == NULL) {
669 env->DeleteLocalRef(printerName);
670 throw std::bad_alloc();
671 }
672
673 BOOL samePrinter = FALSE;
674
675 // check if given printername is same as the currently saved printer
676 if (pd.hDevNames != NULL ) {
677
678 DEVNAMES *devnames = (DEVNAMES *)::GlobalLock(pd.hDevNames);
679 if (devnames != NULL) {
680 LPTSTR lpdevnames = (LPTSTR)devnames;
681 printName = lpdevnames+devnames->wDeviceOffset;
682
683 if (!_tcscmp(printName, getName)) {
684
685 samePrinter = TRUE;
686 printName = _tcsdup(lpdevnames+devnames->wDeviceOffset);
687 portName = _tcsdup(lpdevnames+devnames->wOutputOffset);
688
689 }
690 }
691 ::GlobalUnlock(pd.hDevNames);
692 }
693
694 if (!samePrinter) {
695 LPTSTR foundPrinter = NULL;
696 LPTSTR foundPort = NULL;
697 DWORD cbBuf = 0;
698 VERIFY(AwtPrintControl::FindPrinter(NULL, NULL, &cbBuf,
699 NULL, NULL));
700 LPBYTE buffer = new BYTE[cbBuf];
701
702 if (AwtPrintControl::FindPrinter(printerName, buffer, &cbBuf,
703 &foundPrinter, &foundPort) &&
704 (foundPrinter != NULL) && (foundPort != NULL)) {
705
706 printName = _tcsdup(foundPrinter);
707 portName = _tcsdup(foundPort);
708
709 if (!AwtPrintControl::CreateDevModeAndDevNames(&pd,
710 foundPrinter, foundPort)) {
711 delete [] buffer;
712 if (printName != NULL) {
713 free(printName);
714 }
715 if (portName != NULL) {
716 free(portName);
717 }
718 env->DeleteLocalRef(printerName);
719 return FALSE;
720 }
721
722 DASSERT(pd.hDevNames != NULL);
723 } else {
724 delete [] buffer;
725 if (printName != NULL) {
726 free(printName);
727 }
728 if (portName != NULL) {
729 free(portName);
730 }
731 env->DeleteLocalRef(printerName);
732 return FALSE;
733 }
734
735 delete [] buffer;
736 }
737 env->DeleteLocalRef(printerName);
738 // PrintDlg may change the values of hDevMode and hDevNames so we
739 // re-initialize our saved handles.
740 AwtPrintControl::setPrintHDMode(env, printCtrl, NULL);
741 AwtPrintControl::setPrintHDName(env, printCtrl, NULL);
742 } else {
743
744 // There is no default printer. This means that there are no
745 // printers installed at all.
746
747 if (printName != NULL) {
748 free(printName);
749 }
750 if (portName != NULL) {
751 free(portName);
752 }
753 // Returning TRUE means try to display the native print dialog
754 // which will either display an error message or prompt the
755 // user to install a printer.
756 return TRUE;
757 }
758
759 // Now, set-up the struct for the real calls to ::PrintDlg and ::CreateDC
760
761 pd.hwndOwner = hwndOwner;
762 pd.Flags = PD_ENABLEPRINTHOOK | PD_RETURNDC | PD_USEDEVMODECOPIESANDCOLLATE;
763 pd.lpfnPrintHook = (LPPRINTHOOKPROC)PrintDlgHook;
764
765 pd.nFromPage = (WORD)env->CallIntMethod(printCtrl,
766 AwtPrintControl::getFromPageID);
767 pd.nToPage = (WORD)env->CallIntMethod(printCtrl,
768 AwtPrintControl::getToPageID);
769 pd.nMinPage = (WORD)env->CallIntMethod(printCtrl,
770 AwtPrintControl::getMinPageID);
771 jint maxPage = env->CallIntMethod(printCtrl,
772 AwtPrintControl::getMaxPageID);
773 pd.nMaxPage = (maxPage <= (jint)((WORD)-1)) ? (WORD)maxPage : (WORD)-1;
774 // In the event that the application displays the dialog before
775 // installing a Printable, but sets a page range, then max page will be 1
776 // since the default state of a PrinterJob is an empty "Book" Pageable.
777 // Windows pops up an error dialog in such a case which isn't very
778 // forthcoming about the exact problem.
779 // So if we detect this fix up such a problem here.
780 if (pd.nMinPage > pd.nFromPage) pd.nMinPage = pd.nFromPage;
781 if (pd.nMaxPage < pd.nToPage) pd.nMaxPage = pd.nToPage;
782 if (pd.nToPage > pd.nFromPage && (pd.nFromPage > pd.nMinPage || pd.nToPage < pd.nMaxPage)) {
783 pd.Flags |= PD_PAGENUMS;
784 }
785
786 if (env->CallBooleanMethod(printCtrl,
787 AwtPrintControl::getDestID)) {
788 pd.Flags |= PD_PRINTTOFILE;
789 }
790
791 jint selectType = env->CallIntMethod(printCtrl,
792 AwtPrintControl::getSelectID);
793
794 // selectType identifies whether No selection (2D) or
795 // SunPageSelection (AWT)
796 if (selectType != 0) {
797 pd.Flags |= selectType;
798 }
799
800 if (!env->CallBooleanMethod(printCtrl,
801 AwtPrintControl::getPrintToFileEnabledID)) {
802 pd.Flags |= PD_DISABLEPRINTTOFILE;
803 }
804
805 if (pd.hDevMode != NULL) {
806 DEVMODE *devmode = (DEVMODE *)::GlobalLock(pd.hDevMode);
807 DASSERT(!IsBadWritePtr(devmode, sizeof(DEVMODE)));
808
809 WORD copies = (WORD)env->CallIntMethod(printCtrl,
810 AwtPrintControl::getCopiesID);
811 if (copies > 0) {
812 devmode->dmFields |= DM_COPIES;
813 devmode->dmCopies = copies;
814 }
815
816 jint orient = env->CallIntMethod(printCtrl,
817 AwtPrintControl::getOrientID);
818 if (orient == 0) { // PageFormat.LANDSCAPE == 0
819 devmode->dmFields |= DM_ORIENTATION;
820 devmode->dmOrientation = DMORIENT_LANDSCAPE;
821 } else if (orient == 1) { // PageFormat.PORTRAIT == 1
822 devmode->dmFields |= DM_ORIENTATION;
823 devmode->dmOrientation = DMORIENT_PORTRAIT;
824 }
825
826 // -1 means unset, so we'll accept the printer default.
827 int collate = env->CallIntMethod(printCtrl,
828 AwtPrintControl::getCollateID);
829 if (collate == 1) {
830 devmode->dmFields |= DM_COLLATE;
831 devmode->dmCollate = DMCOLLATE_TRUE;
832 } else if (collate == 0) {
833 devmode->dmFields |= DM_COLLATE;
834 devmode->dmCollate = DMCOLLATE_FALSE;
835 }
836
837 int quality = env->CallIntMethod(printCtrl,
838 AwtPrintControl::getQualityID);
839 if (quality) {
840 devmode->dmFields |= DM_PRINTQUALITY;
841 devmode->dmPrintQuality = quality;
842 }
843
844 int color = env->CallIntMethod(printCtrl,
845 AwtPrintControl::getColorID);
846 if (color) {
847 devmode->dmFields |= DM_COLOR;
848 devmode->dmColor = color;
849 }
850
851 int sides = env->CallIntMethod(printCtrl,
852 AwtPrintControl::getSidesID);
853 if (sides) {
854 devmode->dmFields |= DM_DUPLEX;
855 devmode->dmDuplex = (int)sides;
856 }
857
858 jintArray obj = (jintArray)env->CallObjectMethod(printCtrl,
859 AwtPrintControl::getWin32MediaID);
860 jboolean isCopy;
861 jint *wid_ht = env->GetIntArrayElements(obj,
862 &isCopy);
863
864 double newWid = 0.0, newHt = 0.0;
865 if (wid_ht != NULL && wid_ht[0] != 0 && wid_ht[1] != 0) {
866 devmode->dmFields |= DM_PAPERSIZE;
867 devmode->dmPaperSize = AwtPrintControl::getNearestMatchingPaper(
868 printName,
869 portName,
870 (double)wid_ht[0],
871 (double)wid_ht[1],
872 &newWid, &newHt);
873
874 }
875 env->ReleaseIntArrayElements(obj, wid_ht, 0);
876 ::GlobalUnlock(pd.hDevMode);
877 devmode = NULL;
878 }
879
880 if (printName != NULL) {
881 free(printName);
882 }
883 if (portName != NULL) {
884 free(portName);
885 }
886
887 return TRUE;
888 }
889
890
891 /*
892 * Copy settings from print dialog & any devmode back into attributes
893 * or properties.
894 */
895 extern "C" {
896 extern void setCapabilities(JNIEnv *env, jobject WPrinterJob, HDC hdc);
897 }
898 BOOL AwtPrintControl::UpdateAttributes(JNIEnv *env,
899 jobject printCtrl, PRINTDLG &pd) {
900
901 DEVNAMES *devnames = NULL;
902 DEVMODE *devmode = NULL;
903 unsigned int copies = 1;
904 DWORD pdFlags = pd.Flags;
905 DWORD dmFields = 0, dmValues = 0;
906 bool newDC = false;
907
908 // This call ensures that default PrintService gets updated for the
909 // case where initially, there weren't any printers.
910 env->CallObjectMethod(printCtrl, AwtPrintControl::getPrinterID);
911
912 if (pd.hDevMode != NULL) {
913 devmode = (DEVMODE *)::GlobalLock(pd.hDevMode);
914 DASSERT(!IsBadReadPtr(devmode, sizeof(DEVMODE)));
915 }
916
917 if (devmode != NULL) {
918 /* Query the settings we understand and are interested in.
919 * For the flags that are set in dmFields, where the values
920 * are a simple enumeration, set the same bits in a clean dmFields
921 * variable, and set bits in a dmValues variable to indicate the
922 * selected value. These can all be passed up to Java in one
923 * call to sync up the Java view of this.
924 */
925
926 if (devmode->dmFields & DM_COPIES) {
927 dmFields |= DM_COPIES;
928 copies = devmode->dmCopies;
929 if (pd.nCopies == 1) {
930 env->SetBooleanField(printCtrl,
931 driverDoesMultipleCopiesID,
932 JNI_TRUE);
933 } else {
934 copies = pd.nCopies;
935 }
936 }
937
938 if (devmode->dmFields & DM_PAPERSIZE) {
939 env->CallVoidMethod(printCtrl, AwtPrintControl::setWin32MediaID,
940 devmode->dmPaperSize, devmode->dmPaperWidth,
941 devmode->dmPaperLength);
942
943 }
944
945 if (devmode->dmFields & DM_DEFAULTSOURCE) {
946 env->CallVoidMethod(printCtrl,
947 AwtPrintControl::setWin32MediaTrayID,
948 devmode->dmDefaultSource);
949 }
950
951 if (devmode->dmFields & DM_COLOR) {
952 dmFields |= DM_COLOR;
953 if (devmode->dmColor == DMCOLOR_COLOR) {
954 dmValues |= SET_COLOR;
955 }
956 }
957
958 if (devmode->dmFields & DM_ORIENTATION) {
959 dmFields |= DM_ORIENTATION;
960 if (devmode->dmOrientation == DMORIENT_LANDSCAPE) {
961 dmValues |= SET_ORIENTATION;
962 }
963 }
964
965 if (devmode->dmFields & DM_COLLATE) {
966 dmFields |= DM_COLLATE;
967 if (devmode->dmCollate == DMCOLLATE_TRUE) {
968 pdFlags |= PD_COLLATE;
969 env->SetBooleanField(printCtrl,
970 driverDoesCollationID,
971 JNI_TRUE);
972 } else {
973 pdFlags &= ~PD_COLLATE;
974 }
975 }
976
977 if (devmode->dmFields & DM_PRINTQUALITY) {
978 /* value < 0 indicates quality setting.
979 * value > 0 indicates X resolution. In that case
980 * hopefully we will also find y-resolution specified.
981 * If its not, assume its the same as x-res.
982 * Maybe Java code should try to reconcile this against
983 * the printers claimed set of supported resolutions.
984 */
985 if (devmode->dmPrintQuality < 0) {
986 if (dmFields |= DM_PRINTQUALITY) {
987 if (devmode->dmPrintQuality == DMRES_HIGH) {
988 dmValues |= SET_RES_HIGH;
989 } else if ((devmode->dmPrintQuality == DMRES_LOW) ||
990 (devmode->dmPrintQuality == DMRES_DRAFT)) {
991 dmValues |= SET_RES_LOW;
992 } else if (devmode->dmPrintQuality == DMRES_MEDIUM) {
993 /* default */
994 }
995 }
996 } else {
997 int xRes = devmode->dmPrintQuality;
998 int yRes = (devmode->dmFields & DM_YRESOLUTION) ?
999 devmode->dmYResolution : devmode->dmPrintQuality;
1000 env->CallVoidMethod(printCtrl, AwtPrintControl::setResID,
1001 xRes, yRes);
1002 }
1003 }
1004
1005 if (devmode->dmFields & DM_DUPLEX) {
1006 dmFields |= DM_DUPLEX;
1007 if (devmode->dmDuplex == DMDUP_HORIZONTAL) {
1008 dmValues |= SET_DUP_HORIZONTAL;
1009 } else if (devmode->dmDuplex == DMDUP_VERTICAL) {
1010 dmValues |= SET_DUP_VERTICAL;
1011 }
1012 }
1013
1014
1015 ::GlobalUnlock(pd.hDevMode);
1016 devmode = NULL;
1017 } else {
1018 copies = pd.nCopies;
1019 }
1020
1021 if (pd.hDevNames != NULL) {
1022 DEVNAMES *devnames = (DEVNAMES*)::GlobalLock(pd.hDevNames);
1023 DASSERT(!IsBadReadPtr(devnames, sizeof(DEVNAMES)));
1024 LPTSTR lpcNames = (LPTSTR)devnames;
1025 LPTSTR pbuf = (_tcslen(lpcNames + devnames->wDeviceOffset) == 0 ?
1026 TEXT("") : lpcNames + devnames->wDeviceOffset);
1027 if (pbuf != NULL) {
1028 jstring jstr = JNU_NewStringPlatform(env, pbuf);
1029 env->CallVoidMethod(printCtrl,
1030 AwtPrintControl::setPrinterID,
1031 jstr);
1032 env->DeleteLocalRef(jstr);
1033 }
1034 pbuf = (_tcslen(lpcNames + devnames->wOutputOffset) == 0 ?
1035 TEXT("") : lpcNames + devnames->wOutputOffset);
1036 if (pbuf != NULL) {
1037 if (wcscmp(pbuf, L"FILE:") == 0) {
1038 pdFlags |= PD_PRINTTOFILE;
1039 }
1040 }
1041 ::GlobalUnlock(pd.hDevNames);
1042 devnames = NULL;
1043 }
1044
1045
1046 env->CallVoidMethod(printCtrl, AwtPrintControl::setNativeAttID,
1047 pdFlags, dmFields, dmValues);
1048
1049
1050 // copies & range are always set so no need to check for any flags
1051 env->CallVoidMethod(printCtrl, AwtPrintControl::setRangeCopiesID,
1052 pd.nFromPage, pd.nToPage, (pdFlags & PD_PAGENUMS),
1053 copies);
1054
1055 // repeated calls to printDialog should not leak handles
1056 HDC oldDC = AwtPrintControl::getPrintDC(env, printCtrl);
1057 if (pd.hDC != oldDC) {
1058 if (oldDC != NULL) {
1059 ::DeleteDC(oldDC);
1060 }
1061 AwtPrintControl::setPrintDC(env, printCtrl, pd.hDC);
1062 newDC = true;
1063 }
1064 // Need to update WPrinterJob with device resolution settings for
1065 // new or changed DC.
1066 setCapabilities(env, printCtrl, pd.hDC);
1067
1068 HGLOBAL oldG = AwtPrintControl::getPrintHDMode(env, printCtrl);
1069 if (pd.hDevMode != oldG) {
1070 AwtPrintControl::setPrintHDMode(env, printCtrl, pd.hDevMode);
1071 }
1072
1073 oldG = AwtPrintControl::getPrintHDName(env, printCtrl);
1074 if (pd.hDevNames != oldG) {
1075 AwtPrintControl::setPrintHDName(env, printCtrl, pd.hDevNames);
1076 }
1077
1078 return newDC;
1079 }
1080
1081
1082 BOOL AwtPrintControl::getDevmode( HANDLE hPrinter,
1083 LPTSTR printerName,
1084 LPDEVMODE *pDevMode) {
1085
1086 if (hPrinter == NULL || printerName == NULL || pDevMode == NULL) {
1087 return FALSE;
1088 }
1089
1090 SAVE_CONTROLWORD
1091
1092 DWORD dwNeeded = ::DocumentProperties(NULL, hPrinter, printerName,
1093 NULL, NULL, 0);
1094
1095 RESTORE_CONTROLWORD
1096
1097 if (dwNeeded <= 0) {
1098 *pDevMode = NULL;
1099 return FALSE;
1100 }
1101
1102 *pDevMode = (LPDEVMODE)GlobalAlloc(GPTR, dwNeeded);
1103
1104 if (*pDevMode == NULL) {
1105 return FALSE;
1106 }
1107
1108 DWORD dwRet = ::DocumentProperties(NULL,
1109 hPrinter,
1110 printerName,
1111 *pDevMode,
1112 NULL,
1113 DM_OUT_BUFFER);
1114
1115 RESTORE_CONTROLWORD
1116
1117 if (dwRet != IDOK) {
1118 /* if failure, cleanup and return failure */
1119 GlobalFree(pDevMode);
1120 *pDevMode = NULL;
1121 return FALSE;
1122 }
1123
1124 return TRUE;
1125 }
--- EOF ---