15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "printing/backend/win_helper.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/file_version_info.h"
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/files/file_path.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_ptr.h"
135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/numerics/safe_conversions.h"
145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/strings/string_util.h"
155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/strings/stringprintf.h"
16868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/win/scoped_comptr.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "printing/backend/print_backend.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "printing/backend/print_backend_consts.h"
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "printing/backend/printing_info_win.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef HRESULT (WINAPI* PTOpenProviderProc)(PCWSTR printer_name,
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                             DWORD version,
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                             HPTPROVIDER* provider);
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef HRESULT (WINAPI* PTGetPrintCapabilitiesProc)(HPTPROVIDER provider,
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                     IStream* print_ticket,
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                     IStream* capabilities,
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                     BSTR* error_message);
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef HRESULT (WINAPI* PTConvertDevModeToPrintTicketProc)(
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HPTPROVIDER provider,
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ULONG devmode_size_in_bytes,
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PDEVMODE devmode,
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EPrintTicketScope scope,
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    IStream* print_ticket);
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef HRESULT (WINAPI* PTConvertPrintTicketToDevModeProc)(
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HPTPROVIDER provider,
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    IStream* print_ticket,
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EDefaultDevmodeType base_devmode_type,
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EPrintTicketScope scope,
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ULONG* devmode_byte_count,
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PDEVMODE* devmode,
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BSTR* error_message);
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef HRESULT (WINAPI* PTMergeAndValidatePrintTicketProc)(
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HPTPROVIDER provider,
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    IStream* base_ticket,
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    IStream* delta_ticket,
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EPrintTicketScope scope,
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    IStream* result_ticket,
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BSTR* error_message);
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef HRESULT (WINAPI* PTReleaseMemoryProc)(PVOID buffer);
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef HRESULT (WINAPI* PTCloseProviderProc)(HPTPROVIDER provider);
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef HRESULT (WINAPI* StartXpsPrintJobProc)(
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const LPCWSTR printer_name,
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const LPCWSTR job_name,
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const LPCWSTR output_file_name,
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HANDLE progress_event,
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HANDLE completion_event,
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UINT8* printable_pages_on,
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UINT32 printable_pages_on_count,
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    IXpsPrintJob** xps_print_job,
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    IXpsPrintJobStream** document_stream,
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    IXpsPrintJobStream** print_ticket_stream);
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PTOpenProviderProc g_open_provider_proc = NULL;
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PTGetPrintCapabilitiesProc g_get_print_capabilities_proc = NULL;
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PTConvertDevModeToPrintTicketProc g_convert_devmode_to_print_ticket_proc = NULL;
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PTConvertPrintTicketToDevModeProc g_convert_print_ticket_to_devmode_proc = NULL;
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PTMergeAndValidatePrintTicketProc g_merge_and_validate_print_ticket_proc = NULL;
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PTReleaseMemoryProc g_release_memory_proc = NULL;
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PTCloseProviderProc g_close_provider_proc = NULL;
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)StartXpsPrintJobProc g_start_xps_print_job_proc = NULL;
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)HRESULT StreamFromPrintTicket(const std::string& print_ticket,
835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                              IStream** stream) {
845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(stream);
855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  HRESULT hr = CreateStreamOnHGlobal(NULL, TRUE, stream);
865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (FAILED(hr)) {
875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return hr;
885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ULONG bytes_written = 0;
905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  (*stream)->Write(print_ticket.c_str(),
915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                   base::checked_cast<ULONG>(print_ticket.length()),
925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                   &bytes_written);
935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(bytes_written == print_ticket.length());
945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  LARGE_INTEGER pos = {0};
955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ULARGE_INTEGER new_pos = {0};
965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  (*stream)->Seek(pos, STREAM_SEEK_SET, &new_pos);
975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return S_OK;
985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kXpsTicketTemplate[] =
1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  "<?xml version='1.0' encoding='UTF-8'?>"
1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  "<psf:PrintTicket "
1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  "xmlns:psf='"
1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  "http://schemas.microsoft.com/windows/2003/08/printing/printschemaframework' "
1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  "xmlns:psk="
1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  "'http://schemas.microsoft.com/windows/2003/08/printing/printschemakeywords' "
1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  "version='1'>"
1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  "<psf:Feature name='psk:PageOutputColor'>"
1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  "<psf:Option name='psk:%s'>"
1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  "</psf:Option>"
1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  "</psf:Feature>"
1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  "</psf:PrintTicket>";
1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kXpsTicketColor[] = "Color";
1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kXpsTicketMonochrome[] = "Monochrome";
1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace printing {
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool XPSModule::Init() {
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static bool initialized = InitImpl();
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return initialized;
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool XPSModule::InitImpl() {
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HMODULE prntvpt_module = LoadLibrary(L"prntvpt.dll");
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (prntvpt_module == NULL)
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_open_provider_proc = reinterpret_cast<PTOpenProviderProc>(
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GetProcAddress(prntvpt_module, "PTOpenProvider"));
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!g_open_provider_proc) {
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_get_print_capabilities_proc = reinterpret_cast<PTGetPrintCapabilitiesProc>(
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GetProcAddress(prntvpt_module, "PTGetPrintCapabilities"));
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!g_get_print_capabilities_proc) {
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_convert_devmode_to_print_ticket_proc =
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      reinterpret_cast<PTConvertDevModeToPrintTicketProc>(
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          GetProcAddress(prntvpt_module, "PTConvertDevModeToPrintTicket"));
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!g_convert_devmode_to_print_ticket_proc) {
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_convert_print_ticket_to_devmode_proc =
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      reinterpret_cast<PTConvertPrintTicketToDevModeProc>(
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          GetProcAddress(prntvpt_module, "PTConvertPrintTicketToDevMode"));
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!g_convert_print_ticket_to_devmode_proc) {
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_merge_and_validate_print_ticket_proc =
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      reinterpret_cast<PTMergeAndValidatePrintTicketProc>(
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          GetProcAddress(prntvpt_module, "PTMergeAndValidatePrintTicket"));
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!g_merge_and_validate_print_ticket_proc) {
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_release_memory_proc =
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      reinterpret_cast<PTReleaseMemoryProc>(
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          GetProcAddress(prntvpt_module, "PTReleaseMemory"));
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!g_release_memory_proc) {
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_close_provider_proc =
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      reinterpret_cast<PTCloseProviderProc>(
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          GetProcAddress(prntvpt_module, "PTCloseProvider"));
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!g_close_provider_proc) {
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)HRESULT XPSModule::OpenProvider(const base::string16& printer_name,
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                DWORD version,
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                HPTPROVIDER* provider) {
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return g_open_provider_proc(printer_name.c_str(), version, provider);
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HRESULT XPSModule::GetPrintCapabilities(HPTPROVIDER provider,
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                        IStream* print_ticket,
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                        IStream* capabilities,
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                        BSTR* error_message) {
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return g_get_print_capabilities_proc(provider,
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       print_ticket,
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       capabilities,
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       error_message);
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HRESULT XPSModule::ConvertDevModeToPrintTicket(HPTPROVIDER provider,
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               ULONG devmode_size_in_bytes,
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               PDEVMODE devmode,
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               EPrintTicketScope scope,
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               IStream* print_ticket) {
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return g_convert_devmode_to_print_ticket_proc(provider,
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                devmode_size_in_bytes,
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                devmode,
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                scope,
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                print_ticket);
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HRESULT XPSModule::ConvertPrintTicketToDevMode(
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HPTPROVIDER provider,
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    IStream* print_ticket,
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EDefaultDevmodeType base_devmode_type,
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EPrintTicketScope scope,
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ULONG* devmode_byte_count,
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PDEVMODE* devmode,
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BSTR* error_message) {
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return g_convert_print_ticket_to_devmode_proc(provider,
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                print_ticket,
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                base_devmode_type,
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                scope,
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                devmode_byte_count,
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                devmode,
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                error_message);
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HRESULT XPSModule::MergeAndValidatePrintTicket(HPTPROVIDER provider,
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               IStream* base_ticket,
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               IStream* delta_ticket,
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               EPrintTicketScope scope,
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               IStream* result_ticket,
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               BSTR* error_message) {
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return g_merge_and_validate_print_ticket_proc(provider,
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                base_ticket,
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                delta_ticket,
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                scope,
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                result_ticket,
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                error_message);
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HRESULT XPSModule::ReleaseMemory(PVOID buffer) {
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return g_release_memory_proc(buffer);
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HRESULT XPSModule::CloseProvider(HPTPROVIDER provider) {
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return g_close_provider_proc(provider);
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ScopedXPSInitializer::ScopedXPSInitializer() : initialized_(false) {
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!XPSModule::Init())
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Calls to XPS APIs typically require the XPS provider to be opened with
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // PTOpenProvider. PTOpenProvider calls CoInitializeEx with
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // COINIT_MULTITHREADED. We have seen certain buggy HP printer driver DLLs
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // that call CoInitializeEx with COINIT_APARTMENTTHREADED in the context of
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // PTGetPrintCapabilities. This call fails but the printer driver calls
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // CoUninitialize anyway. This results in the apartment being torn down too
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // early and the msxml DLL being unloaded which in turn causes code in
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // unidrvui.dll to have a dangling pointer to an XML document which causes a
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // crash. To protect ourselves from such drivers we make sure we always have
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // an extra CoInitialize (calls to CoInitialize/CoUninitialize are
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // refcounted).
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If this succeeded we are done because the PTOpenProvider call will provide
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the extra refcount on the apartment. If it failed because someone already
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // called CoInitializeEx with COINIT_APARTMENTTHREADED, we try the other model
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // to provide the additional refcount (since we don't know which model buggy
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // printer drivers will use).
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!SUCCEEDED(hr))
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(SUCCEEDED(hr));
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  initialized_ = true;
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ScopedXPSInitializer::~ScopedXPSInitializer() {
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (initialized_)
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CoUninitialize();
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  initialized_ = false;
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool XPSPrintModule::Init() {
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static bool initialized = InitImpl();
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return initialized;
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool XPSPrintModule::InitImpl() {
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HMODULE xpsprint_module = LoadLibrary(L"xpsprint.dll");
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (xpsprint_module == NULL)
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_start_xps_print_job_proc = reinterpret_cast<StartXpsPrintJobProc>(
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GetProcAddress(xpsprint_module, "StartXpsPrintJob"));
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!g_start_xps_print_job_proc) {
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HRESULT XPSPrintModule::StartXpsPrintJob(
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const LPCWSTR printer_name,
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const LPCWSTR job_name,
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const LPCWSTR output_file_name,
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HANDLE progress_event,
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HANDLE completion_event,
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UINT8* printable_pages_on,
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UINT32 printable_pages_on_count,
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    IXpsPrintJob** xps_print_job,
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    IXpsPrintJobStream** document_stream,
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    IXpsPrintJobStream** print_ticket_stream) {
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return g_start_xps_print_job_proc(printer_name,
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    job_name,
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    output_file_name,
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    progress_event,
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    completion_event,
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    printable_pages_on,
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    printable_pages_on_count,
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    xps_print_job,
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    document_stream,
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    print_ticket_stream);
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool InitBasicPrinterInfo(HANDLE printer, PrinterBasicInfo* printer_info) {
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(printer);
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(printer_info);
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!printer)
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  PrinterInfo2 info_2;
3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!info_2.Init(printer))
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  printer_info->printer_name = base::WideToUTF8(info_2.get()->pPrinterName);
3335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (info_2.get()->pComment) {
3345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    printer_info->printer_description =
3355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        base::WideToUTF8(info_2.get()->pComment);
3365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (info_2.get()->pLocation) {
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    printer_info->options[kLocationTagName] =
3395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        base::WideToUTF8(info_2.get()->pLocation);
3405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (info_2.get()->pDriverName) {
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    printer_info->options[kDriverNameTagName] =
3435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        base::WideToUTF8(info_2.get()->pDriverName);
3445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  printer_info->printer_status = info_2.get()->Status;
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string driver_info = GetDriverInfo(printer);
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!driver_info.empty())
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    printer_info->options[kDriverInfoTagName] = driver_info;
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string GetDriverInfo(HANDLE printer) {
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(printer);
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string driver_info;
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!printer)
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return driver_info;
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DriverInfo6 info_6;
3612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!info_6.Init(printer))
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return driver_info;
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string info[4];
3652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (info_6.get()->pName)
3665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    info[0] = base::WideToUTF8(info_6.get()->pName);
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (info_6.get()->pDriverPath) {
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_ptr<FileVersionInfo> version_info(
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        FileVersionInfo::CreateFileVersionInfo(
3712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            base::FilePath(info_6.get()->pDriverPath)));
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (version_info.get()) {
3735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      info[1] = base::WideToUTF8(version_info->file_version());
3745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      info[2] = base::WideToUTF8(version_info->product_name());
3755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      info[3] = base::WideToUTF8(version_info->product_version());
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < arraysize(info); ++i) {
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::replace(info[i].begin(), info[i].end(), ';', ',');
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    driver_info.append(info[i]);
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (i < arraysize(info) - 1)
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      driver_info.append(";");
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return driver_info;
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
388a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)scoped_ptr<DEVMODE, base::FreeDeleter> XpsTicketToDevMode(
389a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const base::string16& printer_name,
390a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const std::string& print_ticket) {
391a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  scoped_ptr<DEVMODE, base::FreeDeleter> dev_mode;
3925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  printing::ScopedXPSInitializer xps_initializer;
3935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!xps_initializer.initialized()) {
3945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // TODO(sanjeevr): Handle legacy proxy case (with no prntvpt.dll)
395a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return dev_mode.Pass();
3965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  printing::ScopedPrinterHandle printer;
3995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!printer.OpenPrinter(printer_name.c_str()))
400a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return dev_mode.Pass();
4015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::win::ScopedComPtr<IStream> pt_stream;
4035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  HRESULT hr = StreamFromPrintTicket(print_ticket, pt_stream.Receive());
4045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (FAILED(hr))
405a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return dev_mode.Pass();
4065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  HPTPROVIDER provider = NULL;
4085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  hr = printing::XPSModule::OpenProvider(printer_name, 1, &provider);
4095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (SUCCEEDED(hr)) {
4105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ULONG size = 0;
4115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DEVMODE* dm = NULL;
4125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Use kPTJobScope, because kPTDocumentScope breaks duplex.
4135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    hr = printing::XPSModule::ConvertPrintTicketToDevMode(provider,
4145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                          pt_stream,
4155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                          kUserDefaultDevmode,
4165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                          kPTJobScope,
4175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                          &size,
4185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                          &dm,
4195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                          NULL);
4205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (SUCCEEDED(hr)) {
4215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      // Correct DEVMODE using DocumentProperties. See documentation for
4225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      // PTConvertPrintTicketToDevMode.
4231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      dev_mode = CreateDevMode(printer.Get(), dm);
4245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      printing::XPSModule::ReleaseMemory(dm);
4255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
4265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    printing::XPSModule::CloseProvider(provider);
4275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
428a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return dev_mode.Pass();
4295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
4305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
431a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)scoped_ptr<DEVMODE, base::FreeDeleter> CreateDevModeWithColor(
432a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    HANDLE printer,
433a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const base::string16& printer_name,
434a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    bool color) {
435116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  scoped_ptr<DEVMODE, base::FreeDeleter> default_ticket =
436116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      CreateDevMode(printer, NULL);
437116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!default_ticket)
438116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return default_ticket.Pass();
439116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
440116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if ((default_ticket->dmFields & DM_COLOR) &&
441116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      ((default_ticket->dmColor == DMCOLOR_COLOR) == color)) {
442116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return default_ticket.Pass();
4435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
4445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
445116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  default_ticket->dmFields |= DM_COLOR;
446116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  default_ticket->dmColor = color ? DMCOLOR_COLOR : DMCOLOR_MONOCHROME;
4475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DriverInfo6 info_6;
4495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!info_6.Init(printer))
450116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return default_ticket.Pass();
4515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const DRIVER_INFO_6* p = info_6.get();
4535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Only HP known to have issues.
4555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!p->pszMfgName || wcscmp(p->pszMfgName, L"HP") != 0)
456116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return default_ticket.Pass();
4575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Need XPS for this workaround.
4595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  printing::ScopedXPSInitializer xps_initializer;
4605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!xps_initializer.initialized())
461116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return default_ticket.Pass();
4625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const char* xps_color = color ? kXpsTicketColor : kXpsTicketMonochrome;
4645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string xps_ticket = base::StringPrintf(kXpsTicketTemplate, xps_color);
465a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  scoped_ptr<DEVMODE, base::FreeDeleter> ticket =
466a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      printing::XpsTicketToDevMode(printer_name, xps_ticket);
4675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!ticket)
468116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return default_ticket.Pass();
4695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return ticket.Pass();
4715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
4725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
473a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)scoped_ptr<DEVMODE, base::FreeDeleter> CreateDevMode(HANDLE printer,
474a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                                     DEVMODE* in) {
4755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  LONG buffer_size = DocumentProperties(
4765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      NULL, printer, const_cast<wchar_t*>(L""), NULL, NULL, 0);
477a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (buffer_size < static_cast<int>(sizeof(DEVMODE)))
478a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return scoped_ptr<DEVMODE, base::FreeDeleter>();
479a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  scoped_ptr<DEVMODE, base::FreeDeleter> out(
480a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      reinterpret_cast<DEVMODE*>(malloc(buffer_size)));
481a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DWORD flags = (in ? (DM_IN_BUFFER) : 0) | DM_OUT_BUFFER;
4825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (DocumentProperties(
4835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          NULL, printer, const_cast<wchar_t*>(L""), out.get(), in, flags) !=
4845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      IDOK) {
485a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return scoped_ptr<DEVMODE, base::FreeDeleter>();
4865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
487a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  CHECK_GE(buffer_size, out.get()->dmSize + out.get()->dmDriverExtra);
4885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return out.Pass();
4895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
4905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciscoped_ptr<DEVMODE, base::FreeDeleter> PromptDevMode(
4921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    HANDLE printer,
4931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const base::string16& printer_name,
4941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    DEVMODE* in,
4951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    HWND window,
4961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    bool* canceled) {
4971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  LONG buffer_size =
4981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      DocumentProperties(window,
4991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                         printer,
5001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                         const_cast<wchar_t*>(printer_name.c_str()),
5011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                         NULL,
5021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                         NULL,
5031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                         0);
5041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (buffer_size < static_cast<int>(sizeof(DEVMODE)))
5051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return scoped_ptr<DEVMODE, base::FreeDeleter>();
5061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  scoped_ptr<DEVMODE, base::FreeDeleter> out(
5071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      reinterpret_cast<DEVMODE*>(malloc(buffer_size)));
5081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DWORD flags = (in ? (DM_IN_BUFFER) : 0) | DM_OUT_BUFFER | DM_IN_PROMPT;
5091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  LONG result = DocumentProperties(window,
5101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                   printer,
5111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                   const_cast<wchar_t*>(printer_name.c_str()),
5121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                   out.get(),
5131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                   in,
5141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                   flags);
5151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (canceled)
5161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    *canceled = (result == IDCANCEL);
5171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (result != IDOK)
5181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return scoped_ptr<DEVMODE, base::FreeDeleter>();
5191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  CHECK_GE(buffer_size, out.get()->dmSize + out.get()->dmDriverExtra);
5201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return out.Pass();
5211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
5221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace printing
524