OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/service/cloud_print/print_system.h" | 5 #include "printing/backend/print_backend.h" |
6 | 6 |
7 #include <windows.h> | |
8 #include <objidl.h> | 7 #include <objidl.h> |
9 #include <ocidl.h> | |
10 #include <olectl.h> | |
11 #include <prntvpt.h> | 8 #include <prntvpt.h> |
12 #include <winspool.h> | 9 #include <winspool.h> |
13 | 10 |
14 #include "base/lock.h" | |
15 #include "base/file_util.h" | |
16 #include "base/object_watcher.h" | |
17 #include "base/scoped_ptr.h" | 11 #include "base/scoped_ptr.h" |
| 12 #include "base/string_piece.h" |
18 #include "base/utf_string_conversions.h" | 13 #include "base/utf_string_conversions.h" |
19 #include "base/win/scoped_bstr.h" | 14 #include "base/win/scoped_bstr.h" |
20 #include "base/win/scoped_comptr.h" | 15 #include "base/win/scoped_comptr.h" |
21 #include "chrome/service/cloud_print/cloud_print_consts.h" | 16 #include "base/win/scoped_hglobal.h" |
22 #include "chrome/service/service_process.h" | 17 #include "printing/backend/print_backend_consts.h" |
23 #include "chrome/service/service_utility_process_host.h" | 18 #include "printing/backend/win_helper.h" |
24 #include "gfx/rect.h" | |
25 #include "printing/native_metafile.h" | |
26 #include "printing/page_range.h" | |
27 | 19 |
28 #pragma comment(lib, "prntvpt.lib") | 20 #pragma comment(lib, "prntvpt.lib") |
29 #pragma comment(lib, "rpcrt4.lib") | |
30 | 21 |
31 using base::win::ScopedBstr; | 22 using base::win::ScopedBstr; |
32 using base::win::ScopedComPtr; | 23 using base::win::ScopedComPtr; |
| 24 using base::win::ScopedHGlobal; |
33 | 25 |
34 namespace { | 26 namespace { |
35 | 27 |
36 class DevMode { | |
37 public: | |
38 DevMode() : dm_(NULL) {} | |
39 ~DevMode() { Free(); } | |
40 | |
41 void Allocate(int size) { | |
42 Free(); | |
43 dm_ = reinterpret_cast<DEVMODE*>(new char[size]); | |
44 } | |
45 | |
46 void Free() { | |
47 if (dm_) | |
48 delete [] dm_; | |
49 dm_ = NULL; | |
50 } | |
51 | |
52 DEVMODE* dm_; | |
53 | |
54 private: | |
55 DISALLOW_COPY_AND_ASSIGN(DevMode); | |
56 }; | |
57 | |
58 bool InitXPSModule() { | |
59 HMODULE prntvpt_module = LoadLibrary(L"prntvpt.dll"); | |
60 return (NULL != prntvpt_module); | |
61 } | |
62 | |
63 inline HRESULT GetLastErrorHR() { | |
64 LONG error = GetLastError(); | |
65 return HRESULT_FROM_WIN32(error); | |
66 } | |
67 | |
68 HRESULT StreamFromPrintTicket(const std::string& print_ticket, | |
69 IStream** stream) { | |
70 DCHECK(stream); | |
71 HRESULT hr = CreateStreamOnHGlobal(NULL, TRUE, stream); | |
72 if (FAILED(hr)) { | |
73 return hr; | |
74 } | |
75 ULONG bytes_written = 0; | |
76 (*stream)->Write(print_ticket.c_str(), print_ticket.length(), &bytes_written); | |
77 DCHECK(bytes_written == print_ticket.length()); | |
78 LARGE_INTEGER pos = {0}; | |
79 ULARGE_INTEGER new_pos = {0}; | |
80 (*stream)->Seek(pos, STREAM_SEEK_SET, &new_pos); | |
81 return S_OK; | |
82 } | |
83 | |
84 HRESULT StreamOnHGlobalToString(IStream* stream, std::string* out) { | 28 HRESULT StreamOnHGlobalToString(IStream* stream, std::string* out) { |
85 DCHECK(stream); | 29 DCHECK(stream); |
86 DCHECK(out); | 30 DCHECK(out); |
87 HGLOBAL hdata = NULL; | 31 HGLOBAL hdata = NULL; |
88 HRESULT hr = GetHGlobalFromStream(stream, &hdata); | 32 HRESULT hr = GetHGlobalFromStream(stream, &hdata); |
89 if (SUCCEEDED(hr)) { | 33 if (SUCCEEDED(hr)) { |
90 DCHECK(hdata); | 34 DCHECK(hdata); |
91 ScopedHGlobal<char> locked_data(hdata); | 35 ScopedHGlobal<char> locked_data(hdata); |
92 out->assign(locked_data.release(), locked_data.Size()); | 36 out->assign(locked_data.release(), locked_data.Size()); |
93 } | 37 } |
94 return hr; | 38 return hr; |
95 } | 39 } |
96 | 40 |
97 HRESULT PrintTicketToDevMode(const std::string& printer_name, | |
98 const std::string& print_ticket, | |
99 DevMode* dev_mode) { | |
100 DCHECK(dev_mode); | |
101 | |
102 ScopedComPtr<IStream> pt_stream; | |
103 HRESULT hr = StreamFromPrintTicket(print_ticket, pt_stream.Receive()); | |
104 if (FAILED(hr)) | |
105 return hr; | |
106 | |
107 HPTPROVIDER provider = NULL; | |
108 hr = PTOpenProvider(UTF8ToWide(printer_name).c_str(), 1, &provider); | |
109 if (SUCCEEDED(hr)) { | |
110 ULONG size = 0; | |
111 DEVMODE* dm = NULL; | |
112 hr = PTConvertPrintTicketToDevMode(provider, | |
113 pt_stream, | |
114 kUserDefaultDevmode, | |
115 kPTDocumentScope, | |
116 &size, | |
117 &dm, | |
118 NULL); | |
119 if (SUCCEEDED(hr)) { | |
120 dev_mode->Allocate(size); | |
121 memcpy(dev_mode->dm_, dm, size); | |
122 PTReleaseMemory(dm); | |
123 } | |
124 PTCloseProvider(provider); | |
125 } | |
126 return hr; | |
127 } | |
128 | |
129 } // namespace | 41 } // namespace |
130 | 42 |
131 namespace cloud_print { | 43 namespace printing { |
132 | 44 |
133 class PrintSystemWatcherWin | 45 class PrintBackendWin : public PrintBackend { |
134 : public base::ObjectWatcher::Delegate { | |
135 public: | 46 public: |
136 PrintSystemWatcherWin() | 47 PrintBackendWin() {} |
137 : printer_(NULL), printer_change_(NULL), delegate_(NULL) { | 48 virtual ~PrintBackendWin() {} |
138 } | |
139 ~PrintSystemWatcherWin() { | |
140 Stop(); | |
141 } | |
142 | 49 |
143 class Delegate { | |
144 public: | |
145 virtual void OnPrinterAdded() = 0; | |
146 virtual void OnPrinterDeleted() = 0; | |
147 virtual void OnPrinterChanged() = 0; | |
148 virtual void OnJobChanged() = 0; | |
149 }; | |
150 | |
151 bool Start(const std::string& printer_name, Delegate* delegate) { | |
152 delegate_ = delegate; | |
153 // An empty printer name means watch the current server, we need to pass | |
154 // NULL to OpenPrinter. | |
155 LPTSTR printer_name_to_use = NULL; | |
156 std::wstring printer_name_wide; | |
157 if (!printer_name.empty()) { | |
158 printer_name_wide = UTF8ToWide(printer_name); | |
159 printer_name_to_use = const_cast<LPTSTR>(printer_name_wide.c_str()); | |
160 } | |
161 bool ret = false; | |
162 OpenPrinter(printer_name_to_use, &printer_, NULL); | |
163 if (printer_) { | |
164 printer_change_ = FindFirstPrinterChangeNotification( | |
165 printer_, PRINTER_CHANGE_PRINTER|PRINTER_CHANGE_JOB, 0, NULL); | |
166 if (printer_change_) { | |
167 ret = watcher_.StartWatching(printer_change_, this); | |
168 } | |
169 } | |
170 if (!ret) { | |
171 Stop(); | |
172 } | |
173 return ret; | |
174 } | |
175 bool Stop() { | |
176 watcher_.StopWatching(); | |
177 if (printer_) { | |
178 ClosePrinter(printer_); | |
179 printer_ = NULL; | |
180 } | |
181 if (printer_change_) { | |
182 FindClosePrinterChangeNotification(printer_change_); | |
183 printer_change_ = NULL; | |
184 } | |
185 return true; | |
186 } | |
187 | |
188 // base::ObjectWatcher::Delegate method | |
189 virtual void OnObjectSignaled(HANDLE object) { | |
190 DWORD change = 0; | |
191 FindNextPrinterChangeNotification(object, &change, NULL, NULL); | |
192 | |
193 if (change != ((PRINTER_CHANGE_PRINTER|PRINTER_CHANGE_JOB) & | |
194 (~PRINTER_CHANGE_FAILED_CONNECTION_PRINTER))) { | |
195 // For printer connections, we get spurious change notifications with | |
196 // all flags set except PRINTER_CHANGE_FAILED_CONNECTION_PRINTER. | |
197 // Ignore these. | |
198 if (change & PRINTER_CHANGE_ADD_PRINTER) { | |
199 delegate_->OnPrinterAdded(); | |
200 } else if (change & PRINTER_CHANGE_DELETE_PRINTER) { | |
201 delegate_->OnPrinterDeleted(); | |
202 } else if (change & PRINTER_CHANGE_SET_PRINTER) { | |
203 delegate_->OnPrinterChanged(); | |
204 } | |
205 if (change & PRINTER_CHANGE_JOB) { | |
206 delegate_->OnJobChanged(); | |
207 } | |
208 } | |
209 watcher_.StartWatching(printer_change_, this); | |
210 } | |
211 | |
212 bool GetCurrentPrinterInfo(PrinterBasicInfo* printer_info) { | |
213 DCHECK(printer_info); | |
214 if (!printer_) | |
215 return false; | |
216 | |
217 DWORD bytes_needed = 0; | |
218 bool ret = false; | |
219 GetPrinter(printer_, 2, NULL, 0, &bytes_needed); | |
220 if (0 != bytes_needed) { | |
221 scoped_ptr<BYTE> printer_info_buffer(new BYTE[bytes_needed]); | |
222 if (GetPrinter(printer_, 2, printer_info_buffer.get(), | |
223 bytes_needed, &bytes_needed)) { | |
224 PRINTER_INFO_2* printer_info_win = | |
225 reinterpret_cast<PRINTER_INFO_2*>(printer_info_buffer.get()); | |
226 printer_info->printer_name = WideToUTF8(printer_info_win->pPrinterName); | |
227 if (printer_info_win->pComment) | |
228 printer_info->printer_description = | |
229 WideToUTF8(printer_info_win->pComment); | |
230 if (printer_info_win->pLocation) | |
231 printer_info->options[kLocationTagName] = | |
232 WideToUTF8(printer_info_win->pLocation); | |
233 if (printer_info_win->pDriverName) | |
234 printer_info->options[kDriverNameTagName] = | |
235 WideToUTF8(printer_info_win->pDriverName); | |
236 printer_info->printer_status = printer_info_win->Status; | |
237 ret = true; | |
238 } | |
239 } | |
240 return ret; | |
241 } | |
242 | |
243 private: | |
244 base::ObjectWatcher watcher_; | |
245 HANDLE printer_; // The printer being watched | |
246 HANDLE printer_change_; // Returned by FindFirstPrinterChangeNotifier | |
247 Delegate* delegate_; // Delegate to notify | |
248 bool did_signal_; // DoneWaiting was called | |
249 }; | |
250 | |
251 // This typedef is to workaround the issue with certain versions of | |
252 // Visual Studio where it gets confused between multiple Delegate. | |
253 // In this case, some compilers get confused and inherit | |
254 // PrintSystemWin watchers from wrong Delegate, giving C2664 and C2259 errors. | |
255 typedef PrintSystemWatcherWin::Delegate PrintSystemWatcherWinDelegate; | |
256 | |
257 class PrintSystemWin : public PrintSystem { | |
258 public: | |
259 virtual void EnumeratePrinters(PrinterList* printer_list); | 50 virtual void EnumeratePrinters(PrinterList* printer_list); |
260 | 51 |
261 virtual bool GetPrinterCapsAndDefaults(const std::string& printer_name, | 52 virtual bool GetPrinterCapsAndDefaults(const std::string& printer_name, |
262 PrinterCapsAndDefaults* printer_info); | 53 PrinterCapsAndDefaults* printer_info); |
263 | 54 |
264 virtual bool ValidatePrintTicket(const std::string& printer_name, | |
265 const std::string& print_ticket_data); | |
266 | |
267 virtual bool GetJobDetails(const std::string& printer_name, | |
268 PlatformJobId job_id, | |
269 PrintJobDetails *job_details); | |
270 | |
271 virtual bool IsValidPrinter(const std::string& printer_name); | 55 virtual bool IsValidPrinter(const std::string& printer_name); |
272 | |
273 class PrintServerWatcherWin | |
274 : public PrintSystem::PrintServerWatcher, | |
275 public PrintSystemWatcherWinDelegate { | |
276 public: | |
277 PrintServerWatcherWin() {} | |
278 | |
279 // PrintSystem::PrintServerWatcher interface | |
280 virtual bool StartWatching( | |
281 PrintSystem::PrintServerWatcher::Delegate* delegate) { | |
282 delegate_ = delegate; | |
283 return watcher_.Start(std::string(), this); | |
284 } | |
285 virtual bool StopWatching() { | |
286 bool ret = watcher_.Stop(); | |
287 delegate_ = NULL; | |
288 return ret; | |
289 } | |
290 | |
291 // PrintSystemWatcherWin::Delegate interface | |
292 virtual void OnPrinterAdded() { | |
293 delegate_->OnPrinterAdded(); | |
294 } | |
295 virtual void OnPrinterDeleted() { | |
296 } | |
297 virtual void OnPrinterChanged() { | |
298 } | |
299 virtual void OnJobChanged() { | |
300 } | |
301 | |
302 private: | |
303 PrintSystem::PrintServerWatcher::Delegate* delegate_; | |
304 PrintSystemWatcherWin watcher_; | |
305 DISALLOW_COPY_AND_ASSIGN(PrintServerWatcherWin); | |
306 }; | |
307 | |
308 class PrinterWatcherWin | |
309 : public PrintSystem::PrinterWatcher, | |
310 public PrintSystemWatcherWinDelegate { | |
311 public: | |
312 explicit PrinterWatcherWin(const std::string& printer_name) | |
313 : printer_name_(printer_name) {} | |
314 | |
315 // PrintSystem::PrinterWatcher interface | |
316 virtual bool StartWatching( | |
317 PrintSystem::PrinterWatcher::Delegate* delegate) { | |
318 delegate_ = delegate; | |
319 return watcher_.Start(printer_name_, this); | |
320 } | |
321 virtual bool StopWatching() { | |
322 bool ret = watcher_.Stop(); | |
323 delegate_ = NULL; | |
324 return ret; | |
325 } | |
326 virtual bool GetCurrentPrinterInfo(PrinterBasicInfo* printer_info) { | |
327 return watcher_.GetCurrentPrinterInfo(printer_info); | |
328 } | |
329 | |
330 // PrintSystemWatcherWin::Delegate interface | |
331 virtual void OnPrinterAdded() { | |
332 NOTREACHED(); | |
333 } | |
334 virtual void OnPrinterDeleted() { | |
335 delegate_->OnPrinterDeleted(); | |
336 } | |
337 virtual void OnPrinterChanged() { | |
338 delegate_->OnPrinterChanged(); | |
339 } | |
340 virtual void OnJobChanged() { | |
341 delegate_->OnJobChanged(); | |
342 } | |
343 | |
344 private: | |
345 std::string printer_name_; | |
346 PrintSystem::PrinterWatcher::Delegate* delegate_; | |
347 PrintSystemWatcherWin watcher_; | |
348 DISALLOW_COPY_AND_ASSIGN(PrinterWatcherWin); | |
349 }; | |
350 | |
351 class JobSpoolerWin : public PrintSystem::JobSpooler { | |
352 public: | |
353 JobSpoolerWin() : core_(new Core) {} | |
354 // PrintSystem::JobSpooler implementation. | |
355 virtual bool Spool(const std::string& print_ticket, | |
356 const FilePath& print_data_file_path, | |
357 const std::string& print_data_mime_type, | |
358 const std::string& printer_name, | |
359 const std::string& job_title, | |
360 JobSpooler::Delegate* delegate) { | |
361 return core_->Spool(print_ticket, print_data_file_path, | |
362 print_data_mime_type, printer_name, job_title, | |
363 delegate); | |
364 } | |
365 private: | |
366 // We use a Core class because we want a separate RefCountedThreadSafe | |
367 // implementation for ServiceUtilityProcessHost::Client. | |
368 class Core : public ServiceUtilityProcessHost::Client { | |
369 public: | |
370 Core() | |
371 : last_page_printed_(-1), job_id_(-1), delegate_(NULL), saved_dc_(0) { | |
372 } | |
373 ~Core() { | |
374 } | |
375 bool Spool(const std::string& print_ticket, | |
376 const FilePath& print_data_file_path, | |
377 const std::string& print_data_mime_type, | |
378 const std::string& printer_name, | |
379 const std::string& job_title, | |
380 JobSpooler::Delegate* delegate) { | |
381 if (delegate_) { | |
382 // We are already in the process of printing. | |
383 NOTREACHED(); | |
384 return false; | |
385 } | |
386 last_page_printed_ = -1; | |
387 // We only support PDFs for now. | |
388 if (print_data_mime_type != "application/pdf") { | |
389 NOTREACHED(); | |
390 return false; | |
391 } | |
392 | |
393 if (!InitXPSModule()) { | |
394 // TODO(sanjeevr): Handle legacy proxy case (with no prntvpt.dll) | |
395 return false; | |
396 } | |
397 DevMode pt_dev_mode; | |
398 HRESULT hr = PrintTicketToDevMode(printer_name, print_ticket, | |
399 &pt_dev_mode); | |
400 if (FAILED(hr)) { | |
401 NOTREACHED(); | |
402 return false; | |
403 } | |
404 HDC dc = CreateDC(L"WINSPOOL", UTF8ToWide(printer_name).c_str(), | |
405 NULL, pt_dev_mode.dm_); | |
406 if (!dc) { | |
407 NOTREACHED(); | |
408 return false; | |
409 } | |
410 hr = E_FAIL; | |
411 DOCINFO di = {0}; | |
412 di.cbSize = sizeof(DOCINFO); | |
413 std::wstring doc_name = UTF8ToWide(job_title); | |
414 di.lpszDocName = doc_name.c_str(); | |
415 job_id_ = StartDoc(dc, &di); | |
416 if (job_id_ <= 0) | |
417 return false; | |
418 | |
419 printer_dc_.Set(dc); | |
420 | |
421 int printer_dpi = ::GetDeviceCaps(printer_dc_.Get(), LOGPIXELSX); | |
422 saved_dc_ = SaveDC(printer_dc_.Get()); | |
423 SetGraphicsMode(printer_dc_.Get(), GM_ADVANCED); | |
424 XFORM xform = {0}; | |
425 xform.eM11 = xform.eM22 = static_cast<float>(printer_dpi) / | |
426 static_cast<float>(GetDeviceCaps(GetDC(NULL), LOGPIXELSX)); | |
427 ModifyWorldTransform(printer_dc_.Get(), &xform, MWT_LEFTMULTIPLY); | |
428 print_data_file_path_ = print_data_file_path; | |
429 delegate_ = delegate; | |
430 RenderNextPDFPages(); | |
431 return true; | |
432 } | |
433 | |
434 // ServiceUtilityProcessHost::Client implementation. | |
435 virtual void OnRenderPDFPagesToMetafileSucceeded( | |
436 const printing::NativeMetafile& metafile, | |
437 int highest_rendered_page_number) { | |
438 metafile.SafePlayback(printer_dc_.Get()); | |
439 bool done_printing = (highest_rendered_page_number != | |
440 last_page_printed_ + kPageCountPerBatch); | |
441 last_page_printed_ = highest_rendered_page_number; | |
442 if (done_printing) | |
443 PrintJobDone(); | |
444 else | |
445 RenderNextPDFPages(); | |
446 } | |
447 virtual void OnRenderPDFPagesToMetafileFailed() { | |
448 PrintJobDone(); | |
449 } | |
450 virtual void OnChildDied() { | |
451 PrintJobDone(); | |
452 } | |
453 private: | |
454 void PrintJobDone() { | |
455 // If there is no delegate, then there is nothing pending to process. | |
456 if (!delegate_) | |
457 return; | |
458 RestoreDC(printer_dc_.Get(), saved_dc_); | |
459 EndDoc(printer_dc_.Get()); | |
460 if (-1 == last_page_printed_) { | |
461 delegate_->OnJobSpoolFailed(); | |
462 } else { | |
463 delegate_->OnJobSpoolSucceeded(job_id_); | |
464 } | |
465 delegate_ = NULL; | |
466 } | |
467 void RenderNextPDFPages() { | |
468 printing::PageRange range; | |
469 // Render 10 pages at a time. | |
470 range.from = last_page_printed_ + 1; | |
471 range.to = last_page_printed_ + kPageCountPerBatch; | |
472 std::vector<printing::PageRange> page_ranges; | |
473 page_ranges.push_back(range); | |
474 | |
475 int printer_dpi = ::GetDeviceCaps(printer_dc_.Get(), LOGPIXELSX); | |
476 int dc_width = GetDeviceCaps(printer_dc_.Get(), PHYSICALWIDTH); | |
477 int dc_height = GetDeviceCaps(printer_dc_.Get(), PHYSICALHEIGHT); | |
478 gfx::Rect render_area(0, 0, dc_width, dc_height); | |
479 g_service_process->io_thread()->message_loop_proxy()->PostTask( | |
480 FROM_HERE, | |
481 NewRunnableMethod( | |
482 this, | |
483 &JobSpoolerWin::Core::RenderPDFPagesInSandbox, | |
484 print_data_file_path_, | |
485 render_area, | |
486 printer_dpi, | |
487 page_ranges, | |
488 base::MessageLoopProxy::CreateForCurrentThread())); | |
489 } | |
490 // Called on the service process IO thread. | |
491 void RenderPDFPagesInSandbox( | |
492 const FilePath& pdf_path, const gfx::Rect& render_area, | |
493 int render_dpi, const std::vector<printing::PageRange>& page_ranges, | |
494 const scoped_refptr<base::MessageLoopProxy>& | |
495 client_message_loop_proxy) { | |
496 DCHECK(g_service_process->io_thread()->message_loop_proxy()-> | |
497 BelongsToCurrentThread()); | |
498 scoped_ptr<ServiceUtilityProcessHost> utility_host( | |
499 new ServiceUtilityProcessHost(this, client_message_loop_proxy)); | |
500 if (utility_host->StartRenderPDFPagesToMetafile(pdf_path, | |
501 render_area, | |
502 render_dpi, | |
503 page_ranges)) { | |
504 // The object will self-destruct when the child process dies. | |
505 utility_host.release(); | |
506 } | |
507 } | |
508 // Some Cairo-generated PDFs from Chrome OS result in huge metafiles. | |
509 // So the PageCountPerBatch is set to 1 for now. | |
510 // TODO(sanjeevr): Figure out a smarter way to determine the pages per | |
511 // batch. Filed a bug to track this at | |
512 // http://code.google.com/p/chromium/issues/detail?id=57350. | |
513 static const int kPageCountPerBatch = 1; | |
514 int last_page_printed_; | |
515 PlatformJobId job_id_; | |
516 PrintSystem::JobSpooler::Delegate* delegate_; | |
517 int saved_dc_; | |
518 ScopedHDC printer_dc_; | |
519 FilePath print_data_file_path_; | |
520 DISALLOW_COPY_AND_ASSIGN(JobSpoolerWin::Core); | |
521 }; | |
522 scoped_refptr<Core> core_; | |
523 DISALLOW_COPY_AND_ASSIGN(JobSpoolerWin); | |
524 }; | |
525 | |
526 virtual PrintSystem::PrintServerWatcher* CreatePrintServerWatcher(); | |
527 virtual PrintSystem::PrinterWatcher* CreatePrinterWatcher( | |
528 const std::string& printer_name); | |
529 virtual PrintSystem::JobSpooler* CreateJobSpooler(); | |
530 }; | 56 }; |
531 | 57 |
532 void PrintSystemWin::EnumeratePrinters(PrinterList* printer_list) { | 58 void PrintBackendWin::EnumeratePrinters(PrinterList* printer_list) { |
533 DCHECK(printer_list); | 59 DCHECK(printer_list); |
534 DWORD bytes_needed = 0; | 60 DWORD bytes_needed = 0; |
535 DWORD count_returned = 0; | 61 DWORD count_returned = 0; |
536 BOOL ret = EnumPrinters(PRINTER_ENUM_LOCAL|PRINTER_ENUM_CONNECTIONS, NULL, 2, | 62 BOOL ret = EnumPrinters(PRINTER_ENUM_LOCAL|PRINTER_ENUM_CONNECTIONS, NULL, 2, |
537 NULL, 0, &bytes_needed, &count_returned); | 63 NULL, 0, &bytes_needed, &count_returned); |
538 if (0 != bytes_needed) { | 64 if (0 != bytes_needed) { |
539 scoped_ptr<BYTE> printer_info_buffer(new BYTE[bytes_needed]); | 65 scoped_ptr<BYTE> printer_info_buffer(new BYTE[bytes_needed]); |
540 ret = EnumPrinters(PRINTER_ENUM_LOCAL|PRINTER_ENUM_CONNECTIONS, NULL, 2, | 66 ret = EnumPrinters(PRINTER_ENUM_LOCAL|PRINTER_ENUM_CONNECTIONS, NULL, 2, |
541 printer_info_buffer.get(), bytes_needed, &bytes_needed, | 67 printer_info_buffer.get(), bytes_needed, &bytes_needed, |
542 &count_returned); | 68 &count_returned); |
(...skipping 10 matching lines...) Expand all Loading... |
553 info.options[kLocationTagName] = | 79 info.options[kLocationTagName] = |
554 WideToUTF8(printer_info[index].pLocation); | 80 WideToUTF8(printer_info[index].pLocation); |
555 if (printer_info[index].pDriverName) | 81 if (printer_info[index].pDriverName) |
556 info.options[kDriverNameTagName] = | 82 info.options[kDriverNameTagName] = |
557 WideToUTF8(printer_info[index].pDriverName); | 83 WideToUTF8(printer_info[index].pDriverName); |
558 printer_list->push_back(info); | 84 printer_list->push_back(info); |
559 } | 85 } |
560 } | 86 } |
561 } | 87 } |
562 | 88 |
563 bool PrintSystemWin::GetPrinterCapsAndDefaults( | 89 bool PrintBackendWin::GetPrinterCapsAndDefaults( |
564 const std::string& printer_name, | 90 const std::string& printer_name, |
565 PrinterCapsAndDefaults* printer_info) { | 91 PrinterCapsAndDefaults* printer_info) { |
566 if (!InitXPSModule()) { | 92 if (!printing::InitXPSModule()) { |
567 // TODO(sanjeevr): Handle legacy proxy case (with no prntvpt.dll) | 93 // TODO(sanjeevr): Handle legacy proxy case (with no prntvpt.dll) |
568 return false; | 94 return false; |
569 } | 95 } |
570 if (!IsValidPrinter(printer_name)) { | 96 if (!IsValidPrinter(printer_name)) { |
571 return false; | 97 return false; |
572 } | 98 } |
573 DCHECK(printer_info); | 99 DCHECK(printer_info); |
574 HPTPROVIDER provider = NULL; | 100 HPTPROVIDER provider = NULL; |
575 std::wstring printer_name_wide = UTF8ToWide(printer_name); | 101 std::wstring printer_name_wide = UTF8ToWide(printer_name); |
576 HRESULT hr = PTOpenProvider(printer_name_wide.c_str(), 1, &provider); | 102 HRESULT hr = PTOpenProvider(printer_name_wide.c_str(), 1, &provider); |
(...skipping 18 matching lines...) Expand all Loading... |
595 } | 121 } |
596 // TODO(sanjeevr): Add ScopedPrinterHandle | 122 // TODO(sanjeevr): Add ScopedPrinterHandle |
597 HANDLE printer_handle = NULL; | 123 HANDLE printer_handle = NULL; |
598 OpenPrinter(const_cast<LPTSTR>(printer_name_wide.c_str()), &printer_handle, | 124 OpenPrinter(const_cast<LPTSTR>(printer_name_wide.c_str()), &printer_handle, |
599 NULL); | 125 NULL); |
600 DCHECK(printer_handle); | 126 DCHECK(printer_handle); |
601 if (printer_handle) { | 127 if (printer_handle) { |
602 DWORD devmode_size = DocumentProperties( | 128 DWORD devmode_size = DocumentProperties( |
603 NULL, printer_handle, const_cast<LPTSTR>(printer_name_wide.c_str()), | 129 NULL, printer_handle, const_cast<LPTSTR>(printer_name_wide.c_str()), |
604 NULL, NULL, 0); | 130 NULL, NULL, 0); |
605 DCHECK(0 != devmode_size); | 131 DCHECK_NE(0U, devmode_size); |
606 scoped_ptr<BYTE> devmode_out_buffer(new BYTE[devmode_size]); | 132 scoped_ptr<BYTE> devmode_out_buffer(new BYTE[devmode_size]); |
607 DEVMODE* devmode_out = | 133 DEVMODE* devmode_out = |
608 reinterpret_cast<DEVMODE*>(devmode_out_buffer.get()); | 134 reinterpret_cast<DEVMODE*>(devmode_out_buffer.get()); |
609 DocumentProperties( | 135 DocumentProperties( |
610 NULL, printer_handle, const_cast<LPTSTR>(printer_name_wide.c_str()), | 136 NULL, printer_handle, const_cast<LPTSTR>(printer_name_wide.c_str()), |
611 devmode_out, NULL, DM_OUT_BUFFER); | 137 devmode_out, NULL, DM_OUT_BUFFER); |
612 ScopedComPtr<IStream> printer_defaults_stream; | 138 ScopedComPtr<IStream> printer_defaults_stream; |
613 hr = CreateStreamOnHGlobal(NULL, TRUE, | 139 hr = CreateStreamOnHGlobal(NULL, TRUE, |
614 printer_defaults_stream.Receive()); | 140 printer_defaults_stream.Receive()); |
615 DCHECK(SUCCEEDED(hr)); | 141 DCHECK(SUCCEEDED(hr)); |
616 if (printer_defaults_stream) { | 142 if (printer_defaults_stream) { |
617 hr = PTConvertDevModeToPrintTicket(provider, devmode_size, | 143 hr = PTConvertDevModeToPrintTicket(provider, devmode_size, |
618 devmode_out, kPTJobScope, | 144 devmode_out, kPTJobScope, |
619 printer_defaults_stream); | 145 printer_defaults_stream); |
620 DCHECK(SUCCEEDED(hr)); | 146 DCHECK(SUCCEEDED(hr)); |
621 if (SUCCEEDED(hr)) { | 147 if (SUCCEEDED(hr)) { |
622 hr = StreamOnHGlobalToString(printer_defaults_stream.get(), | 148 hr = StreamOnHGlobalToString(printer_defaults_stream.get(), |
623 &printer_info->printer_defaults); | 149 &printer_info->printer_defaults); |
624 DCHECK(SUCCEEDED(hr)); | 150 DCHECK(SUCCEEDED(hr)); |
625 printer_info->defaults_mime_type = "text/xml"; | 151 printer_info->defaults_mime_type = "text/xml"; |
626 } | 152 } |
627 } | 153 } |
628 ClosePrinter(printer_handle); | 154 ClosePrinter(printer_handle); |
629 } | 155 } |
630 PTCloseProvider(provider); | 156 PTCloseProvider(provider); |
631 } | 157 } |
632 return true; | 158 return true; |
633 } | 159 } |
634 | 160 |
635 bool PrintSystemWin::ValidatePrintTicket( | 161 bool PrintBackendWin::IsValidPrinter(const std::string& printer_name) { |
636 const std::string& printer_name, | |
637 const std::string& print_ticket_data) { | |
638 if (!InitXPSModule()) { | |
639 // TODO(sanjeevr): Handle legacy proxy case (with no prntvpt.dll) | |
640 return false; | |
641 } | |
642 bool ret = false; | |
643 HPTPROVIDER provider = NULL; | |
644 PTOpenProvider(UTF8ToWide(printer_name.c_str()).c_str(), 1, &provider); | |
645 if (provider) { | |
646 ScopedComPtr<IStream> print_ticket_stream; | |
647 CreateStreamOnHGlobal(NULL, TRUE, print_ticket_stream.Receive()); | |
648 ULONG bytes_written = 0; | |
649 print_ticket_stream->Write(print_ticket_data.c_str(), | |
650 print_ticket_data.length(), | |
651 &bytes_written); | |
652 DCHECK(bytes_written == print_ticket_data.length()); | |
653 LARGE_INTEGER pos = {0}; | |
654 ULARGE_INTEGER new_pos = {0}; | |
655 print_ticket_stream->Seek(pos, STREAM_SEEK_SET, &new_pos); | |
656 ScopedBstr error; | |
657 ScopedComPtr<IStream> result_ticket_stream; | |
658 CreateStreamOnHGlobal(NULL, TRUE, result_ticket_stream.Receive()); | |
659 ret = SUCCEEDED(PTMergeAndValidatePrintTicket(provider, | |
660 print_ticket_stream.get(), | |
661 NULL, | |
662 kPTJobScope, | |
663 result_ticket_stream.get(), | |
664 error.Receive())); | |
665 PTCloseProvider(provider); | |
666 } | |
667 return ret; | |
668 } | |
669 | |
670 bool PrintSystemWin::GetJobDetails(const std::string& printer_name, | |
671 PlatformJobId job_id, | |
672 PrintJobDetails *job_details) { | |
673 DCHECK(job_details); | |
674 HANDLE printer_handle = NULL; | |
675 std::wstring printer_name_wide = UTF8ToWide(printer_name); | |
676 OpenPrinter(const_cast<LPTSTR>(printer_name_wide.c_str()), &printer_handle, | |
677 NULL); | |
678 DCHECK(printer_handle); | |
679 bool ret = false; | |
680 if (printer_handle) { | |
681 DWORD bytes_needed = 0; | |
682 GetJob(printer_handle, job_id, 1, NULL, 0, &bytes_needed); | |
683 DWORD last_error = GetLastError(); | |
684 if (ERROR_INVALID_PARAMETER != last_error) { | |
685 // ERROR_INVALID_PARAMETER normally means that the job id is not valid. | |
686 DCHECK(last_error == ERROR_INSUFFICIENT_BUFFER); | |
687 scoped_ptr<BYTE> job_info_buffer(new BYTE[bytes_needed]); | |
688 if (GetJob(printer_handle, job_id, 1, job_info_buffer.get(), bytes_needed, | |
689 &bytes_needed)) { | |
690 JOB_INFO_1 *job_info = | |
691 reinterpret_cast<JOB_INFO_1 *>(job_info_buffer.get()); | |
692 if (job_info->pStatus) { | |
693 WideToUTF8(job_info->pStatus, wcslen(job_info->pStatus), | |
694 &job_details->status_message); | |
695 } | |
696 job_details->platform_status_flags = job_info->Status; | |
697 if ((job_info->Status & JOB_STATUS_COMPLETE) || | |
698 (job_info->Status & JOB_STATUS_PRINTED)) { | |
699 job_details->status = PRINT_JOB_STATUS_COMPLETED; | |
700 } else if (job_info->Status & JOB_STATUS_ERROR) { | |
701 job_details->status = PRINT_JOB_STATUS_ERROR; | |
702 } else { | |
703 job_details->status = PRINT_JOB_STATUS_IN_PROGRESS; | |
704 } | |
705 job_details->total_pages = job_info->TotalPages; | |
706 job_details->pages_printed = job_info->PagesPrinted; | |
707 ret = true; | |
708 } | |
709 } | |
710 ClosePrinter(printer_handle); | |
711 } | |
712 return ret; | |
713 } | |
714 | |
715 bool PrintSystemWin::IsValidPrinter(const std::string& printer_name) { | |
716 std::wstring printer_name_wide = UTF8ToWide(printer_name); | 162 std::wstring printer_name_wide = UTF8ToWide(printer_name); |
717 HANDLE printer_handle = NULL; | 163 HANDLE printer_handle = NULL; |
718 OpenPrinter(const_cast<LPTSTR>(printer_name_wide.c_str()), &printer_handle, | 164 OpenPrinter(const_cast<LPTSTR>(printer_name_wide.c_str()), &printer_handle, |
719 NULL); | 165 NULL); |
720 bool ret = false; | 166 bool ret = false; |
721 if (printer_handle) { | 167 if (printer_handle) { |
722 ret = true; | 168 ret = true; |
723 ClosePrinter(printer_handle); | 169 ClosePrinter(printer_handle); |
724 } | 170 } |
725 return ret; | 171 return ret; |
726 } | 172 } |
727 | 173 |
728 PrintSystem::PrintServerWatcher* | 174 scoped_refptr<PrintBackend> PrintBackend::CreateInstance( |
729 PrintSystemWin::CreatePrintServerWatcher() { | 175 const DictionaryValue* print_backend_settings) { |
730 return new PrintServerWatcherWin(); | 176 return new PrintBackendWin; |
731 } | 177 } |
732 | 178 |
733 PrintSystem::PrinterWatcher* PrintSystemWin::CreatePrinterWatcher( | 179 } // namespace printing |
734 const std::string& printer_name) { | |
735 DCHECK(!printer_name.empty()); | |
736 return new PrinterWatcherWin(printer_name); | |
737 } | |
738 | |
739 PrintSystem::JobSpooler* | |
740 PrintSystemWin::CreateJobSpooler() { | |
741 return new JobSpoolerWin(); | |
742 } | |
743 | |
744 std::string PrintSystem::GenerateProxyId() { | |
745 GUID proxy_id = {0}; | |
746 HRESULT hr = UuidCreate(&proxy_id); | |
747 DCHECK(SUCCEEDED(hr)); | |
748 wchar_t* proxy_id_as_string = NULL; | |
749 UuidToString(&proxy_id, reinterpret_cast<RPC_WSTR *>(&proxy_id_as_string)); | |
750 DCHECK(proxy_id_as_string); | |
751 std::string ret; | |
752 WideToUTF8(proxy_id_as_string, wcslen(proxy_id_as_string), &ret); | |
753 RpcStringFree(reinterpret_cast<RPC_WSTR *>(&proxy_id_as_string)); | |
754 return ret; | |
755 } | |
756 | |
757 scoped_refptr<PrintSystem> PrintSystem::CreateInstance( | |
758 const DictionaryValue* print_system_settings) { | |
759 return new PrintSystemWin; | |
760 } | |
761 | |
762 } // namespace cloud_print | |
763 | |
OLD | NEW |