Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qwindowsprintdevice.cpp
Go to the documentation of this file.
1// Copyright (C) 2014 John Layt <jlayt@kde.org>
2// Copyright (C) 2018 The Qt Company Ltd.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4// Qt-Security score:significant reason:default
5
7
8#include <QtCore/qdebug.h>
9
10#ifndef DC_COLLATE
11# define DC_COLLATE 22
12#endif
13
15
16using WindowsPrinterLookup = QList<QWindowsPrinterInfo>;
18
19extern qreal qt_pointMultiplier(QPageLayout::Unit unit);
20
21static inline uint qwcsnlen(const wchar_t *str, uint maxlen)
22{
23 uint length = 0;
24 if (str) {
25 while (length < maxlen && *str++)
26 length++;
27 }
28 return length;
29}
30
31static LPDEVMODE getDevmode(HANDLE hPrinter, const QString &printerId)
32{
33 LPWSTR printerIdUtf16 = const_cast<LPWSTR>(reinterpret_cast<LPCWSTR>(printerId.utf16()));
34 // Allocate the required DEVMODE buffer
35 LONG dmSize = DocumentProperties(nullptr, hPrinter, printerIdUtf16, nullptr, nullptr, 0);
36 if (dmSize <= 0)
37 return nullptr;
38 LPDEVMODE pDevMode = reinterpret_cast<LPDEVMODE>(malloc(dmSize));
39 // Get the default DevMode
40 LONG result = DocumentProperties(nullptr, hPrinter, printerIdUtf16, pDevMode, nullptr, DM_OUT_BUFFER);
41 if (result != IDOK) {
42 free(pDevMode);
43 pDevMode = nullptr;
44 }
45 return pDevMode;
46}
47
48QWindowsPrintDevice::QWindowsPrintDevice()
49 : QPlatformPrintDevice(),
50 m_hPrinter(0)
51{
52}
53
54QWindowsPrintDevice::QWindowsPrintDevice(const QString &id)
55 : QPlatformPrintDevice(id),
56 m_hPrinter(0)
57{
58 // First do a fast lookup to see if printer exists, if it does then open it
59 if (!id.isEmpty() && QWindowsPrintDevice::availablePrintDeviceIds().contains(id)) {
60 if (OpenPrinter(const_cast<LPWSTR>(wcharId()), &m_hPrinter, nullptr)) {
61 DWORD needed = 0;
62 GetPrinter(m_hPrinter, 2, 0, 0, &needed);
63 QScopedArrayPointer<BYTE> buffer(new BYTE[needed]);
64 if (GetPrinter(m_hPrinter, 2, buffer.data(), needed, &needed)) {
65 PPRINTER_INFO_2 info = reinterpret_cast<PPRINTER_INFO_2>(buffer.data());
66 m_name = QString::fromWCharArray(info->pPrinterName);
67 m_location = QString::fromWCharArray(info->pLocation);
68 m_makeAndModel = QString::fromWCharArray(info->pDriverName); // TODO Check is not available elsewhere
69 m_isRemote = info->Attributes & PRINTER_ATTRIBUTE_NETWORK;
70 }
71 QWindowsPrinterInfo m_info;
72 m_info.m_id = m_id;
73 m_info.m_name = m_name;
74 m_info.m_location = m_location;
75 m_info.m_makeAndModel = m_makeAndModel;
76 m_info.m_isRemote = m_isRemote;
77 m_infoIndex = windowsDeviceLookup()->indexOf(m_info);
78 if (m_infoIndex != -1) {
79 m_info = windowsDeviceLookup()->at(m_infoIndex);
80 m_havePageSizes = m_info.m_havePageSizes;
81 m_pageSizes = m_info.m_pageSizes;
82 m_haveResolutions = m_info.m_haveResolutions;
83 m_resolutions = m_info.m_resolutions;
84 m_haveCopies = m_info.m_haveCopies;
85 m_supportsMultipleCopies = m_info.m_supportsMultipleCopies;
86 m_supportsCollateCopies = m_info.m_supportsCollateCopies;
87 m_haveMinMaxPageSizes = m_info.m_haveMinMaxPageSizes;
88 m_minimumPhysicalPageSize = m_info.m_minimumPhysicalPageSize;
89 m_maximumPhysicalPageSize = m_info.m_maximumPhysicalPageSize;
90 m_supportsCustomPageSizes = m_info.m_supportsCustomPageSizes;
91 m_haveInputSlots = m_info.m_haveInputSlots;
92 m_inputSlots = m_info.m_inputSlots;
93 m_haveOutputBins = m_info.m_haveOutputBins;
94 m_outputBins = m_info.m_outputBins;
95 m_haveDuplexModes = m_info.m_haveDuplexModes;
96 m_duplexModes = m_info.m_duplexModes;
97 m_haveColorModes = m_info.m_haveColorModes;
98 m_colorModes = m_info.m_colorModes;
99 m_infoIndex = windowsDeviceLookup()->indexOf(m_info);
100 } else {
101 windowsDeviceLookup()->append(m_info);
102 m_infoIndex = windowsDeviceLookup()->count() - 1;
103 }
104 }
105 }
106}
107
108QWindowsPrintDevice::~QWindowsPrintDevice()
109{
110 ClosePrinter(m_hPrinter);
111}
112
113bool QWindowsPrintDevice::isValid() const
114{
115 return m_hPrinter;
116}
117
118bool QWindowsPrintDevice::isDefault() const
119{
120 return m_id == defaultPrintDeviceId();
121}
122
123QPrint::DeviceState QWindowsPrintDevice::state() const
124{
125 DWORD needed = 0;
126 GetPrinter(m_hPrinter, 6, 0, 0, &needed);
127 QScopedArrayPointer<BYTE> buffer(new BYTE[needed]);
128
129 if (GetPrinter(m_hPrinter, 6, buffer.data(), needed, &needed)) {
130 PPRINTER_INFO_6 info = reinterpret_cast<PPRINTER_INFO_6>(buffer.data());
131 // TODO Check mapping
132 if (info->dwStatus == 0
133 || (info->dwStatus & PRINTER_STATUS_WAITING) == PRINTER_STATUS_WAITING
134 || (info->dwStatus & PRINTER_STATUS_POWER_SAVE) == PRINTER_STATUS_POWER_SAVE) {
135 return QPrint::Idle;
136 } else if ((info->dwStatus & PRINTER_STATUS_PRINTING) == PRINTER_STATUS_PRINTING
137 || (info->dwStatus & PRINTER_STATUS_BUSY) == PRINTER_STATUS_BUSY
138 || (info->dwStatus & PRINTER_STATUS_INITIALIZING) == PRINTER_STATUS_INITIALIZING
139 || (info->dwStatus & PRINTER_STATUS_IO_ACTIVE) == PRINTER_STATUS_IO_ACTIVE
140 || (info->dwStatus & PRINTER_STATUS_PROCESSING) == PRINTER_STATUS_PROCESSING
141 || (info->dwStatus & PRINTER_STATUS_WARMING_UP) == PRINTER_STATUS_WARMING_UP) {
142 return QPrint::Active;
143 }
144 }
145
146 return QPrint::Error;
147}
148
149void QWindowsPrintDevice::loadPageSizes() const
150{
151 // Get the number of paper sizes and check all 3 attributes have same count
152 const int paperCount = DeviceCapabilities(wcharId(), nullptr, DC_PAPERNAMES, nullptr, nullptr);
153 if (paperCount > 0
154 && DeviceCapabilities(wcharId(), nullptr, DC_PAPERSIZE, nullptr, nullptr) == paperCount
155 && DeviceCapabilities(wcharId(), nullptr, DC_PAPERS, nullptr, nullptr) == paperCount) {
156
157 QScopedArrayPointer<wchar_t> paperNames(new wchar_t[paperCount*64]);
158 QScopedArrayPointer<POINT> winSizes(new POINT[paperCount]);
159 QScopedArrayPointer<wchar_t> papers(new wchar_t[paperCount]);
160
161 // Get the details and match the default paper size
162 if (DeviceCapabilities(wcharId(), nullptr, DC_PAPERNAMES, paperNames.data(), nullptr) == paperCount
163 && DeviceCapabilities(wcharId(), nullptr, DC_PAPERSIZE,
164 reinterpret_cast<wchar_t *>(winSizes.data()), nullptr) == paperCount
165 && DeviceCapabilities(wcharId(), nullptr, DC_PAPERS, papers.data(), nullptr) == paperCount) {
166
167 // Returned size is in tenths of a millimeter
168 const qreal multiplier = qt_pointMultiplier(QPageLayout::Millimeter);
169 for (int i = 0; i < int(paperCount); ++i) {
170 QSize size = QSize(qRound((winSizes[i].x / 10.0) * multiplier), qRound((winSizes[i].y / 10.0) * multiplier));
171 wchar_t *paper = paperNames.data() + (i * 64);
172 QString name = QString::fromWCharArray(paper, qwcsnlen(paper, 64));
173 m_pageSizes.append(createPageSize(papers[i], size, name));
174 }
175
176 }
177 }
178
179 m_havePageSizes = true;
180 QWindowsPrinterInfo *info = windowsDeviceLookup()->data();
181 info[m_infoIndex].m_havePageSizes = true;
182 info[m_infoIndex].m_pageSizes = m_pageSizes;
183}
184
185QPageSize QWindowsPrintDevice::defaultPageSize() const
186{
187 if (!m_havePageSizes)
188 loadPageSizes();
189
190 QPageSize pageSize;
191
192 if (LPDEVMODE pDevMode = getDevmode(m_hPrinter, m_id)) {
193 // Get the default paper size
194 if (pDevMode->dmFields & DM_PAPERSIZE) {
195 // Find the supported page size that matches, in theory default should be one of them
196 for (const QPageSize &ps : m_pageSizes) {
197 if (ps.windowsId() == pDevMode->dmPaperSize) {
198 pageSize = ps;
199 break;
200 }
201 }
202 }
203 // Clean-up
204 free(pDevMode);
205 }
206
207 return pageSize;
208}
209
210QMarginsF QWindowsPrintDevice::printableMargins(const QPageSize &pageSize,
211 QPageLayout::Orientation orientation,
212 int resolution) const
213{
214 // TODO This is slow, need to cache values or find better way!
215 // Modify the DevMode to get the DC printable margins in device pixels
216 QMarginsF margins = QMarginsF(0, 0, 0, 0);
217 DWORD needed = 0;
218 GetPrinter(m_hPrinter, 2, 0, 0, &needed);
219 QScopedArrayPointer<BYTE> buffer(new BYTE[needed]);
220 if (GetPrinter(m_hPrinter, 2, buffer.data(), needed, &needed)) {
221 PPRINTER_INFO_2 info = reinterpret_cast<PPRINTER_INFO_2>(buffer.data());
222 LPDEVMODE devMode = info->pDevMode;
223 bool separateDevMode = false;
224 if (!devMode) {
225 // GetPrinter() didn't include the DEVMODE. Get it a different way.
226 devMode = getDevmode(m_hPrinter, m_id);
227 if (!devMode)
228 return margins;
229 separateDevMode = true;
230 }
231
232 HDC pDC = CreateDC(nullptr, wcharId(), nullptr, devMode);
233 if (pageSize.id() == QPageSize::Custom || pageSize.windowsId() <= 0 || pageSize.windowsId() > DMPAPER_LAST) {
234 devMode->dmPaperSize = 0;
235 devMode->dmPaperWidth = pageSize.size(QPageSize::Millimeter).width() * 10.0;
236 devMode->dmPaperLength = pageSize.size(QPageSize::Millimeter).height() * 10.0;
237 } else {
238 devMode->dmPaperSize = pageSize.windowsId();
239 }
240 devMode->dmPrintQuality = resolution;
241 devMode->dmOrientation = orientation == QPageLayout::Portrait ? DMORIENT_PORTRAIT : DMORIENT_LANDSCAPE;
242 ResetDC(pDC, devMode);
243 const int dpiWidth = GetDeviceCaps(pDC, LOGPIXELSX);
244 const int dpiHeight = GetDeviceCaps(pDC, LOGPIXELSY);
245 const qreal wMult = 72.0 / dpiWidth;
246 const qreal hMult = 72.0 / dpiHeight;
247 const qreal physicalWidth = GetDeviceCaps(pDC, PHYSICALWIDTH) * wMult;
248 const qreal physicalHeight = GetDeviceCaps(pDC, PHYSICALHEIGHT) * hMult;
249 const qreal printableWidth = GetDeviceCaps(pDC, HORZRES) * wMult;
250 const qreal printableHeight = GetDeviceCaps(pDC, VERTRES) * hMult;
251 const qreal leftMargin = GetDeviceCaps(pDC, PHYSICALOFFSETX)* wMult;
252 const qreal topMargin = GetDeviceCaps(pDC, PHYSICALOFFSETY) * hMult;
253 const qreal rightMargin = physicalWidth - leftMargin - printableWidth;
254 const qreal bottomMargin = physicalHeight - topMargin - printableHeight;
255 margins = QMarginsF(leftMargin, topMargin, rightMargin, bottomMargin);
256 if (separateDevMode)
257 free(devMode);
258 DeleteDC(pDC);
259 }
260 return margins;
261}
262
263void QWindowsPrintDevice::loadResolutions() const
264{
265 const int resCount = DeviceCapabilities(wcharId(), nullptr, DC_ENUMRESOLUTIONS, nullptr, nullptr);
266 if (resCount > 0) {
267 QScopedArrayPointer<LONG> resolutions(new LONG[resCount*2]);
268 // Get the details and match the default paper size
269 if (DeviceCapabilities(wcharId(), nullptr, DC_ENUMRESOLUTIONS,
270 reinterpret_cast<LPWSTR>(resolutions.data()), nullptr) == resCount) {
271 for (int i = 0; i < int(resCount * 2); i += 2)
272 m_resolutions.append(resolutions[i+1]);
273 }
274 }
275 m_haveResolutions = true;
276 QWindowsPrinterInfo *info = windowsDeviceLookup()->data();
277 info[m_infoIndex].m_haveResolutions = true;
278 info[m_infoIndex].m_resolutions = m_resolutions;
279}
280
281int QWindowsPrintDevice::defaultResolution() const
282{
283 int resolution = 72; // TODO Set a sensible default?
284
285 if (LPDEVMODE pDevMode = getDevmode(m_hPrinter, m_id)) {
286 // Get the default resolution
287 if (pDevMode->dmFields & DM_YRESOLUTION) {
288 if (pDevMode->dmPrintQuality > 0)
289 resolution = pDevMode->dmPrintQuality;
290 else
291 resolution = pDevMode->dmYResolution;
292 }
293 // Clean-up
294 free(pDevMode);
295 }
296 return resolution;
297}
298
299void QWindowsPrintDevice::loadInputSlots() const
300{
301 const auto printerId = wcharId();
302 const int binCount = DeviceCapabilities(printerId, nullptr, DC_BINS, nullptr, nullptr);
303 if (binCount > 0
304 && DeviceCapabilities(printerId, nullptr, DC_BINNAMES, nullptr, nullptr) == binCount) {
305
306 QScopedArrayPointer<WORD> bins(new WORD[binCount]);
307 QScopedArrayPointer<wchar_t> binNames(new wchar_t[binCount*24]);
308
309 // Get the details and match the default paper size
310 if (DeviceCapabilities(printerId, nullptr, DC_BINS,
311 reinterpret_cast<LPWSTR>(bins.data()), nullptr) == binCount
312 && DeviceCapabilities(printerId, nullptr, DC_BINNAMES, binNames.data(),
313 nullptr) == binCount) {
314
315 for (int i = 0; i < int(binCount); ++i) {
316 wchar_t *binName = binNames.data() + (i * 24);
317 QString name = QString::fromWCharArray(binName, qwcsnlen(binName, 24));
318 m_inputSlots.append(QPrintUtils::paperBinToInputSlot(bins[i], name));
319 }
320
321 }
322 }
323
324 m_haveInputSlots = true;
325 QWindowsPrinterInfo *info = windowsDeviceLookup()->data();
326 info[m_infoIndex].m_haveInputSlots = true;
327 info[m_infoIndex].m_inputSlots = m_inputSlots;
328}
329
330QPrint::InputSlot QWindowsPrintDevice::defaultInputSlot() const
331{
332 QPrint::InputSlot inputSlot = QPlatformPrintDevice::defaultInputSlot();
333
334 if (LPDEVMODE pDevMode = getDevmode(m_hPrinter, m_id)) {
335 // Get the default input slot
336 if (pDevMode->dmFields & DM_DEFAULTSOURCE) {
337 QPrint::InputSlot tempSlot =
338 QPrintUtils::paperBinToInputSlot(pDevMode->dmDefaultSource, QString());
339 const auto inputSlots = supportedInputSlots();
340 for (const QPrint::InputSlot &slot : inputSlots) {
341 if (slot.key == tempSlot.key) {
342 inputSlot = slot;
343 break;
344 }
345 }
346 }
347 // Clean-up
348 free(pDevMode);
349 }
350 return inputSlot;
351}
352
353void QWindowsPrintDevice::loadOutputBins() const
354{
355 m_outputBins.append(QPlatformPrintDevice::defaultOutputBin());
356 m_haveOutputBins = true;
357 QWindowsPrinterInfo *info = windowsDeviceLookup()->data();
358 info[m_infoIndex].m_haveOutputBins = true;
359 info[m_infoIndex].m_outputBins = m_outputBins;
360}
361
362void QWindowsPrintDevice::loadDuplexModes() const
363{
364 m_duplexModes.append(QPrint::DuplexNone);
365 DWORD duplex = DeviceCapabilities(wcharId(), nullptr, DC_DUPLEX, nullptr, nullptr);
366 if (int(duplex) == 1) {
367 // TODO Assume if duplex flag supports both modes
368 m_duplexModes.append(QPrint::DuplexAuto);
369 m_duplexModes.append(QPrint::DuplexLongSide);
370 m_duplexModes.append(QPrint::DuplexShortSide);
371 }
372 m_haveDuplexModes = true;
373 QWindowsPrinterInfo *info = windowsDeviceLookup()->data();
374 info[m_infoIndex].m_haveDuplexModes = true;
375 info[m_infoIndex].m_duplexModes = m_duplexModes;
376}
377
378QPrint::DuplexMode QWindowsPrintDevice::defaultDuplexMode() const
379{
380 QPrint::DuplexMode duplexMode = QPrint::DuplexNone;
381
382 if (LPDEVMODE pDevMode = getDevmode(m_hPrinter, m_id)) {
383 // Get the default duplex mode
384 if (pDevMode->dmFields & DM_DUPLEX) {
385 if (pDevMode->dmDuplex == DMDUP_VERTICAL)
386 duplexMode = QPrint::DuplexLongSide;
387 else if (pDevMode->dmDuplex == DMDUP_HORIZONTAL)
388 duplexMode = QPrint::DuplexShortSide;
389 }
390 // Clean-up
391 free(pDevMode);
392 }
393 return duplexMode;
394}
395
396void QWindowsPrintDevice::loadColorModes() const
397{
398 m_colorModes.append(QPrint::GrayScale);
399 DWORD color = DeviceCapabilities(wcharId(), nullptr, DC_COLORDEVICE, nullptr, nullptr);
400 if (int(color) == 1)
401 m_colorModes.append(QPrint::Color);
402 m_haveColorModes = true;
403 QWindowsPrinterInfo *info = windowsDeviceLookup()->data();
404 info[m_infoIndex].m_haveColorModes = true;
405 info[m_infoIndex].m_colorModes = m_colorModes;
406}
407
408QPrint::ColorMode QWindowsPrintDevice::defaultColorMode() const
409{
410 if (!m_haveColorModes)
411 loadColorModes();
412 if (!m_colorModes.contains(QPrint::Color))
413 return QPrint::GrayScale;
414
415 QPrint::ColorMode colorMode = QPrint::GrayScale;
416
417 if (LPDEVMODE pDevMode = getDevmode(m_hPrinter, m_id)) {
418 // Get the default color mode
419 if (pDevMode->dmFields & DM_COLOR && pDevMode->dmColor == DMCOLOR_COLOR)
420 colorMode = QPrint::Color;
421 // Clean-up
422 free(pDevMode);
423 }
424 return colorMode;
425}
426
427QStringList QWindowsPrintDevice::availablePrintDeviceIds()
428{
429 QStringList list;
430 DWORD needed = 0;
431 DWORD returned = 0;
432 if ((!EnumPrinters(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS, nullptr, 4, 0, 0, &needed, &returned)
433 && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
434 || !needed) {
435 return list;
436 }
437 QScopedArrayPointer<BYTE> buffer(new BYTE[needed]);
438 if (!EnumPrinters(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS, nullptr, 4, buffer.data(), needed, &needed, &returned))
439 return list;
440 PPRINTER_INFO_4 infoList = reinterpret_cast<PPRINTER_INFO_4>(buffer.data());
441 for (uint i = 0; i < returned; ++i)
442 list.append(QString::fromWCharArray(infoList[i].pPrinterName));
443 return list;
444}
445
446QString QWindowsPrintDevice::defaultPrintDeviceId()
447{
448 DWORD size = 0;
449 if (GetDefaultPrinter(nullptr, &size) == ERROR_FILE_NOT_FOUND || size < 2)
450 return QString();
451
452 QScopedArrayPointer<wchar_t> name(new wchar_t[size]);
453 GetDefaultPrinter(name.data(), &size);
454 return QString::fromWCharArray(name.data());
455}
456
457void QWindowsPrintDevice::loadCopiesSupport() const
458{
459 auto printerId = wcharId();
460 m_supportsMultipleCopies = (DeviceCapabilities(printerId, nullptr, DC_COPIES, nullptr, nullptr) > 1);
461 m_supportsCollateCopies = DeviceCapabilities(printerId, nullptr, DC_COLLATE, nullptr, nullptr);
462 m_haveCopies = true;
463 QWindowsPrinterInfo *info = windowsDeviceLookup()->data();
464 info[m_infoIndex].m_haveCopies = true;
465 info[m_infoIndex].m_supportsMultipleCopies = m_supportsMultipleCopies;
466 info[m_infoIndex].m_supportsCollateCopies = m_supportsCollateCopies;
467}
468
469bool QWindowsPrintDevice::supportsCollateCopies() const
470{
471 if (!m_haveCopies)
472 loadCopiesSupport();
473 return m_supportsCollateCopies;
474}
475
476bool QWindowsPrintDevice::supportsMultipleCopies() const
477{
478 if (!m_haveCopies)
479 loadCopiesSupport();
480 return m_supportsMultipleCopies;
481}
482
483bool QWindowsPrintDevice::supportsCustomPageSizes() const
484{
485 if (!m_haveMinMaxPageSizes)
486 loadMinMaxPageSizes();
487 return m_supportsCustomPageSizes;
488}
489
490QSize QWindowsPrintDevice::minimumPhysicalPageSize() const
491{
492 if (!m_haveMinMaxPageSizes)
493 loadMinMaxPageSizes();
494 return m_minimumPhysicalPageSize;
495}
496
497QSize QWindowsPrintDevice::maximumPhysicalPageSize() const
498{
499 if (!m_haveMinMaxPageSizes)
500 loadMinMaxPageSizes();
501 return m_maximumPhysicalPageSize;
502}
503
504void QWindowsPrintDevice::loadMinMaxPageSizes() const
505{
506 // Min/Max custom size is in tenths of a millimeter
507 const qreal multiplier = qt_pointMultiplier(QPageLayout::Millimeter);
508 auto printerId = wcharId();
509 DWORD min = DeviceCapabilities(printerId, nullptr, DC_MINEXTENT, nullptr, nullptr);
510 m_minimumPhysicalPageSize = QSize((LOWORD(min) / 10.0) * multiplier, (HIWORD(min) / 10.0) * multiplier);
511 DWORD max = DeviceCapabilities(printerId, nullptr, DC_MAXEXTENT, nullptr, nullptr);
512 m_maximumPhysicalPageSize = QSize((LOWORD(max) / 10.0) * multiplier, (HIWORD(max) / 10.0) * multiplier);
513 m_supportsCustomPageSizes = (m_maximumPhysicalPageSize.width() > 0 && m_maximumPhysicalPageSize.height() > 0);
514 m_haveMinMaxPageSizes = true;
515 QWindowsPrinterInfo *info = windowsDeviceLookup()->data();
516 info[m_infoIndex].m_haveCopies = true;
517 info[m_infoIndex].m_supportsMultipleCopies = m_supportsMultipleCopies;
518 info[m_infoIndex].m_supportsCollateCopies = m_supportsCollateCopies;
519}
520
521QT_END_NAMESPACE
Q_GLOBAL_STATIC(QReadWriteLock, g_updateMutex)
qreal qt_pointMultiplier(QPageLayout::Unit unit)
#define DC_COLLATE
static LPDEVMODE getDevmode(HANDLE hPrinter, const QString &printerId)
static uint qwcsnlen(const wchar_t *str, uint maxlen)