Enable the following tests back under ThreadSanitizer v2:
[chromium-blink-merge.git] / printing / backend / print_backend_win.cc
blob0d1958fd39c3fa03f14fc4c949989318e22451c4
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/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"
21 namespace {
23 HRESULT StreamOnHGlobalToString(IStream* stream, std::string* out) {
24 DCHECK(stream);
25 DCHECK(out);
26 HGLOBAL hdata = NULL;
27 HRESULT hr = GetHGlobalFromStream(stream, &hdata);
28 if (SUCCEEDED(hr)) {
29 DCHECK(hdata);
30 base::win::ScopedHGlobal<char> locked_data(hdata);
31 out->assign(locked_data.release(), locked_data.Size());
33 return hr;
36 } // namespace
38 namespace printing {
40 class PrintBackendWin : public PrintBackend {
41 public:
42 PrintBackendWin() {}
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;
57 protected:
58 virtual ~PrintBackendWin() {}
61 bool PrintBackendWin::EnumeratePrinters(PrinterList* printer_list) {
62 DCHECK(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);
68 if (!bytes_needed)
69 return false;
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,
73 &count_returned);
74 DCHECK(ret);
75 if (!ret)
76 return false;
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);
90 return true;
93 std::string PrintBackendWin::GetDefaultPrinterName() {
94 DWORD size = MAX_PATH;
95 TCHAR default_printer_name[MAX_PATH];
96 if (!::GetDefaultPrinter(default_printer_name, &size))
97 return std::string();
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();
107 return false;
110 PrinterInfo5 info_5;
111 if (!info_5.Init(printer_handle)) {
112 return false;
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,
122 DC_COLORDEVICE,
123 NULL,
124 NULL) == 1);
126 caps.duplex_capable = (::DeviceCapabilities(info_5.get()->pPrinterName,
127 info_5.get()->pPortName,
128 DC_DUPLEX,
129 NULL,
130 NULL) == 1);
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) {
140 case DMDUP_SIMPLEX:
141 caps.duplex_default = SIMPLEX;
142 break;
143 case DMDUP_VERTICAL:
144 caps.duplex_default = LONG_EDGE;
145 break;
146 case DMDUP_HORIZONTAL:
147 caps.duplex_default = SHORT_EDGE;
148 break;
149 default:
150 NOTREACHED();
153 } else {
154 LOG(WARNING) << "Fallback to color/simplex mode.";
155 caps.color_default = caps.color_changeable;
156 caps.duplex_default = SIMPLEX;
159 *printer_info = caps;
160 return true;
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)
169 return false;
171 if (!IsValidPrinter(printer_name)) {
172 return false;
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);
178 if (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,
186 NULL,
187 print_capabilities_stream,
188 error.Receive());
189 DCHECK(SUCCEEDED(hr));
190 if (FAILED(hr)) {
191 return false;
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()),
202 NULL, NULL, 0);
203 if (devmode_size <= 0)
204 return false;
205 scoped_ptr<BYTE[]> devmode_out_buffer(new BYTE[devmode_size]);
206 DEVMODE* devmode_out =
207 reinterpret_cast<DEVMODE*>(devmode_out_buffer.get());
208 DocumentProperties(
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,
217 devmode_size,
218 devmode_out,
219 kPTJobScope,
220 printer_defaults_stream);
221 DCHECK(SUCCEEDED(hr));
222 if (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);
232 return true;
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