Cleanup extension_service.h
[chromium-blink-merge.git] / printing / backend / print_backend_win.cc
blob75c562a130694674d14fc42300ceabfd33d5dba6
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"
7 #include <objidl.h>
8 #include <winspool.h>
10 #include "base/memory/scoped_ptr.h"
11 #include "base/numerics/safe_conversions.h"
12 #include "base/strings/string_piece.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "base/win/scoped_bstr.h"
15 #include "base/win/scoped_comptr.h"
16 #include "base/win/scoped_hglobal.h"
17 #include "printing/backend/print_backend_consts.h"
18 #include "printing/backend/printing_info_win.h"
19 #include "printing/backend/win_helper.h"
21 namespace printing {
23 namespace {
25 HRESULT StreamOnHGlobalToString(IStream* stream, std::string* out) {
26 DCHECK(stream);
27 DCHECK(out);
28 HGLOBAL hdata = NULL;
29 HRESULT hr = GetHGlobalFromStream(stream, &hdata);
30 if (SUCCEEDED(hr)) {
31 DCHECK(hdata);
32 base::win::ScopedHGlobal<char> locked_data(hdata);
33 out->assign(locked_data.release(), locked_data.Size());
35 return hr;
38 template <class T>
39 void GetDeviceCapabilityArray(const wchar_t* printer,
40 const wchar_t* port,
41 WORD id,
42 std::vector<T>* result) {
43 int count = DeviceCapabilities(printer, port, id, NULL, NULL);
44 if (count <= 0)
45 return;
46 std::vector<T> tmp;
47 tmp.resize(count * 2);
48 count = DeviceCapabilities(printer, port, id,
49 reinterpret_cast<LPTSTR>(tmp.data()), NULL);
50 if (count <= 0)
51 return;
52 CHECK_LE(count, base::checked_cast<int>(tmp.size()));
53 tmp.resize(count);
54 result->swap(tmp);
57 void LoadPaper(const wchar_t* printer,
58 const wchar_t* port,
59 const DEVMODE* devmode,
60 PrinterSemanticCapsAndDefaults* caps) {
61 static const size_t kToUm = 100; // Windows uses 0.1mm.
62 static const size_t kMaxPaperName = 64;
64 struct PaperName {
65 wchar_t chars[kMaxPaperName];
68 DCHECK_EQ(sizeof(PaperName), sizeof(wchar_t) * kMaxPaperName);
70 // Paper
71 std::vector<PaperName> names;
72 GetDeviceCapabilityArray(printer, port, DC_PAPERNAMES, &names);
74 std::vector<POINT> sizes;
75 GetDeviceCapabilityArray(printer, port, DC_PAPERSIZE, &sizes);
77 std::vector<WORD> ids;
78 GetDeviceCapabilityArray(printer, port, DC_PAPERS, &ids);
80 DCHECK_EQ(ids.size(), sizes.size());
81 DCHECK_EQ(names.size(), sizes.size());
83 if (ids.size() != sizes.size())
84 ids.clear();
85 if (names.size() != sizes.size())
86 names.clear();
88 for (size_t i = 0; i < sizes.size(); ++i) {
89 PrinterSemanticCapsAndDefaults::Paper paper;
90 paper.size_um.SetSize(sizes[i].x * kToUm, sizes[i].y * kToUm);
91 if (!names.empty()) {
92 const wchar_t* name_start = names[i].chars;
93 base::string16 tmp_name(name_start, kMaxPaperName);
94 // Trim trailing zeros.
95 tmp_name = tmp_name.c_str();
96 paper.name = base::WideToUTF8(tmp_name);
98 caps->papers.push_back(paper);
101 if (devmode) {
102 short default_id = 0;
103 gfx::Size default_size;
105 if (devmode->dmFields & DM_PAPERSIZE)
106 default_id = devmode->dmPaperSize;
107 if (devmode->dmFields & DM_PAPERWIDTH)
108 default_size.set_width(devmode->dmPaperWidth * kToUm);
109 if (devmode->dmFields & DM_PAPERLENGTH)
110 default_size.set_height(devmode->dmPaperLength * kToUm);
112 if (default_size.IsEmpty()) {
113 for (size_t i = 0; i < ids.size(); ++i) {
114 if (ids[i] == default_id) {
115 PrinterSemanticCapsAndDefaults::Paper paper;
116 paper.size_um.SetSize(sizes[i].x * kToUm, sizes[i].y * kToUm);
117 if (!names.empty()) {
118 const wchar_t* name_start = names[i].chars;
119 base::string16 tmp_name(name_start, kMaxPaperName);
120 // Trim trailing zeros.
121 tmp_name = tmp_name.c_str();
122 paper.name = base::WideToUTF8(tmp_name);
124 caps->default_paper = paper;
125 break;
128 } else {
129 caps->default_paper.size_um = default_size;
134 void LoadDpi(const wchar_t* printer,
135 const wchar_t* port,
136 const DEVMODE* devmode,
137 PrinterSemanticCapsAndDefaults* caps) {
138 std::vector<POINT> dpis;
139 GetDeviceCapabilityArray(printer, port, DC_ENUMRESOLUTIONS, &dpis);
141 for (size_t i = 0; i < dpis.size() ; ++i)
142 caps->dpis.push_back(gfx::Size(dpis[i].x, dpis[i].y));
144 if (devmode) {
145 if ((devmode->dmFields & DM_PRINTQUALITY) && devmode->dmPrintQuality > 0) {
146 caps->default_dpi.SetSize(devmode->dmPrintQuality,
147 devmode->dmPrintQuality);
148 if (devmode->dmFields & DM_YRESOLUTION) {
149 caps->default_dpi.set_height(devmode->dmYResolution);
155 } // namespace
157 class PrintBackendWin : public PrintBackend {
158 public:
159 PrintBackendWin() {}
161 // PrintBackend implementation.
162 virtual bool EnumeratePrinters(PrinterList* printer_list) OVERRIDE;
163 virtual std::string GetDefaultPrinterName() OVERRIDE;
164 virtual bool GetPrinterSemanticCapsAndDefaults(
165 const std::string& printer_name,
166 PrinterSemanticCapsAndDefaults* printer_info) OVERRIDE;
167 virtual bool GetPrinterCapsAndDefaults(
168 const std::string& printer_name,
169 PrinterCapsAndDefaults* printer_info) OVERRIDE;
170 virtual std::string GetPrinterDriverInfo(
171 const std::string& printer_name) OVERRIDE;
172 virtual bool IsValidPrinter(const std::string& printer_name) OVERRIDE;
174 protected:
175 virtual ~PrintBackendWin() {}
178 bool PrintBackendWin::EnumeratePrinters(PrinterList* printer_list) {
179 DCHECK(printer_list);
180 DWORD bytes_needed = 0;
181 DWORD count_returned = 0;
182 const DWORD kLevel = 4;
183 BOOL ret = EnumPrinters(PRINTER_ENUM_LOCAL|PRINTER_ENUM_CONNECTIONS, NULL,
184 kLevel, NULL, 0, &bytes_needed, &count_returned);
185 if (!bytes_needed)
186 return false;
187 scoped_ptr<BYTE[]> printer_info_buffer(new BYTE[bytes_needed]);
188 ret = EnumPrinters(PRINTER_ENUM_LOCAL|PRINTER_ENUM_CONNECTIONS, NULL, kLevel,
189 printer_info_buffer.get(), bytes_needed, &bytes_needed,
190 &count_returned);
191 DCHECK(ret);
192 if (!ret)
193 return false;
195 std::string default_printer = GetDefaultPrinterName();
196 PRINTER_INFO_4* printer_info =
197 reinterpret_cast<PRINTER_INFO_4*>(printer_info_buffer.get());
198 for (DWORD index = 0; index < count_returned; index++) {
199 ScopedPrinterHandle printer;
200 PrinterBasicInfo info;
201 if (printer.OpenPrinter(printer_info[index].pPrinterName) &&
202 InitBasicPrinterInfo(printer, &info)) {
203 info.is_default = (info.printer_name == default_printer);
204 printer_list->push_back(info);
207 return true;
210 std::string PrintBackendWin::GetDefaultPrinterName() {
211 DWORD size = MAX_PATH;
212 TCHAR default_printer_name[MAX_PATH];
213 if (!::GetDefaultPrinter(default_printer_name, &size))
214 return std::string();
215 return base::WideToUTF8(default_printer_name);
218 bool PrintBackendWin::GetPrinterSemanticCapsAndDefaults(
219 const std::string& printer_name,
220 PrinterSemanticCapsAndDefaults* printer_info) {
221 ScopedPrinterHandle printer_handle;
222 if (!printer_handle.OpenPrinter(base::UTF8ToWide(printer_name).c_str())) {
223 LOG(WARNING) << "Failed to open printer, error = " << GetLastError();
224 return false;
227 PrinterInfo5 info_5;
228 if (!info_5.Init(printer_handle))
229 return false;
230 const wchar_t* name = info_5.get()->pPrinterName;
231 const wchar_t* port = info_5.get()->pPortName;
232 DCHECK_EQ(name, base::UTF8ToUTF16(printer_name));
234 PrinterSemanticCapsAndDefaults caps;
236 scoped_ptr<DEVMODE, base::FreeDeleter> user_settings =
237 CreateDevMode(printer_handle, NULL);
238 if (user_settings) {
239 if (user_settings->dmFields & DM_COLOR)
240 caps.color_default = (user_settings->dmColor == DMCOLOR_COLOR);
242 if (user_settings->dmFields & DM_DUPLEX) {
243 switch (user_settings->dmDuplex) {
244 case DMDUP_SIMPLEX:
245 caps.duplex_default = SIMPLEX;
246 break;
247 case DMDUP_VERTICAL:
248 caps.duplex_default = LONG_EDGE;
249 break;
250 case DMDUP_HORIZONTAL:
251 caps.duplex_default = SHORT_EDGE;
252 break;
253 default:
254 NOTREACHED();
258 if (user_settings->dmFields & DM_COLLATE)
259 caps.collate_default = (user_settings->dmCollate == DMCOLLATE_TRUE);
260 } else {
261 LOG(WARNING) << "Fallback to color/simplex mode.";
262 caps.color_default = caps.color_changeable;
263 caps.duplex_default = SIMPLEX;
266 // Get printer capabilities. For more info see here:
267 // http://msdn.microsoft.com/en-us/library/windows/desktop/dd183552(v=vs.85).aspx
268 caps.color_changeable =
269 (DeviceCapabilities(name, port, DC_COLORDEVICE, NULL, NULL) == 1);
271 caps.duplex_capable =
272 (DeviceCapabilities(name, port, DC_DUPLEX, NULL, NULL) == 1);
274 caps.collate_capable =
275 (DeviceCapabilities(name, port, DC_COLLATE, NULL, NULL) == 1);
277 caps.copies_capable =
278 (DeviceCapabilities(name, port, DC_COPIES, NULL, NULL) > 1);
280 LoadPaper(name, port, user_settings.get(), &caps);
281 LoadDpi(name, port, user_settings.get(), &caps);
283 *printer_info = caps;
284 return true;
287 bool PrintBackendWin::GetPrinterCapsAndDefaults(
288 const std::string& printer_name,
289 PrinterCapsAndDefaults* printer_info) {
290 ScopedXPSInitializer xps_initializer;
291 if (!xps_initializer.initialized()) {
292 // TODO(sanjeevr): Handle legacy proxy case (with no prntvpt.dll)
293 return false;
295 if (!IsValidPrinter(printer_name)) {
296 return false;
298 DCHECK(printer_info);
299 HPTPROVIDER provider = NULL;
300 std::wstring printer_name_wide = base::UTF8ToWide(printer_name);
301 HRESULT hr = XPSModule::OpenProvider(printer_name_wide, 1, &provider);
302 if (provider) {
303 base::win::ScopedComPtr<IStream> print_capabilities_stream;
304 hr = CreateStreamOnHGlobal(NULL, TRUE,
305 print_capabilities_stream.Receive());
306 DCHECK(SUCCEEDED(hr));
307 if (print_capabilities_stream) {
308 base::win::ScopedBstr error;
309 hr = XPSModule::GetPrintCapabilities(provider,
310 NULL,
311 print_capabilities_stream,
312 error.Receive());
313 DCHECK(SUCCEEDED(hr));
314 if (FAILED(hr)) {
315 return false;
317 hr = StreamOnHGlobalToString(print_capabilities_stream.get(),
318 &printer_info->printer_capabilities);
319 DCHECK(SUCCEEDED(hr));
320 printer_info->caps_mime_type = "text/xml";
322 ScopedPrinterHandle printer_handle;
323 if (printer_handle.OpenPrinter(printer_name_wide.c_str())) {
324 scoped_ptr<DEVMODE, base::FreeDeleter> devmode_out(
325 CreateDevMode(printer_handle, NULL));
326 if (!devmode_out)
327 return false;
328 base::win::ScopedComPtr<IStream> printer_defaults_stream;
329 hr = CreateStreamOnHGlobal(NULL, TRUE,
330 printer_defaults_stream.Receive());
331 DCHECK(SUCCEEDED(hr));
332 if (printer_defaults_stream) {
333 DWORD dm_size = devmode_out->dmSize + devmode_out->dmDriverExtra;
334 hr = XPSModule::ConvertDevModeToPrintTicket(provider, dm_size,
335 devmode_out.get(), kPTJobScope, printer_defaults_stream);
336 DCHECK(SUCCEEDED(hr));
337 if (SUCCEEDED(hr)) {
338 hr = StreamOnHGlobalToString(printer_defaults_stream.get(),
339 &printer_info->printer_defaults);
340 DCHECK(SUCCEEDED(hr));
341 printer_info->defaults_mime_type = "text/xml";
345 XPSModule::CloseProvider(provider);
347 return true;
350 // Gets the information about driver for a specific printer.
351 std::string PrintBackendWin::GetPrinterDriverInfo(
352 const std::string& printer_name) {
353 ScopedPrinterHandle printer;
354 if (!printer.OpenPrinter(base::UTF8ToWide(printer_name).c_str())) {
355 return std::string();
357 return GetDriverInfo(printer);
360 bool PrintBackendWin::IsValidPrinter(const std::string& printer_name) {
361 ScopedPrinterHandle printer_handle;
362 return printer_handle.OpenPrinter(base::UTF8ToWide(printer_name).c_str());
365 scoped_refptr<PrintBackend> PrintBackend::CreateInstance(
366 const base::DictionaryValue* print_backend_settings) {
367 return new PrintBackendWin;
370 } // namespace printing