Change wording in the banner to invite to use Apps Developer Tools from "It's also...
[chromium-blink-merge.git] / printing / backend / win_helper.cc
blob3832dff69a006d4bcecd72b0014dc0d9c276f384
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/win_helper.h"
7 #include <algorithm>
9 #include "base/file_version_info.h"
10 #include "base/files/file_path.h"
11 #include "base/logging.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "printing/backend/print_backend.h"
15 #include "printing/backend/print_backend_consts.h"
16 #include "printing/backend/printing_info_win.h"
18 namespace {
20 typedef HRESULT (WINAPI* PTOpenProviderProc)(PCWSTR printer_name,
21 DWORD version,
22 HPTPROVIDER* provider);
24 typedef HRESULT (WINAPI* PTGetPrintCapabilitiesProc)(HPTPROVIDER provider,
25 IStream* print_ticket,
26 IStream* capabilities,
27 BSTR* error_message);
29 typedef HRESULT (WINAPI* PTConvertDevModeToPrintTicketProc)(
30 HPTPROVIDER provider,
31 ULONG devmode_size_in_bytes,
32 PDEVMODE devmode,
33 EPrintTicketScope scope,
34 IStream* print_ticket);
36 typedef HRESULT (WINAPI* PTConvertPrintTicketToDevModeProc)(
37 HPTPROVIDER provider,
38 IStream* print_ticket,
39 EDefaultDevmodeType base_devmode_type,
40 EPrintTicketScope scope,
41 ULONG* devmode_byte_count,
42 PDEVMODE* devmode,
43 BSTR* error_message);
45 typedef HRESULT (WINAPI* PTMergeAndValidatePrintTicketProc)(
46 HPTPROVIDER provider,
47 IStream* base_ticket,
48 IStream* delta_ticket,
49 EPrintTicketScope scope,
50 IStream* result_ticket,
51 BSTR* error_message);
53 typedef HRESULT (WINAPI* PTReleaseMemoryProc)(PVOID buffer);
55 typedef HRESULT (WINAPI* PTCloseProviderProc)(HPTPROVIDER provider);
57 typedef HRESULT (WINAPI* StartXpsPrintJobProc)(
58 const LPCWSTR printer_name,
59 const LPCWSTR job_name,
60 const LPCWSTR output_file_name,
61 HANDLE progress_event,
62 HANDLE completion_event,
63 UINT8* printable_pages_on,
64 UINT32 printable_pages_on_count,
65 IXpsPrintJob** xps_print_job,
66 IXpsPrintJobStream** document_stream,
67 IXpsPrintJobStream** print_ticket_stream);
69 PTOpenProviderProc g_open_provider_proc = NULL;
70 PTGetPrintCapabilitiesProc g_get_print_capabilities_proc = NULL;
71 PTConvertDevModeToPrintTicketProc g_convert_devmode_to_print_ticket_proc = NULL;
72 PTConvertPrintTicketToDevModeProc g_convert_print_ticket_to_devmode_proc = NULL;
73 PTMergeAndValidatePrintTicketProc g_merge_and_validate_print_ticket_proc = NULL;
74 PTReleaseMemoryProc g_release_memory_proc = NULL;
75 PTCloseProviderProc g_close_provider_proc = NULL;
76 StartXpsPrintJobProc g_start_xps_print_job_proc = NULL;
78 } // namespace
81 namespace printing {
83 bool XPSModule::Init() {
84 static bool initialized = InitImpl();
85 return initialized;
88 bool XPSModule::InitImpl() {
89 HMODULE prntvpt_module = LoadLibrary(L"prntvpt.dll");
90 if (prntvpt_module == NULL)
91 return false;
92 g_open_provider_proc = reinterpret_cast<PTOpenProviderProc>(
93 GetProcAddress(prntvpt_module, "PTOpenProvider"));
94 if (!g_open_provider_proc) {
95 NOTREACHED();
96 return false;
98 g_get_print_capabilities_proc = reinterpret_cast<PTGetPrintCapabilitiesProc>(
99 GetProcAddress(prntvpt_module, "PTGetPrintCapabilities"));
100 if (!g_get_print_capabilities_proc) {
101 NOTREACHED();
102 return false;
104 g_convert_devmode_to_print_ticket_proc =
105 reinterpret_cast<PTConvertDevModeToPrintTicketProc>(
106 GetProcAddress(prntvpt_module, "PTConvertDevModeToPrintTicket"));
107 if (!g_convert_devmode_to_print_ticket_proc) {
108 NOTREACHED();
109 return false;
111 g_convert_print_ticket_to_devmode_proc =
112 reinterpret_cast<PTConvertPrintTicketToDevModeProc>(
113 GetProcAddress(prntvpt_module, "PTConvertPrintTicketToDevMode"));
114 if (!g_convert_print_ticket_to_devmode_proc) {
115 NOTREACHED();
116 return false;
118 g_merge_and_validate_print_ticket_proc =
119 reinterpret_cast<PTMergeAndValidatePrintTicketProc>(
120 GetProcAddress(prntvpt_module, "PTMergeAndValidatePrintTicket"));
121 if (!g_merge_and_validate_print_ticket_proc) {
122 NOTREACHED();
123 return false;
125 g_release_memory_proc =
126 reinterpret_cast<PTReleaseMemoryProc>(
127 GetProcAddress(prntvpt_module, "PTReleaseMemory"));
128 if (!g_release_memory_proc) {
129 NOTREACHED();
130 return false;
132 g_close_provider_proc =
133 reinterpret_cast<PTCloseProviderProc>(
134 GetProcAddress(prntvpt_module, "PTCloseProvider"));
135 if (!g_close_provider_proc) {
136 NOTREACHED();
137 return false;
139 return true;
142 HRESULT XPSModule::OpenProvider(const string16& printer_name,
143 DWORD version,
144 HPTPROVIDER* provider) {
145 return g_open_provider_proc(printer_name.c_str(), version, provider);
148 HRESULT XPSModule::GetPrintCapabilities(HPTPROVIDER provider,
149 IStream* print_ticket,
150 IStream* capabilities,
151 BSTR* error_message) {
152 return g_get_print_capabilities_proc(provider,
153 print_ticket,
154 capabilities,
155 error_message);
158 HRESULT XPSModule::ConvertDevModeToPrintTicket(HPTPROVIDER provider,
159 ULONG devmode_size_in_bytes,
160 PDEVMODE devmode,
161 EPrintTicketScope scope,
162 IStream* print_ticket) {
163 return g_convert_devmode_to_print_ticket_proc(provider,
164 devmode_size_in_bytes,
165 devmode,
166 scope,
167 print_ticket);
170 HRESULT XPSModule::ConvertPrintTicketToDevMode(
171 HPTPROVIDER provider,
172 IStream* print_ticket,
173 EDefaultDevmodeType base_devmode_type,
174 EPrintTicketScope scope,
175 ULONG* devmode_byte_count,
176 PDEVMODE* devmode,
177 BSTR* error_message) {
178 return g_convert_print_ticket_to_devmode_proc(provider,
179 print_ticket,
180 base_devmode_type,
181 scope,
182 devmode_byte_count,
183 devmode,
184 error_message);
187 HRESULT XPSModule::MergeAndValidatePrintTicket(HPTPROVIDER provider,
188 IStream* base_ticket,
189 IStream* delta_ticket,
190 EPrintTicketScope scope,
191 IStream* result_ticket,
192 BSTR* error_message) {
193 return g_merge_and_validate_print_ticket_proc(provider,
194 base_ticket,
195 delta_ticket,
196 scope,
197 result_ticket,
198 error_message);
201 HRESULT XPSModule::ReleaseMemory(PVOID buffer) {
202 return g_release_memory_proc(buffer);
205 HRESULT XPSModule::CloseProvider(HPTPROVIDER provider) {
206 return g_close_provider_proc(provider);
209 ScopedXPSInitializer::ScopedXPSInitializer() : initialized_(false) {
210 if (!XPSModule::Init())
211 return;
212 // Calls to XPS APIs typically require the XPS provider to be opened with
213 // PTOpenProvider. PTOpenProvider calls CoInitializeEx with
214 // COINIT_MULTITHREADED. We have seen certain buggy HP printer driver DLLs
215 // that call CoInitializeEx with COINIT_APARTMENTTHREADED in the context of
216 // PTGetPrintCapabilities. This call fails but the printer driver calls
217 // CoUninitialize anyway. This results in the apartment being torn down too
218 // early and the msxml DLL being unloaded which in turn causes code in
219 // unidrvui.dll to have a dangling pointer to an XML document which causes a
220 // crash. To protect ourselves from such drivers we make sure we always have
221 // an extra CoInitialize (calls to CoInitialize/CoUninitialize are
222 // refcounted).
223 HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
224 // If this succeeded we are done because the PTOpenProvider call will provide
225 // the extra refcount on the apartment. If it failed because someone already
226 // called CoInitializeEx with COINIT_APARTMENTTHREADED, we try the other model
227 // to provide the additional refcount (since we don't know which model buggy
228 // printer drivers will use).
229 if (!SUCCEEDED(hr))
230 hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
231 DCHECK(SUCCEEDED(hr));
232 initialized_ = true;
235 ScopedXPSInitializer::~ScopedXPSInitializer() {
236 if (initialized_)
237 CoUninitialize();
238 initialized_ = false;
241 bool XPSPrintModule::Init() {
242 static bool initialized = InitImpl();
243 return initialized;
246 bool XPSPrintModule::InitImpl() {
247 HMODULE xpsprint_module = LoadLibrary(L"xpsprint.dll");
248 if (xpsprint_module == NULL)
249 return false;
250 g_start_xps_print_job_proc = reinterpret_cast<StartXpsPrintJobProc>(
251 GetProcAddress(xpsprint_module, "StartXpsPrintJob"));
252 if (!g_start_xps_print_job_proc) {
253 NOTREACHED();
254 return false;
256 return true;
259 HRESULT XPSPrintModule::StartXpsPrintJob(
260 const LPCWSTR printer_name,
261 const LPCWSTR job_name,
262 const LPCWSTR output_file_name,
263 HANDLE progress_event,
264 HANDLE completion_event,
265 UINT8* printable_pages_on,
266 UINT32 printable_pages_on_count,
267 IXpsPrintJob** xps_print_job,
268 IXpsPrintJobStream** document_stream,
269 IXpsPrintJobStream** print_ticket_stream) {
270 return g_start_xps_print_job_proc(printer_name,
271 job_name,
272 output_file_name,
273 progress_event,
274 completion_event,
275 printable_pages_on,
276 printable_pages_on_count,
277 xps_print_job,
278 document_stream,
279 print_ticket_stream);
282 bool InitBasicPrinterInfo(HANDLE printer, PrinterBasicInfo* printer_info) {
283 DCHECK(printer);
284 DCHECK(printer_info);
285 if (!printer)
286 return false;
288 PrinterInfo2 info_2;
289 if (!info_2.Init(printer))
290 return false;
292 printer_info->printer_name = WideToUTF8(info_2.get()->pPrinterName);
293 if (info_2.get()->pComment)
294 printer_info->printer_description = WideToUTF8(info_2.get()->pComment);
295 if (info_2.get()->pLocation)
296 printer_info->options[kLocationTagName] =
297 WideToUTF8(info_2.get()->pLocation);
298 if (info_2.get()->pDriverName)
299 printer_info->options[kDriverNameTagName] =
300 WideToUTF8(info_2.get()->pDriverName);
301 printer_info->printer_status = info_2.get()->Status;
303 std::string driver_info = GetDriverInfo(printer);
304 if (!driver_info.empty())
305 printer_info->options[kDriverInfoTagName] = driver_info;
306 return true;
309 std::string GetDriverInfo(HANDLE printer) {
310 DCHECK(printer);
311 std::string driver_info;
313 if (!printer)
314 return driver_info;
316 DriverInfo6 info_6;
317 if (!info_6.Init(printer))
318 return driver_info;
320 std::string info[4];
321 if (info_6.get()->pName)
322 info[0] = WideToUTF8(info_6.get()->pName);
324 if (info_6.get()->pDriverPath) {
325 scoped_ptr<FileVersionInfo> version_info(
326 FileVersionInfo::CreateFileVersionInfo(
327 base::FilePath(info_6.get()->pDriverPath)));
328 if (version_info.get()) {
329 info[1] = WideToUTF8(version_info->file_version());
330 info[2] = WideToUTF8(version_info->product_name());
331 info[3] = WideToUTF8(version_info->product_version());
335 for (size_t i = 0; i < arraysize(info); ++i) {
336 std::replace(info[i].begin(), info[i].end(), ';', ',');
337 driver_info.append(info[i]);
338 if (i < arraysize(info) - 1)
339 driver_info.append(";");
341 return driver_info;
344 } // namespace printing