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 "chrome/service/cloud_print/print_system.h"
7 #include "base/command_line.h"
8 #include "base/files/file_util.h"
9 #include "base/json/json_writer.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/profiler/scoped_tracker.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "base/win/object_watcher.h"
14 #include "base/win/scoped_bstr.h"
15 #include "base/win/scoped_comptr.h"
16 #include "base/win/scoped_hdc.h"
17 #include "chrome/common/chrome_switches.h"
18 #include "chrome/common/cloud_print/cloud_print_cdd_conversion.h"
19 #include "chrome/common/cloud_print/cloud_print_constants.h"
20 #include "chrome/common/crash_keys.h"
21 #include "chrome/service/cloud_print/cdd_conversion_win.h"
22 #include "chrome/service/service_process.h"
23 #include "chrome/service/service_utility_process_host.h"
24 #include "printing/backend/win_helper.h"
25 #include "printing/emf_win.h"
26 #include "printing/page_range.h"
27 #include "printing/pdf_render_settings.h"
28 #include "printing/printing_utils.h"
29 #include "ui/gfx/geometry/rect.h"
31 namespace cloud_print
{
35 class PrintSystemWatcherWin
: public base::win::ObjectWatcher::Delegate
{
37 PrintSystemWatcherWin()
41 ~PrintSystemWatcherWin() {
47 virtual ~Delegate() {}
48 virtual void OnPrinterAdded() = 0;
49 virtual void OnPrinterDeleted() = 0;
50 virtual void OnPrinterChanged() = 0;
51 virtual void OnJobChanged() = 0;
54 bool Start(const std::string
& printer_name
, Delegate
* delegate
) {
55 scoped_refptr
<printing::PrintBackend
> print_backend(
56 printing::PrintBackend::CreateInstance(NULL
));
57 printer_info_
= print_backend
->GetPrinterDriverInfo(printer_name
);
58 crash_keys::ScopedPrinterInfo
crash_key(printer_info_
);
61 // An empty printer name means watch the current server, we need to pass
62 // NULL to OpenPrinter.
63 LPTSTR printer_name_to_use
= NULL
;
64 std::wstring printer_name_wide
;
65 if (!printer_name
.empty()) {
66 printer_name_wide
= base::UTF8ToWide(printer_name
);
67 printer_name_to_use
= const_cast<LPTSTR
>(printer_name_wide
.c_str());
70 if (printer_
.OpenPrinter(printer_name_to_use
)) {
71 printer_change_
.Set(FindFirstPrinterChangeNotification(
72 printer_
.Get(), PRINTER_CHANGE_PRINTER
|PRINTER_CHANGE_JOB
, 0, NULL
));
73 if (printer_change_
.IsValid()) {
74 ret
= watcher_
.StartWatching(printer_change_
.Get(), this);
84 watcher_
.StopWatching();
86 printer_change_
.Close();
90 // base::ObjectWatcher::Delegate method
91 virtual void OnObjectSignaled(HANDLE object
) {
92 // TODO(vadimt): Remove ScopedTracker below once crbug.com/418183 is fixed.
93 tracked_objects::ScopedTracker
tracking_profile(
94 FROM_HERE_WITH_EXPLICIT_FUNCTION(
95 "PrintSystemWatcherWin_OnObjectSignaled"));
97 crash_keys::ScopedPrinterInfo
crash_key(printer_info_
);
99 FindNextPrinterChangeNotification(object
, &change
, NULL
, NULL
);
101 if (change
!= ((PRINTER_CHANGE_PRINTER
|PRINTER_CHANGE_JOB
) &
102 (~PRINTER_CHANGE_FAILED_CONNECTION_PRINTER
))) {
103 // For printer connections, we get spurious change notifications with
104 // all flags set except PRINTER_CHANGE_FAILED_CONNECTION_PRINTER.
106 if (change
& PRINTER_CHANGE_ADD_PRINTER
) {
107 delegate_
->OnPrinterAdded();
108 } else if (change
& PRINTER_CHANGE_DELETE_PRINTER
) {
109 delegate_
->OnPrinterDeleted();
110 } else if (change
& PRINTER_CHANGE_SET_PRINTER
) {
111 delegate_
->OnPrinterChanged();
113 if (change
& PRINTER_CHANGE_JOB
) {
114 delegate_
->OnJobChanged();
117 watcher_
.StartWatching(printer_change_
.Get(), this);
120 bool GetCurrentPrinterInfo(printing::PrinterBasicInfo
* printer_info
) {
121 DCHECK(printer_info
);
122 return InitBasicPrinterInfo(printer_
.Get(), printer_info
);
126 base::win::ObjectWatcher watcher_
;
127 printing::ScopedPrinterHandle printer_
; // The printer being watched
128 // Returned by FindFirstPrinterChangeNotifier.
129 printing::ScopedPrinterChangeHandle printer_change_
;
130 Delegate
* delegate_
; // Delegate to notify
131 bool did_signal_
; // DoneWaiting was called
132 std::string printer_info_
; // For crash reporting.
135 class PrintServerWatcherWin
136 : public PrintSystem::PrintServerWatcher
,
137 public PrintSystemWatcherWin::Delegate
{
139 PrintServerWatcherWin() : delegate_(NULL
) {}
141 // PrintSystem::PrintServerWatcher implementation.
142 virtual bool StartWatching(
143 PrintSystem::PrintServerWatcher::Delegate
* delegate
) override
{
144 delegate_
= delegate
;
145 return watcher_
.Start(std::string(), this);
148 virtual bool StopWatching() override
{
149 bool ret
= watcher_
.Stop();
154 // PrintSystemWatcherWin::Delegate implementation.
155 virtual void OnPrinterAdded() override
{
156 delegate_
->OnPrinterAdded();
158 virtual void OnPrinterDeleted() override
{}
159 virtual void OnPrinterChanged() override
{}
160 virtual void OnJobChanged() override
{}
163 virtual ~PrintServerWatcherWin() {}
166 PrintSystem::PrintServerWatcher::Delegate
* delegate_
;
167 PrintSystemWatcherWin watcher_
;
169 DISALLOW_COPY_AND_ASSIGN(PrintServerWatcherWin
);
172 class PrinterWatcherWin
173 : public PrintSystem::PrinterWatcher
,
174 public PrintSystemWatcherWin::Delegate
{
176 explicit PrinterWatcherWin(const std::string
& printer_name
)
177 : printer_name_(printer_name
),
181 // PrintSystem::PrinterWatcher implementation.
182 virtual bool StartWatching(
183 PrintSystem::PrinterWatcher::Delegate
* delegate
) override
{
184 delegate_
= delegate
;
185 return watcher_
.Start(printer_name_
, this);
188 virtual bool StopWatching() override
{
189 bool ret
= watcher_
.Stop();
194 virtual bool GetCurrentPrinterInfo(
195 printing::PrinterBasicInfo
* printer_info
) override
{
196 return watcher_
.GetCurrentPrinterInfo(printer_info
);
199 // PrintSystemWatcherWin::Delegate implementation.
200 virtual void OnPrinterAdded() override
{
203 virtual void OnPrinterDeleted() override
{
204 delegate_
->OnPrinterDeleted();
206 virtual void OnPrinterChanged() override
{
207 delegate_
->OnPrinterChanged();
209 virtual void OnJobChanged() override
{
210 delegate_
->OnJobChanged();
214 virtual ~PrinterWatcherWin() {}
217 std::string printer_name_
;
218 PrintSystem::PrinterWatcher::Delegate
* delegate_
;
219 PrintSystemWatcherWin watcher_
;
221 DISALLOW_COPY_AND_ASSIGN(PrinterWatcherWin
);
224 class JobSpoolerWin
: public PrintSystem::JobSpooler
{
226 JobSpoolerWin() : core_(new Core
) {}
228 // PrintSystem::JobSpooler implementation.
229 virtual bool Spool(const std::string
& print_ticket
,
230 const std::string
& print_ticket_mime_type
,
231 const base::FilePath
& print_data_file_path
,
232 const std::string
& print_data_mime_type
,
233 const std::string
& printer_name
,
234 const std::string
& job_title
,
235 const std::vector
<std::string
>& tags
,
236 JobSpooler::Delegate
* delegate
) override
{
237 // TODO(gene): add tags handling.
238 scoped_refptr
<printing::PrintBackend
> print_backend(
239 printing::PrintBackend::CreateInstance(NULL
));
240 crash_keys::ScopedPrinterInfo
crash_key(
241 print_backend
->GetPrinterDriverInfo(printer_name
));
242 return core_
->Spool(print_ticket
, print_ticket_mime_type
,
243 print_data_file_path
, print_data_mime_type
,
244 printer_name
, job_title
, delegate
);
248 virtual ~JobSpoolerWin() {}
251 // We use a Core class because we want a separate RefCountedThreadSafe
252 // implementation for ServiceUtilityProcessHost::Client.
253 class Core
: public ServiceUtilityProcessHost::Client
,
254 public base::win::ObjectWatcher::Delegate
{
256 Core() : job_id_(-1), delegate_(NULL
), saved_dc_(0) {}
260 bool Spool(const std::string
& print_ticket
,
261 const std::string
& print_ticket_mime_type
,
262 const base::FilePath
& print_data_file_path
,
263 const std::string
& print_data_mime_type
,
264 const std::string
& printer_name
,
265 const std::string
& job_title
,
266 JobSpooler::Delegate
* delegate
) {
268 // We are already in the process of printing.
272 base::string16 printer_wide
= base::UTF8ToWide(printer_name
);
273 // We only support PDF and XPS documents for now.
274 if (print_data_mime_type
== kContentTypePDF
) {
275 scoped_ptr
<DEVMODE
, base::FreeDeleter
> dev_mode
;
276 if (print_ticket_mime_type
== kContentTypeJSON
) {
277 dev_mode
= CjtToDevMode(printer_wide
, print_ticket
);
279 DCHECK(print_ticket_mime_type
== kContentTypeXML
);
280 dev_mode
= printing::XpsTicketToDevMode(printer_wide
, print_ticket
);
288 HDC dc
= CreateDC(L
"WINSPOOL", printer_wide
.c_str(), NULL
,
295 di
.cbSize
= sizeof(DOCINFO
);
296 base::string16 doc_name
= base::UTF8ToUTF16(job_title
);
297 DCHECK(printing::SimplifyDocumentTitle(doc_name
) == doc_name
);
298 di
.lpszDocName
= doc_name
.c_str();
299 job_id_
= StartDoc(dc
, &di
);
304 saved_dc_
= SaveDC(printer_dc_
.Get());
305 print_data_file_path_
= print_data_file_path
;
306 delegate_
= delegate
;
308 } else if (print_data_mime_type
== kContentTypeXPS
) {
309 DCHECK(print_ticket_mime_type
== kContentTypeXML
);
310 bool ret
= PrintXPSDocument(printer_name
,
312 print_data_file_path
,
315 delegate_
= delegate
;
324 void PreparePageDCForPrinting(HDC
, float scale_factor
) {
325 SetGraphicsMode(printer_dc_
.Get(), GM_ADVANCED
);
326 // Setup the matrix to translate and scale to the right place. Take in
327 // account the scale factor.
328 // Note that the printing output is relative to printable area of
329 // the page. That is 0,0 is offset by PHYSICALOFFSETX/Y from the page.
330 int offset_x
= ::GetDeviceCaps(printer_dc_
.Get(), PHYSICALOFFSETX
);
331 int offset_y
= ::GetDeviceCaps(printer_dc_
.Get(), PHYSICALOFFSETY
);
333 xform
.eDx
= static_cast<float>(-offset_x
);
334 xform
.eDy
= static_cast<float>(-offset_y
);
335 xform
.eM11
= xform
.eM22
= 1.0f
/ scale_factor
;
336 SetWorldTransform(printer_dc_
.Get(), &xform
);
339 // ServiceUtilityProcessHost::Client implementation.
340 virtual void OnRenderPDFPagesToMetafilePageDone(
342 const printing::MetafilePlayer
& emf
) override
{
343 PreparePageDCForPrinting(printer_dc_
.Get(), scale_factor
);
344 ::StartPage(printer_dc_
.Get());
345 emf
.SafePlayback(printer_dc_
.Get());
346 ::EndPage(printer_dc_
.Get());
349 // ServiceUtilityProcessHost::Client implementation.
350 virtual void OnRenderPDFPagesToMetafileDone(bool success
) override
{
351 PrintJobDone(success
);
354 virtual void OnChildDied() override
{ PrintJobDone(false); }
356 // base::win::ObjectWatcher::Delegate implementation.
357 virtual void OnObjectSignaled(HANDLE object
) override
{
358 // TODO(vadimt): Remove ScopedTracker below once crbug.com/418183 is
360 tracked_objects::ScopedTracker
tracking_profile(
361 FROM_HERE_WITH_EXPLICIT_FUNCTION("Core_OnObjectSignaled"));
363 DCHECK(xps_print_job_
.get());
364 DCHECK(object
== job_progress_event_
.Get());
365 ResetEvent(job_progress_event_
.Get());
368 XPS_JOB_STATUS job_status
= {0};
369 xps_print_job_
->GetJobStatus(&job_status
);
370 if ((job_status
.completion
== XPS_JOB_CANCELLED
) ||
371 (job_status
.completion
== XPS_JOB_FAILED
)) {
372 delegate_
->OnJobSpoolFailed();
373 } else if (job_status
.jobId
||
374 (job_status
.completion
== XPS_JOB_COMPLETED
)) {
375 // Note: In the case of the XPS document being printed to the
376 // Microsoft XPS Document Writer, it seems to skip spooling the job
377 // and goes to the completed state without ever assigning a job id.
378 delegate_
->OnJobSpoolSucceeded(job_status
.jobId
);
380 job_progress_watcher_
.StopWatching();
381 job_progress_watcher_
.StartWatching(job_progress_event_
.Get(), this);
386 // Helper class to allow PrintXPSDocument() to have multiple exits.
387 class PrintJobCanceler
{
389 explicit PrintJobCanceler(
390 base::win::ScopedComPtr
<IXpsPrintJob
>* job_ptr
)
391 : job_ptr_(job_ptr
) {
393 ~PrintJobCanceler() {
394 if (job_ptr_
&& job_ptr_
->get()) {
395 (*job_ptr_
)->Cancel();
400 void reset() { job_ptr_
= NULL
; }
403 base::win::ScopedComPtr
<IXpsPrintJob
>* job_ptr_
;
405 DISALLOW_COPY_AND_ASSIGN(PrintJobCanceler
);
408 void PrintJobDone(bool success
) {
409 // If there is no delegate, then there is nothing pending to process.
412 RestoreDC(printer_dc_
.Get(), saved_dc_
);
413 EndDoc(printer_dc_
.Get());
415 delegate_
->OnJobSpoolSucceeded(job_id_
);
417 delegate_
->OnJobSpoolFailed();
422 void RenderPDFPages() {
423 int printer_dpi
= ::GetDeviceCaps(printer_dc_
.Get(), LOGPIXELSX
);
424 int dc_width
= GetDeviceCaps(printer_dc_
.Get(), PHYSICALWIDTH
);
425 int dc_height
= GetDeviceCaps(printer_dc_
.Get(), PHYSICALHEIGHT
);
426 gfx::Rect
render_area(0, 0, dc_width
, dc_height
);
427 g_service_process
->io_thread()->message_loop_proxy()->PostTask(
429 base::Bind(&JobSpoolerWin::Core::RenderPDFPagesInSandbox
,
431 print_data_file_path_
,
434 base::MessageLoopProxy::current()));
437 // Called on the service process IO thread.
438 void RenderPDFPagesInSandbox(const base::FilePath
& pdf_path
,
439 const gfx::Rect
& render_area
,
441 const scoped_refptr
<base::MessageLoopProxy
>&
442 client_message_loop_proxy
) {
443 DCHECK(g_service_process
->io_thread()->message_loop_proxy()->
444 BelongsToCurrentThread());
445 scoped_ptr
<ServiceUtilityProcessHost
> utility_host(
446 new ServiceUtilityProcessHost(this, client_message_loop_proxy
.get()));
447 // TODO(gene): For now we disabling autorotation for CloudPrinting.
448 // Landscape/Portrait setting is passed in the print ticket and
449 // server is generating portrait PDF always.
450 // We should enable autorotation once server will be able to generate
451 // PDF that matches paper size and orientation.
452 if (utility_host
->StartRenderPDFPagesToMetafile(
454 printing::PdfRenderSettings(render_area
, render_dpi
, false))) {
455 // The object will self-destruct when the child process dies.
456 utility_host
.release();
458 client_message_loop_proxy
->PostTask(
459 FROM_HERE
, base::Bind(&Core::PrintJobDone
, this, false));
463 bool PrintXPSDocument(const std::string
& printer_name
,
464 const std::string
& job_title
,
465 const base::FilePath
& print_data_file_path
,
466 const std::string
& print_ticket
) {
467 if (!printing::XPSPrintModule::Init())
470 job_progress_event_
.Set(CreateEvent(NULL
, TRUE
, FALSE
, NULL
));
471 if (!job_progress_event_
.Get())
474 PrintJobCanceler
job_canceler(&xps_print_job_
);
475 base::win::ScopedComPtr
<IXpsPrintJobStream
> doc_stream
;
476 base::win::ScopedComPtr
<IXpsPrintJobStream
> print_ticket_stream
;
477 if (FAILED(printing::XPSPrintModule::StartXpsPrintJob(
478 base::UTF8ToWide(printer_name
).c_str(),
479 base::UTF8ToWide(job_title
).c_str(),
480 NULL
, job_progress_event_
.Get(), NULL
, NULL
, NULL
,
481 xps_print_job_
.Receive(), doc_stream
.Receive(),
482 print_ticket_stream
.Receive())))
485 ULONG print_bytes_written
= 0;
486 if (FAILED(print_ticket_stream
->Write(print_ticket
.c_str(),
487 print_ticket
.length(),
488 &print_bytes_written
)))
490 DCHECK_EQ(print_ticket
.length(), print_bytes_written
);
491 if (FAILED(print_ticket_stream
->Close()))
494 std::string document_data
;
495 base::ReadFileToString(print_data_file_path
, &document_data
);
496 ULONG doc_bytes_written
= 0;
497 if (FAILED(doc_stream
->Write(document_data
.c_str(),
498 document_data
.length(),
499 &doc_bytes_written
)))
501 DCHECK_EQ(document_data
.length(), doc_bytes_written
);
502 if (FAILED(doc_stream
->Close()))
505 job_progress_watcher_
.StartWatching(job_progress_event_
.Get(), this);
506 job_canceler
.reset();
510 PlatformJobId job_id_
;
511 PrintSystem::JobSpooler::Delegate
* delegate_
;
513 base::win::ScopedCreateDC printer_dc_
;
514 base::FilePath print_data_file_path_
;
515 base::win::ScopedHandle job_progress_event_
;
516 base::win::ObjectWatcher job_progress_watcher_
;
517 base::win::ScopedComPtr
<IXpsPrintJob
> xps_print_job_
;
519 DISALLOW_COPY_AND_ASSIGN(Core
);
521 scoped_refptr
<Core
> core_
;
523 DISALLOW_COPY_AND_ASSIGN(JobSpoolerWin
);
526 // A helper class to handle the response from the utility process to the
527 // request to fetch printer capabilities and defaults.
528 class PrinterCapsHandler
: public ServiceUtilityProcessHost::Client
{
531 const std::string
& printer_name
,
532 const PrintSystem::PrinterCapsAndDefaultsCallback
& callback
)
533 : printer_name_(printer_name
), callback_(callback
) {
536 // ServiceUtilityProcessHost::Client implementation.
537 virtual void OnChildDied() override
{
538 OnGetPrinterCapsAndDefaults(false, printer_name_
,
539 printing::PrinterCapsAndDefaults());
542 virtual void OnGetPrinterCapsAndDefaults(
544 const std::string
& printer_name
,
545 const printing::PrinterCapsAndDefaults
& caps_and_defaults
) override
{
546 callback_
.Run(succeeded
, printer_name
, caps_and_defaults
);
551 virtual void OnGetPrinterSemanticCapsAndDefaults(
553 const std::string
& printer_name
,
554 const printing::PrinterSemanticCapsAndDefaults
& semantic_info
) override
{
555 printing::PrinterCapsAndDefaults printer_info
;
557 printer_info
.caps_mime_type
= kContentTypeJSON
;
558 scoped_ptr
<base::DictionaryValue
> description(
559 PrinterSemanticCapsAndDefaultsToCdd(semantic_info
));
561 base::JSONWriter::WriteWithOptions(
562 description
.get(), base::JSONWriter::OPTIONS_PRETTY_PRINT
,
563 &printer_info
.printer_capabilities
);
566 callback_
.Run(succeeded
, printer_name
, printer_info
);
571 void StartGetPrinterCapsAndDefaults() {
572 g_service_process
->io_thread()->message_loop_proxy()->PostTask(
574 base::Bind(&PrinterCapsHandler::GetPrinterCapsAndDefaultsImpl
, this,
575 base::MessageLoopProxy::current()));
578 void StartGetPrinterSemanticCapsAndDefaults() {
579 g_service_process
->io_thread()->message_loop_proxy()->PostTask(
581 base::Bind(&PrinterCapsHandler::GetPrinterSemanticCapsAndDefaultsImpl
,
582 this, base::MessageLoopProxy::current()));
586 void GetPrinterCapsAndDefaultsImpl(
587 const scoped_refptr
<base::MessageLoopProxy
>&
588 client_message_loop_proxy
) {
589 DCHECK(g_service_process
->io_thread()->message_loop_proxy()->
590 BelongsToCurrentThread());
591 scoped_ptr
<ServiceUtilityProcessHost
> utility_host(
592 new ServiceUtilityProcessHost(this, client_message_loop_proxy
.get()));
593 if (utility_host
->StartGetPrinterCapsAndDefaults(printer_name_
)) {
594 // The object will self-destruct when the child process dies.
595 utility_host
.release();
597 client_message_loop_proxy
->PostTask(
599 base::Bind(&PrinterCapsHandler::OnChildDied
, this));
603 void GetPrinterSemanticCapsAndDefaultsImpl(
604 const scoped_refptr
<base::MessageLoopProxy
>&
605 client_message_loop_proxy
) {
606 DCHECK(g_service_process
->io_thread()->message_loop_proxy()->
607 BelongsToCurrentThread());
608 scoped_ptr
<ServiceUtilityProcessHost
> utility_host(
609 new ServiceUtilityProcessHost(this, client_message_loop_proxy
.get()));
610 if (utility_host
->StartGetPrinterSemanticCapsAndDefaults(printer_name_
)) {
611 // The object will self-destruct when the child process dies.
612 utility_host
.release();
614 client_message_loop_proxy
->PostTask(
616 base::Bind(&PrinterCapsHandler::OnChildDied
, this));
620 std::string printer_name_
;
621 PrintSystem::PrinterCapsAndDefaultsCallback callback_
;
624 class PrintSystemWin
: public PrintSystem
{
628 // PrintSystem implementation.
629 virtual PrintSystemResult
Init() override
;
630 virtual PrintSystem::PrintSystemResult
EnumeratePrinters(
631 printing::PrinterList
* printer_list
) override
;
632 virtual void GetPrinterCapsAndDefaults(
633 const std::string
& printer_name
,
634 const PrinterCapsAndDefaultsCallback
& callback
) override
;
635 virtual bool IsValidPrinter(const std::string
& printer_name
) override
;
636 virtual bool ValidatePrintTicket(
637 const std::string
& printer_name
,
638 const std::string
& print_ticket_data
,
639 const std::string
& print_ticket_data_mime_type
) override
;
640 virtual bool GetJobDetails(const std::string
& printer_name
,
641 PlatformJobId job_id
,
642 PrintJobDetails
*job_details
) override
;
643 virtual PrintSystem::PrintServerWatcher
* CreatePrintServerWatcher() override
;
644 virtual PrintSystem::PrinterWatcher
* CreatePrinterWatcher(
645 const std::string
& printer_name
) override
;
646 virtual PrintSystem::JobSpooler
* CreateJobSpooler() override
;
647 virtual bool UseCddAndCjt() override
;
648 virtual std::string
GetSupportedMimeTypes() override
;
651 std::string
PrintSystemWin::GetPrinterDriverInfo(
652 const std::string
& printer_name
) const;
654 scoped_refptr
<printing::PrintBackend
> print_backend_
;
656 DISALLOW_COPY_AND_ASSIGN(PrintSystemWin
);
659 PrintSystemWin::PrintSystemWin() : use_cdd_(true) {
660 print_backend_
= printing::PrintBackend::CreateInstance(NULL
);
663 PrintSystem::PrintSystemResult
PrintSystemWin::Init() {
664 use_cdd_
= !base::CommandLine::ForCurrentProcess()->HasSwitch(
665 switches::kEnableCloudPrintXps
);
668 use_cdd_
= !printing::XPSModule::Init();
671 HPTPROVIDER provider
= NULL
;
672 HRESULT hr
= printing::XPSModule::OpenProvider(L
"", 1, &provider
);
674 printing::XPSModule::CloseProvider(provider
);
675 // Use cdd if error is different from expected.
676 use_cdd_
= (hr
!= HRESULT_FROM_WIN32(ERROR_INVALID_PRINTER_NAME
));
679 return PrintSystemResult(true, std::string());
682 PrintSystem::PrintSystemResult
PrintSystemWin::EnumeratePrinters(
683 printing::PrinterList
* printer_list
) {
684 bool ret
= print_backend_
->EnumeratePrinters(printer_list
);
685 return PrintSystemResult(ret
, std::string());
688 void PrintSystemWin::GetPrinterCapsAndDefaults(
689 const std::string
& printer_name
,
690 const PrinterCapsAndDefaultsCallback
& callback
) {
691 // Launch as child process to retrieve the capabilities and defaults because
692 // this involves invoking a printer driver DLL and crashes have been known to
694 PrinterCapsHandler
* handler
= new PrinterCapsHandler(printer_name
, callback
);
697 handler
->StartGetPrinterSemanticCapsAndDefaults();
699 handler
->StartGetPrinterCapsAndDefaults();
702 bool PrintSystemWin::IsValidPrinter(const std::string
& printer_name
) {
703 return print_backend_
->IsValidPrinter(printer_name
);
706 bool PrintSystemWin::ValidatePrintTicket(
707 const std::string
& printer_name
,
708 const std::string
& print_ticket_data
,
709 const std::string
& print_ticket_data_mime_type
) {
710 crash_keys::ScopedPrinterInfo
crash_key(GetPrinterDriverInfo(printer_name
));
713 return print_ticket_data_mime_type
== kContentTypeJSON
&&
714 IsValidCjt(print_ticket_data
);
716 DCHECK(print_ticket_data_mime_type
== kContentTypeXML
);
718 printing::ScopedXPSInitializer xps_initializer
;
719 if (!xps_initializer
.initialized()) {
720 // TODO(sanjeevr): Handle legacy proxy case (with no prntvpt.dll)
724 HPTPROVIDER provider
= NULL
;
725 printing::XPSModule::OpenProvider(base::UTF8ToWide(printer_name
), 1,
728 base::win::ScopedComPtr
<IStream
> print_ticket_stream
;
729 CreateStreamOnHGlobal(NULL
, TRUE
, print_ticket_stream
.Receive());
730 ULONG bytes_written
= 0;
731 print_ticket_stream
->Write(print_ticket_data
.c_str(),
732 print_ticket_data
.length(),
734 DCHECK(bytes_written
== print_ticket_data
.length());
735 LARGE_INTEGER pos
= {0};
736 ULARGE_INTEGER new_pos
= {0};
737 print_ticket_stream
->Seek(pos
, STREAM_SEEK_SET
, &new_pos
);
738 base::win::ScopedBstr error
;
739 base::win::ScopedComPtr
<IStream
> result_ticket_stream
;
740 CreateStreamOnHGlobal(NULL
, TRUE
, result_ticket_stream
.Receive());
741 ret
= SUCCEEDED(printing::XPSModule::MergeAndValidatePrintTicket(
743 print_ticket_stream
.get(),
746 result_ticket_stream
.get(),
748 printing::XPSModule::CloseProvider(provider
);
753 bool PrintSystemWin::GetJobDetails(const std::string
& printer_name
,
754 PlatformJobId job_id
,
755 PrintJobDetails
*job_details
) {
756 crash_keys::ScopedPrinterInfo
crash_key(
757 print_backend_
->GetPrinterDriverInfo(printer_name
));
759 printing::ScopedPrinterHandle printer_handle
;
760 std::wstring printer_name_wide
= base::UTF8ToWide(printer_name
);
761 printer_handle
.OpenPrinter(printer_name_wide
.c_str());
762 DCHECK(printer_handle
.IsValid());
764 if (printer_handle
.IsValid()) {
765 DWORD bytes_needed
= 0;
766 GetJob(printer_handle
.Get(), job_id
, 1, NULL
, 0, &bytes_needed
);
767 DWORD last_error
= GetLastError();
768 if (ERROR_INVALID_PARAMETER
!= last_error
) {
769 // ERROR_INVALID_PARAMETER normally means that the job id is not valid.
770 DCHECK(last_error
== ERROR_INSUFFICIENT_BUFFER
);
771 scoped_ptr
<BYTE
[]> job_info_buffer(new BYTE
[bytes_needed
]);
772 if (GetJob(printer_handle
.Get(), job_id
, 1, job_info_buffer
.get(),
773 bytes_needed
, &bytes_needed
)) {
774 JOB_INFO_1
*job_info
=
775 reinterpret_cast<JOB_INFO_1
*>(job_info_buffer
.get());
776 if (job_info
->pStatus
) {
777 base::WideToUTF8(job_info
->pStatus
, wcslen(job_info
->pStatus
),
778 &job_details
->status_message
);
780 job_details
->platform_status_flags
= job_info
->Status
;
781 if ((job_info
->Status
& JOB_STATUS_COMPLETE
) ||
782 (job_info
->Status
& JOB_STATUS_PRINTED
)) {
783 job_details
->status
= PRINT_JOB_STATUS_COMPLETED
;
784 } else if (job_info
->Status
& JOB_STATUS_ERROR
) {
785 job_details
->status
= PRINT_JOB_STATUS_ERROR
;
787 job_details
->status
= PRINT_JOB_STATUS_IN_PROGRESS
;
789 job_details
->total_pages
= job_info
->TotalPages
;
790 job_details
->pages_printed
= job_info
->PagesPrinted
;
798 PrintSystem::PrintServerWatcher
*
799 PrintSystemWin::CreatePrintServerWatcher() {
800 return new PrintServerWatcherWin();
803 PrintSystem::PrinterWatcher
* PrintSystemWin::CreatePrinterWatcher(
804 const std::string
& printer_name
) {
805 DCHECK(!printer_name
.empty());
806 return new PrinterWatcherWin(printer_name
);
809 PrintSystem::JobSpooler
* PrintSystemWin::CreateJobSpooler() {
810 return new JobSpoolerWin();
813 bool PrintSystemWin::UseCddAndCjt() {
817 std::string
PrintSystemWin::GetSupportedMimeTypes() {
820 result
= kContentTypeXPS
;
823 result
+= kContentTypePDF
;
827 std::string
PrintSystemWin::GetPrinterDriverInfo(
828 const std::string
& printer_name
) const {
829 return print_backend_
->GetPrinterDriverInfo(printer_name
);
834 scoped_refptr
<PrintSystem
> PrintSystem::CreateInstance(
835 const base::DictionaryValue
* print_system_settings
) {
836 return new PrintSystemWin
;
839 } // namespace cloud_print