print_backend_win.cc revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
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.
4
5#include "printing/backend/print_backend.h"
6
7#include <objidl.h>
8#include <winspool.h>
9
10#include "base/memory/scoped_ptr.h"
11#include "base/string_piece.h"
12#include "base/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"
19
20
21namespace {
22
23HRESULT 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());
32  }
33  return hr;
34}
35
36}  // namespace
37
38namespace printing {
39
40class PrintBackendWin : public PrintBackend {
41 public:
42  PrintBackendWin() {}
43
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;
56
57 protected:
58  virtual ~PrintBackendWin() {}
59};
60
61bool 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_array<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;
77
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    OpenPrinter(printer_info[index].pPrinterName, printer.Receive(), NULL);
84    PrinterBasicInfo info;
85    if (InitBasicPrinterInfo(printer, &info)) {
86      info.is_default = (info.printer_name == default_printer);
87      printer_list->push_back(info);
88    }
89  }
90  return true;
91}
92
93std::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);
99}
100
101bool PrintBackendWin::GetPrinterSemanticCapsAndDefaults(
102    const std::string& printer_name,
103    PrinterSemanticCapsAndDefaults* printer_info) {
104  ScopedPrinterHandle printer_handle;
105  OpenPrinter(const_cast<LPTSTR>(UTF8ToWide(printer_name).c_str()),
106              printer_handle.Receive(), NULL);
107  DCHECK(printer_handle);
108  if (!printer_handle.IsValid()) {
109    LOG(WARNING) << "Failed to open printer, error = " << GetLastError();
110    return false;
111  }
112
113  PrinterInfo5 info_5;
114  if (!info_5.Init(printer_handle)) {
115    return false;
116  }
117  DCHECK_EQ(info_5.get()->pPrinterName, UTF8ToUTF16(printer_name));
118
119  PrinterSemanticCapsAndDefaults caps;
120
121  // Get printer capabilities. For more info see here:
122  // http://msdn.microsoft.com/en-us/library/windows/desktop/dd183552(v=vs.85).aspx
123  caps.color_changeable = (::DeviceCapabilities(info_5.get()->pPrinterName,
124                                                info_5.get()->pPortName,
125                                                DC_COLORDEVICE,
126                                                NULL,
127                                                NULL) == 1);
128
129  caps.duplex_capable = (::DeviceCapabilities(info_5.get()->pPrinterName,
130                                              info_5.get()->pPortName,
131                                              DC_DUPLEX,
132                                              NULL,
133                                              NULL) == 1);
134
135  UserDefaultDevMode user_settings;
136
137  if (user_settings.Init(printer_handle)) {
138    if ((user_settings.get()->dmFields & DM_COLOR) == DM_COLOR)
139      caps.color_default = (user_settings.get()->dmColor == DMCOLOR_COLOR);
140
141    if ((user_settings.get()->dmFields & DM_DUPLEX) == DM_DUPLEX) {
142      switch (user_settings.get()->dmDuplex) {
143      case DMDUP_SIMPLEX:
144        caps.duplex_default = SIMPLEX;
145        break;
146      case DMDUP_VERTICAL:
147        caps.duplex_default = LONG_EDGE;
148        break;
149      case DMDUP_HORIZONTAL:
150        caps.duplex_default = SHORT_EDGE;
151        break;
152      default:
153        NOTREACHED();
154      }
155    }
156  } else {
157    LOG(WARNING) << "Fallback to color/simplex mode.";
158    caps.color_default = caps.color_changeable;
159    caps.duplex_default = SIMPLEX;
160  }
161
162  *printer_info = caps;
163  return true;
164}
165
166bool PrintBackendWin::GetPrinterCapsAndDefaults(
167    const std::string& printer_name,
168    PrinterCapsAndDefaults* printer_info) {
169  ScopedXPSInitializer xps_initializer;
170  if (!xps_initializer.initialized()) {
171    // TODO(sanjeevr): Handle legacy proxy case (with no prntvpt.dll)
172    return false;
173  }
174  if (!IsValidPrinter(printer_name)) {
175    return false;
176  }
177  DCHECK(printer_info);
178  HPTPROVIDER provider = NULL;
179  std::wstring printer_name_wide = UTF8ToWide(printer_name);
180  HRESULT hr = XPSModule::OpenProvider(printer_name_wide, 1, &provider);
181  if (provider) {
182    base::win::ScopedComPtr<IStream> print_capabilities_stream;
183    hr = CreateStreamOnHGlobal(NULL, TRUE,
184                               print_capabilities_stream.Receive());
185    DCHECK(SUCCEEDED(hr));
186    if (print_capabilities_stream) {
187      base::win::ScopedBstr error;
188      hr = XPSModule::GetPrintCapabilities(provider,
189                                           NULL,
190                                           print_capabilities_stream,
191                                           error.Receive());
192      DCHECK(SUCCEEDED(hr));
193      if (FAILED(hr)) {
194        return false;
195      }
196      hr = StreamOnHGlobalToString(print_capabilities_stream.get(),
197                                   &printer_info->printer_capabilities);
198      DCHECK(SUCCEEDED(hr));
199      printer_info->caps_mime_type = "text/xml";
200    }
201    ScopedPrinterHandle printer_handle;
202    OpenPrinter(const_cast<LPTSTR>(printer_name_wide.c_str()),
203                printer_handle.Receive(), NULL);
204    DCHECK(printer_handle);
205    if (printer_handle.IsValid()) {
206      LONG devmode_size = DocumentProperties(
207          NULL, printer_handle, const_cast<LPTSTR>(printer_name_wide.c_str()),
208          NULL, NULL, 0);
209      if (devmode_size <= 0)
210        return false;
211      scoped_array<BYTE> devmode_out_buffer(new BYTE[devmode_size]);
212      DEVMODE* devmode_out =
213          reinterpret_cast<DEVMODE*>(devmode_out_buffer.get());
214      DocumentProperties(
215          NULL, printer_handle, const_cast<LPTSTR>(printer_name_wide.c_str()),
216          devmode_out, NULL, DM_OUT_BUFFER);
217      base::win::ScopedComPtr<IStream> printer_defaults_stream;
218      hr = CreateStreamOnHGlobal(NULL, TRUE,
219                                 printer_defaults_stream.Receive());
220      DCHECK(SUCCEEDED(hr));
221      if (printer_defaults_stream) {
222        hr = XPSModule::ConvertDevModeToPrintTicket(provider,
223                                                    devmode_size,
224                                                    devmode_out,
225                                                    kPTJobScope,
226                                                    printer_defaults_stream);
227        DCHECK(SUCCEEDED(hr));
228        if (SUCCEEDED(hr)) {
229          hr = StreamOnHGlobalToString(printer_defaults_stream.get(),
230                                       &printer_info->printer_defaults);
231          DCHECK(SUCCEEDED(hr));
232          printer_info->defaults_mime_type = "text/xml";
233        }
234      }
235    }
236    XPSModule::CloseProvider(provider);
237  }
238  return true;
239}
240
241// Gets the information about driver for a specific printer.
242std::string PrintBackendWin::GetPrinterDriverInfo(
243    const std::string& printer_name) {
244  ScopedPrinterHandle printer;
245  if (!::OpenPrinter(const_cast<LPTSTR>(UTF8ToWide(printer_name).c_str()),
246                     printer.Receive(), NULL)) {
247    return std::string();
248  }
249  return GetDriverInfo(printer);
250}
251
252bool PrintBackendWin::IsValidPrinter(const std::string& printer_name) {
253  ScopedPrinterHandle printer_handle;
254  OpenPrinter(const_cast<LPTSTR>(UTF8ToWide(printer_name).c_str()),
255              printer_handle.Receive(), NULL);
256  return printer_handle.IsValid();
257}
258
259scoped_refptr<PrintBackend> PrintBackend::CreateInstance(
260    const base::DictionaryValue* print_backend_settings) {
261  return new PrintBackendWin;
262}
263
264}  // namespace printing
265