- add sources.
[platform/framework/web/crosswalk.git] / src / printing / backend / win_helper.cc
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/win_helper.h"
6
7 #include <algorithm>
8
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"
17
18 namespace {
19
20 typedef HRESULT (WINAPI* PTOpenProviderProc)(PCWSTR printer_name,
21                                              DWORD version,
22                                              HPTPROVIDER* provider);
23
24 typedef HRESULT (WINAPI* PTGetPrintCapabilitiesProc)(HPTPROVIDER provider,
25                                                      IStream* print_ticket,
26                                                      IStream* capabilities,
27                                                      BSTR* error_message);
28
29 typedef HRESULT (WINAPI* PTConvertDevModeToPrintTicketProc)(
30     HPTPROVIDER provider,
31     ULONG devmode_size_in_bytes,
32     PDEVMODE devmode,
33     EPrintTicketScope scope,
34     IStream* print_ticket);
35
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);
44
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);
52
53 typedef HRESULT (WINAPI* PTReleaseMemoryProc)(PVOID buffer);
54
55 typedef HRESULT (WINAPI* PTCloseProviderProc)(HPTPROVIDER provider);
56
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);
68
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;
77
78 }  // namespace
79
80
81 namespace printing {
82
83 bool XPSModule::Init() {
84   static bool initialized = InitImpl();
85   return initialized;
86 }
87
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;
97   }
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;
103   }
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;
110   }
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;
117   }
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;
124   }
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;
131   }
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;
138   }
139   return true;
140 }
141
142 HRESULT XPSModule::OpenProvider(const base::string16& printer_name,
143                                 DWORD version,
144                                 HPTPROVIDER* provider) {
145   return g_open_provider_proc(printer_name.c_str(), version, provider);
146 }
147
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);
156 }
157
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);
168 }
169
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);
185 }
186
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);
199 }
200
201 HRESULT XPSModule::ReleaseMemory(PVOID buffer) {
202   return g_release_memory_proc(buffer);
203 }
204
205 HRESULT XPSModule::CloseProvider(HPTPROVIDER provider) {
206   return g_close_provider_proc(provider);
207 }
208
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;
233 }
234
235 ScopedXPSInitializer::~ScopedXPSInitializer() {
236   if (initialized_)
237     CoUninitialize();
238   initialized_ = false;
239 }
240
241 bool XPSPrintModule::Init() {
242   static bool initialized = InitImpl();
243   return initialized;
244 }
245
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;
255   }
256   return true;
257 }
258
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);
280 }
281
282 bool InitBasicPrinterInfo(HANDLE printer, PrinterBasicInfo* printer_info) {
283   DCHECK(printer);
284   DCHECK(printer_info);
285   if (!printer)
286     return false;
287
288   PrinterInfo2 info_2;
289   if (!info_2.Init(printer))
290     return false;
291
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;
302
303   std::string driver_info = GetDriverInfo(printer);
304   if (!driver_info.empty())
305     printer_info->options[kDriverInfoTagName] = driver_info;
306   return true;
307 }
308
309 std::string GetDriverInfo(HANDLE printer) {
310   DCHECK(printer);
311   std::string driver_info;
312
313   if (!printer)
314     return driver_info;
315
316   DriverInfo6 info_6;
317   if (!info_6.Init(printer))
318     return driver_info;
319
320   std::string info[4];
321   if (info_6.get()->pName)
322     info[0] = WideToUTF8(info_6.get()->pName);
323
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());
332     }
333   }
334
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(";");
340   }
341   return driver_info;
342 }
343
344 }  // namespace printing