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