1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "printing/backend/print_backend.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/strings/string_piece.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "base/win/scoped_bstr.h"
14 #include "base/win/scoped_comptr.h"
15 #include "base/win/scoped_hglobal.h"
16 #include "printing/backend/print_backend_consts.h"
17 #include "printing/backend/printing_info_win.h"
18 #include "printing/backend/win_helper.h"
23 HRESULT
StreamOnHGlobalToString(IStream
* stream
, std::string
* out
) {
27 HRESULT hr
= GetHGlobalFromStream(stream
, &hdata
);
30 base::win::ScopedHGlobal
<char> locked_data(hdata
);
31 out
->assign(locked_data
.release(), locked_data
.Size());
40 class PrintBackendWin
: public PrintBackend
{
44 // PrintBackend implementation.
45 virtual bool EnumeratePrinters(PrinterList
* printer_list
) OVERRIDE
;
46 virtual std::string
GetDefaultPrinterName() OVERRIDE
;
47 virtual bool GetPrinterSemanticCapsAndDefaults(
48 const std::string
& printer_name
,
49 PrinterSemanticCapsAndDefaults
* printer_info
) OVERRIDE
;
50 virtual bool GetPrinterCapsAndDefaults(
51 const std::string
& printer_name
,
52 PrinterCapsAndDefaults
* printer_info
) OVERRIDE
;
53 virtual std::string
GetPrinterDriverInfo(
54 const std::string
& printer_name
) OVERRIDE
;
55 virtual bool IsValidPrinter(const std::string
& printer_name
) OVERRIDE
;
58 virtual ~PrintBackendWin() {}
61 bool PrintBackendWin::EnumeratePrinters(PrinterList
* printer_list
) {
63 DWORD bytes_needed
= 0;
64 DWORD count_returned
= 0;
65 const DWORD kLevel
= 4;
66 BOOL ret
= EnumPrinters(PRINTER_ENUM_LOCAL
|PRINTER_ENUM_CONNECTIONS
, NULL
,
67 kLevel
, NULL
, 0, &bytes_needed
, &count_returned
);
70 scoped_ptr
<BYTE
[]> printer_info_buffer(new BYTE
[bytes_needed
]);
71 ret
= EnumPrinters(PRINTER_ENUM_LOCAL
|PRINTER_ENUM_CONNECTIONS
, NULL
, kLevel
,
72 printer_info_buffer
.get(), bytes_needed
, &bytes_needed
,
78 std::string default_printer
= GetDefaultPrinterName();
79 PRINTER_INFO_4
* printer_info
=
80 reinterpret_cast<PRINTER_INFO_4
*>(printer_info_buffer
.get());
81 for (DWORD index
= 0; index
< count_returned
; index
++) {
82 ScopedPrinterHandle printer
;
83 PrinterBasicInfo info
;
84 if (printer
.OpenPrinter(printer_info
[index
].pPrinterName
) &&
85 InitBasicPrinterInfo(printer
, &info
)) {
86 info
.is_default
= (info
.printer_name
== default_printer
);
87 printer_list
->push_back(info
);
93 std::string
PrintBackendWin::GetDefaultPrinterName() {
94 DWORD size
= MAX_PATH
;
95 TCHAR default_printer_name
[MAX_PATH
];
96 if (!::GetDefaultPrinter(default_printer_name
, &size
))
98 return WideToUTF8(default_printer_name
);
101 bool PrintBackendWin::GetPrinterSemanticCapsAndDefaults(
102 const std::string
& printer_name
,
103 PrinterSemanticCapsAndDefaults
* printer_info
) {
104 ScopedPrinterHandle printer_handle
;
105 if (!printer_handle
.OpenPrinter(UTF8ToWide(printer_name
).c_str())) {
106 LOG(WARNING
) << "Failed to open printer, error = " << GetLastError();
111 if (!info_5
.Init(printer_handle
)) {
114 DCHECK_EQ(info_5
.get()->pPrinterName
, UTF8ToUTF16(printer_name
));
116 PrinterSemanticCapsAndDefaults caps
;
118 // Get printer capabilities. For more info see here:
119 // http://msdn.microsoft.com/en-us/library/windows/desktop/dd183552(v=vs.85).aspx
120 caps
.color_changeable
= (::DeviceCapabilities(info_5
.get()->pPrinterName
,
121 info_5
.get()->pPortName
,
126 caps
.duplex_capable
= (::DeviceCapabilities(info_5
.get()->pPrinterName
,
127 info_5
.get()->pPortName
,
132 UserDefaultDevMode user_settings
;
134 if (user_settings
.Init(printer_handle
)) {
135 if ((user_settings
.get()->dmFields
& DM_COLOR
) == DM_COLOR
)
136 caps
.color_default
= (user_settings
.get()->dmColor
== DMCOLOR_COLOR
);
138 if ((user_settings
.get()->dmFields
& DM_DUPLEX
) == DM_DUPLEX
) {
139 switch (user_settings
.get()->dmDuplex
) {
141 caps
.duplex_default
= SIMPLEX
;
144 caps
.duplex_default
= LONG_EDGE
;
146 case DMDUP_HORIZONTAL
:
147 caps
.duplex_default
= SHORT_EDGE
;
154 LOG(WARNING
) << "Fallback to color/simplex mode.";
155 caps
.color_default
= caps
.color_changeable
;
156 caps
.duplex_default
= SIMPLEX
;
159 *printer_info
= caps
;
163 bool PrintBackendWin::GetPrinterCapsAndDefaults(
164 const std::string
& printer_name
,
165 PrinterCapsAndDefaults
* printer_info
) {
166 ScopedXPSInitializer xps_initializer
;
167 if (!xps_initializer
.initialized()) {
168 // TODO(sanjeevr): Handle legacy proxy case (with no prntvpt.dll)
171 if (!IsValidPrinter(printer_name
)) {
174 DCHECK(printer_info
);
175 HPTPROVIDER provider
= NULL
;
176 std::wstring printer_name_wide
= UTF8ToWide(printer_name
);
177 HRESULT hr
= XPSModule::OpenProvider(printer_name_wide
, 1, &provider
);
179 base::win::ScopedComPtr
<IStream
> print_capabilities_stream
;
180 hr
= CreateStreamOnHGlobal(NULL
, TRUE
,
181 print_capabilities_stream
.Receive());
182 DCHECK(SUCCEEDED(hr
));
183 if (print_capabilities_stream
) {
184 base::win::ScopedBstr error
;
185 hr
= XPSModule::GetPrintCapabilities(provider
,
187 print_capabilities_stream
,
189 DCHECK(SUCCEEDED(hr
));
193 hr
= StreamOnHGlobalToString(print_capabilities_stream
.get(),
194 &printer_info
->printer_capabilities
);
195 DCHECK(SUCCEEDED(hr
));
196 printer_info
->caps_mime_type
= "text/xml";
198 ScopedPrinterHandle printer_handle
;
199 if (printer_handle
.OpenPrinter(printer_name_wide
.c_str())) {
200 LONG devmode_size
= DocumentProperties(
201 NULL
, printer_handle
, const_cast<LPTSTR
>(printer_name_wide
.c_str()),
203 if (devmode_size
<= 0)
205 scoped_ptr
<BYTE
[]> devmode_out_buffer(new BYTE
[devmode_size
]);
206 DEVMODE
* devmode_out
=
207 reinterpret_cast<DEVMODE
*>(devmode_out_buffer
.get());
209 NULL
, printer_handle
, const_cast<LPTSTR
>(printer_name_wide
.c_str()),
210 devmode_out
, NULL
, DM_OUT_BUFFER
);
211 base::win::ScopedComPtr
<IStream
> printer_defaults_stream
;
212 hr
= CreateStreamOnHGlobal(NULL
, TRUE
,
213 printer_defaults_stream
.Receive());
214 DCHECK(SUCCEEDED(hr
));
215 if (printer_defaults_stream
) {
216 hr
= XPSModule::ConvertDevModeToPrintTicket(provider
,
220 printer_defaults_stream
);
221 DCHECK(SUCCEEDED(hr
));
223 hr
= StreamOnHGlobalToString(printer_defaults_stream
.get(),
224 &printer_info
->printer_defaults
);
225 DCHECK(SUCCEEDED(hr
));
226 printer_info
->defaults_mime_type
= "text/xml";
230 XPSModule::CloseProvider(provider
);
235 // Gets the information about driver for a specific printer.
236 std::string
PrintBackendWin::GetPrinterDriverInfo(
237 const std::string
& printer_name
) {
238 ScopedPrinterHandle printer
;
239 if (!printer
.OpenPrinter(UTF8ToWide(printer_name
).c_str())) {
240 return std::string();
242 return GetDriverInfo(printer
);
245 bool PrintBackendWin::IsValidPrinter(const std::string
& printer_name
) {
246 ScopedPrinterHandle printer_handle
;
247 return printer_handle
.OpenPrinter(UTF8ToWide(printer_name
).c_str());
250 scoped_refptr
<PrintBackend
> PrintBackend::CreateInstance(
251 const base::DictionaryValue
* print_backend_settings
) {
252 return new PrintBackendWin
;
255 } // namespace printing