Home | History | Annotate | Download | only in backend
      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/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"
     19 
     20 
     21 namespace {
     22 
     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());
     32   }
     33   return hr;
     34 }
     35 
     36 }  // namespace
     37 
     38 namespace printing {
     39 
     40 class 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 
     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;
     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     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);
     88     }
     89   }
     90   return true;
     91 }
     92 
     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);
     99 }
    100 
    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;
    108   }
    109 
    110   PrinterInfo5 info_5;
    111   if (!info_5.Init(printer_handle)) {
    112     return false;
    113   }
    114   DCHECK_EQ(info_5.get()->pPrinterName, UTF8ToUTF16(printer_name));
    115 
    116   PrinterSemanticCapsAndDefaults caps;
    117 
    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);
    125 
    126   caps.duplex_capable = (::DeviceCapabilities(info_5.get()->pPrinterName,
    127                                               info_5.get()->pPortName,
    128                                               DC_DUPLEX,
    129                                               NULL,
    130                                               NULL) == 1);
    131 
    132   UserDefaultDevMode user_settings;
    133 
    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);
    137 
    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();
    151       }
    152     }
    153   } else {
    154     LOG(WARNING) << "Fallback to color/simplex mode.";
    155     caps.color_default = caps.color_changeable;
    156     caps.duplex_default = SIMPLEX;
    157   }
    158 
    159   *printer_info = caps;
    160   return true;
    161 }
    162 
    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;
    170   }
    171   if (!IsValidPrinter(printer_name)) {
    172     return false;
    173   }
    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;
    192       }
    193       hr = StreamOnHGlobalToString(print_capabilities_stream.get(),
    194                                    &printer_info->printer_capabilities);
    195       DCHECK(SUCCEEDED(hr));
    196       printer_info->caps_mime_type = "text/xml";
    197     }
    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";
    227         }
    228       }
    229     }
    230     XPSModule::CloseProvider(provider);
    231   }
    232   return true;
    233 }
    234 
    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();
    241   }
    242   return GetDriverInfo(printer);
    243 }
    244 
    245 bool PrintBackendWin::IsValidPrinter(const std::string& printer_name) {
    246   ScopedPrinterHandle printer_handle;
    247   return printer_handle.OpenPrinter(UTF8ToWide(printer_name).c_str());
    248 }
    249 
    250 scoped_refptr<PrintBackend> PrintBackend::CreateInstance(
    251     const base::DictionaryValue* print_backend_settings) {
    252   return new PrintBackendWin;
    253 }
    254 
    255 }  // namespace printing
    256