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/strings/utf_string_conversions.h"
12 #include "base/thread_task_runner_handle.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()
40 ~PrintSystemWatcherWin() override
{ Stop(); }
44 virtual ~Delegate() {}
45 virtual void OnPrinterAdded() = 0;
46 virtual void OnPrinterDeleted() = 0;
47 virtual void OnPrinterChanged() = 0;
48 virtual void OnJobChanged() = 0;
51 bool Start(const std::string
& printer_name
, Delegate
* delegate
) {
52 scoped_refptr
<printing::PrintBackend
> print_backend(
53 printing::PrintBackend::CreateInstance(NULL
));
54 printer_info_
= print_backend
->GetPrinterDriverInfo(printer_name
);
55 crash_keys::ScopedPrinterInfo
crash_key(printer_info_
);
58 // An empty printer name means watch the current server, we need to pass
59 // NULL to OpenPrinter.
60 LPTSTR printer_name_to_use
= NULL
;
61 std::wstring printer_name_wide
;
62 if (!printer_name
.empty()) {
63 printer_name_wide
= base::UTF8ToWide(printer_name
);
64 printer_name_to_use
= const_cast<LPTSTR
>(printer_name_wide
.c_str());
67 if (printer_
.OpenPrinter(printer_name_to_use
)) {
68 printer_change_
.Set(FindFirstPrinterChangeNotification(
69 printer_
.Get(), PRINTER_CHANGE_PRINTER
|PRINTER_CHANGE_JOB
, 0, NULL
));
70 if (printer_change_
.IsValid()) {
71 ret
= watcher_
.StartWatching(printer_change_
.Get(), this);
81 watcher_
.StopWatching();
83 printer_change_
.Close();
87 // base::ObjectWatcher::Delegate method
88 void OnObjectSignaled(HANDLE object
) override
{
89 crash_keys::ScopedPrinterInfo
crash_key(printer_info_
);
91 FindNextPrinterChangeNotification(object
, &change
, NULL
, NULL
);
93 if (change
!= ((PRINTER_CHANGE_PRINTER
|PRINTER_CHANGE_JOB
) &
94 (~PRINTER_CHANGE_FAILED_CONNECTION_PRINTER
))) {
95 // For printer connections, we get spurious change notifications with
96 // all flags set except PRINTER_CHANGE_FAILED_CONNECTION_PRINTER.
98 if (change
& PRINTER_CHANGE_ADD_PRINTER
) {
99 delegate_
->OnPrinterAdded();
100 } else if (change
& PRINTER_CHANGE_DELETE_PRINTER
) {
101 delegate_
->OnPrinterDeleted();
102 } else if (change
& PRINTER_CHANGE_SET_PRINTER
) {
103 delegate_
->OnPrinterChanged();
105 if (change
& PRINTER_CHANGE_JOB
) {
106 delegate_
->OnJobChanged();
109 watcher_
.StartWatching(printer_change_
.Get(), this);
112 bool GetCurrentPrinterInfo(printing::PrinterBasicInfo
* printer_info
) {
113 DCHECK(printer_info
);
114 return InitBasicPrinterInfo(printer_
.Get(), printer_info
);
118 base::win::ObjectWatcher watcher_
;
119 printing::ScopedPrinterHandle printer_
; // The printer being watched
120 // Returned by FindFirstPrinterChangeNotifier.
121 printing::ScopedPrinterChangeHandle printer_change_
;
122 Delegate
* delegate_
; // Delegate to notify
123 std::string printer_info_
; // For crash reporting.
126 class PrintServerWatcherWin
127 : public PrintSystem::PrintServerWatcher
,
128 public PrintSystemWatcherWin::Delegate
{
130 PrintServerWatcherWin() : delegate_(NULL
) {}
132 // PrintSystem::PrintServerWatcher implementation.
134 PrintSystem::PrintServerWatcher::Delegate
* delegate
) override
{
135 delegate_
= delegate
;
136 return watcher_
.Start(std::string(), this);
139 bool StopWatching() override
{
140 bool ret
= watcher_
.Stop();
145 // PrintSystemWatcherWin::Delegate implementation.
146 void OnPrinterAdded() override
{
147 delegate_
->OnPrinterAdded();
149 void OnPrinterDeleted() override
{}
150 void OnPrinterChanged() override
{}
151 void OnJobChanged() override
{}
154 ~PrintServerWatcherWin() override
{}
157 PrintSystem::PrintServerWatcher::Delegate
* delegate_
;
158 PrintSystemWatcherWin watcher_
;
160 DISALLOW_COPY_AND_ASSIGN(PrintServerWatcherWin
);
163 class PrinterWatcherWin
164 : public PrintSystem::PrinterWatcher
,
165 public PrintSystemWatcherWin::Delegate
{
167 explicit PrinterWatcherWin(const std::string
& printer_name
)
168 : printer_name_(printer_name
),
172 // PrintSystem::PrinterWatcher implementation.
173 bool StartWatching(PrintSystem::PrinterWatcher::Delegate
* delegate
) override
{
174 delegate_
= delegate
;
175 return watcher_
.Start(printer_name_
, this);
178 bool StopWatching() override
{
179 bool ret
= watcher_
.Stop();
184 bool GetCurrentPrinterInfo(
185 printing::PrinterBasicInfo
* printer_info
) override
{
186 return watcher_
.GetCurrentPrinterInfo(printer_info
);
189 // PrintSystemWatcherWin::Delegate implementation.
190 void OnPrinterAdded() override
{
193 void OnPrinterDeleted() override
{
194 delegate_
->OnPrinterDeleted();
196 void OnPrinterChanged() override
{
197 delegate_
->OnPrinterChanged();
199 void OnJobChanged() override
{
200 delegate_
->OnJobChanged();
204 ~PrinterWatcherWin() override
{}
207 std::string printer_name_
;
208 PrintSystem::PrinterWatcher::Delegate
* delegate_
;
209 PrintSystemWatcherWin watcher_
;
211 DISALLOW_COPY_AND_ASSIGN(PrinterWatcherWin
);
214 class JobSpoolerWin
: public PrintSystem::JobSpooler
{
216 JobSpoolerWin() : core_(new Core
) {}
218 // PrintSystem::JobSpooler implementation.
219 bool Spool(const std::string
& print_ticket
,
220 const std::string
& print_ticket_mime_type
,
221 const base::FilePath
& print_data_file_path
,
222 const std::string
& print_data_mime_type
,
223 const std::string
& printer_name
,
224 const std::string
& job_title
,
225 const std::vector
<std::string
>& tags
,
226 JobSpooler::Delegate
* delegate
) override
{
227 // TODO(gene): add tags handling.
228 scoped_refptr
<printing::PrintBackend
> print_backend(
229 printing::PrintBackend::CreateInstance(NULL
));
230 crash_keys::ScopedPrinterInfo
crash_key(
231 print_backend
->GetPrinterDriverInfo(printer_name
));
232 return core_
->Spool(print_ticket
, print_ticket_mime_type
,
233 print_data_file_path
, print_data_mime_type
,
234 printer_name
, job_title
, delegate
);
238 ~JobSpoolerWin() override
{}
241 // We use a Core class because we want a separate RefCountedThreadSafe
242 // implementation for ServiceUtilityProcessHost::Client.
243 class Core
: public ServiceUtilityProcessHost::Client
,
244 public base::win::ObjectWatcher::Delegate
{
246 Core() : job_id_(-1), delegate_(NULL
), saved_dc_(0) {}
248 bool Spool(const std::string
& print_ticket
,
249 const std::string
& print_ticket_mime_type
,
250 const base::FilePath
& print_data_file_path
,
251 const std::string
& print_data_mime_type
,
252 const std::string
& printer_name
,
253 const std::string
& job_title
,
254 JobSpooler::Delegate
* delegate
) {
256 // We are already in the process of printing.
260 base::string16 printer_wide
= base::UTF8ToWide(printer_name
);
261 // We only support PDF and XPS documents for now.
262 if (print_data_mime_type
== kContentTypePDF
) {
263 scoped_ptr
<DEVMODE
, base::FreeDeleter
> dev_mode
;
264 if (print_ticket_mime_type
== kContentTypeJSON
) {
265 dev_mode
= CjtToDevMode(printer_wide
, print_ticket
);
267 DCHECK(print_ticket_mime_type
== kContentTypeXML
);
268 dev_mode
= printing::XpsTicketToDevMode(printer_wide
, print_ticket
);
276 HDC dc
= CreateDC(L
"WINSPOOL", printer_wide
.c_str(), NULL
,
283 di
.cbSize
= sizeof(DOCINFO
);
284 base::string16 doc_name
= base::UTF8ToUTF16(job_title
);
285 DCHECK(printing::SimplifyDocumentTitle(doc_name
) == doc_name
);
286 di
.lpszDocName
= doc_name
.c_str();
287 job_id_
= StartDoc(dc
, &di
);
292 saved_dc_
= SaveDC(printer_dc_
.Get());
293 print_data_file_path_
= print_data_file_path
;
294 delegate_
= delegate
;
296 } else if (print_data_mime_type
== kContentTypeXPS
) {
297 DCHECK(print_ticket_mime_type
== kContentTypeXML
);
298 bool ret
= PrintXPSDocument(printer_name
,
300 print_data_file_path
,
303 delegate_
= delegate
;
312 void PreparePageDCForPrinting(HDC
, float scale_factor
) {
313 SetGraphicsMode(printer_dc_
.Get(), GM_ADVANCED
);
314 // Setup the matrix to translate and scale to the right place. Take in
315 // account the scale factor.
316 // Note that the printing output is relative to printable area of
317 // the page. That is 0,0 is offset by PHYSICALOFFSETX/Y from the page.
318 int offset_x
= ::GetDeviceCaps(printer_dc_
.Get(), PHYSICALOFFSETX
);
319 int offset_y
= ::GetDeviceCaps(printer_dc_
.Get(), PHYSICALOFFSETY
);
321 xform
.eDx
= static_cast<float>(-offset_x
);
322 xform
.eDy
= static_cast<float>(-offset_y
);
323 xform
.eM11
= xform
.eM22
= 1.0f
/ scale_factor
;
324 SetWorldTransform(printer_dc_
.Get(), &xform
);
327 // ServiceUtilityProcessHost::Client implementation.
328 void OnRenderPDFPagesToMetafilePageDone(
330 const printing::MetafilePlayer
& emf
) override
{
331 PreparePageDCForPrinting(printer_dc_
.Get(), scale_factor
);
332 ::StartPage(printer_dc_
.Get());
333 emf
.SafePlayback(printer_dc_
.Get());
334 ::EndPage(printer_dc_
.Get());
337 // ServiceUtilityProcessHost::Client implementation.
338 void OnRenderPDFPagesToMetafileDone(bool success
) override
{
339 PrintJobDone(success
);
342 void OnChildDied() override
{ PrintJobDone(false); }
344 // base::win::ObjectWatcher::Delegate implementation.
345 void OnObjectSignaled(HANDLE object
) override
{
346 DCHECK(xps_print_job_
.get());
347 DCHECK(object
== job_progress_event_
.Get());
348 ResetEvent(job_progress_event_
.Get());
351 XPS_JOB_STATUS job_status
= {0};
352 xps_print_job_
->GetJobStatus(&job_status
);
353 if ((job_status
.completion
== XPS_JOB_CANCELLED
) ||
354 (job_status
.completion
== XPS_JOB_FAILED
)) {
355 delegate_
->OnJobSpoolFailed();
356 } else if (job_status
.jobId
||
357 (job_status
.completion
== XPS_JOB_COMPLETED
)) {
358 // Note: In the case of the XPS document being printed to the
359 // Microsoft XPS Document Writer, it seems to skip spooling the job
360 // and goes to the completed state without ever assigning a job id.
361 delegate_
->OnJobSpoolSucceeded(job_status
.jobId
);
363 job_progress_watcher_
.StopWatching();
364 job_progress_watcher_
.StartWatching(job_progress_event_
.Get(), this);
371 // Helper class to allow PrintXPSDocument() to have multiple exits.
372 class PrintJobCanceler
{
374 explicit PrintJobCanceler(
375 base::win::ScopedComPtr
<IXpsPrintJob
>* job_ptr
)
376 : job_ptr_(job_ptr
) {
378 ~PrintJobCanceler() {
379 if (job_ptr_
&& job_ptr_
->get()) {
380 (*job_ptr_
)->Cancel();
385 void reset() { job_ptr_
= NULL
; }
388 base::win::ScopedComPtr
<IXpsPrintJob
>* job_ptr_
;
390 DISALLOW_COPY_AND_ASSIGN(PrintJobCanceler
);
393 void PrintJobDone(bool success
) {
394 // If there is no delegate, then there is nothing pending to process.
397 RestoreDC(printer_dc_
.Get(), saved_dc_
);
398 EndDoc(printer_dc_
.Get());
400 delegate_
->OnJobSpoolSucceeded(job_id_
);
402 delegate_
->OnJobSpoolFailed();
407 void RenderPDFPages() {
408 int printer_dpi
= ::GetDeviceCaps(printer_dc_
.Get(), LOGPIXELSX
);
409 int dc_width
= GetDeviceCaps(printer_dc_
.Get(), PHYSICALWIDTH
);
410 int dc_height
= GetDeviceCaps(printer_dc_
.Get(), PHYSICALHEIGHT
);
411 gfx::Rect
render_area(0, 0, dc_width
, dc_height
);
412 g_service_process
->io_thread()->task_runner()->PostTask(
414 base::Bind(&JobSpoolerWin::Core::RenderPDFPagesInSandbox
, this,
415 print_data_file_path_
, render_area
, printer_dpi
,
416 base::ThreadTaskRunnerHandle::Get()));
419 // Called on the service process IO thread.
420 void RenderPDFPagesInSandbox(
421 const base::FilePath
& pdf_path
,
422 const gfx::Rect
& render_area
,
424 const scoped_refptr
<base::SingleThreadTaskRunner
>& client_task_runner
) {
425 DCHECK(g_service_process
->io_thread()
427 ->BelongsToCurrentThread());
428 scoped_ptr
<ServiceUtilityProcessHost
> utility_host(
429 new ServiceUtilityProcessHost(this, client_task_runner
.get()));
430 // TODO(gene): For now we disabling autorotation for CloudPrinting.
431 // Landscape/Portrait setting is passed in the print ticket and
432 // server is generating portrait PDF always.
433 // We should enable autorotation once server will be able to generate
434 // PDF that matches paper size and orientation.
435 if (utility_host
->StartRenderPDFPagesToMetafile(
437 printing::PdfRenderSettings(render_area
, render_dpi
, false))) {
438 // The object will self-destruct when the child process dies.
439 utility_host
.release();
441 client_task_runner
->PostTask(
442 FROM_HERE
, base::Bind(&Core::PrintJobDone
, this, false));
446 bool PrintXPSDocument(const std::string
& printer_name
,
447 const std::string
& job_title
,
448 const base::FilePath
& print_data_file_path
,
449 const std::string
& print_ticket
) {
450 if (!printing::XPSPrintModule::Init())
453 job_progress_event_
.Set(CreateEvent(NULL
, TRUE
, FALSE
, NULL
));
454 if (!job_progress_event_
.Get())
457 PrintJobCanceler
job_canceler(&xps_print_job_
);
458 base::win::ScopedComPtr
<IXpsPrintJobStream
> doc_stream
;
459 base::win::ScopedComPtr
<IXpsPrintJobStream
> print_ticket_stream
;
460 if (FAILED(printing::XPSPrintModule::StartXpsPrintJob(
461 base::UTF8ToWide(printer_name
).c_str(),
462 base::UTF8ToWide(job_title
).c_str(),
463 NULL
, job_progress_event_
.Get(), NULL
, NULL
, NULL
,
464 xps_print_job_
.Receive(), doc_stream
.Receive(),
465 print_ticket_stream
.Receive())))
468 ULONG print_bytes_written
= 0;
469 if (FAILED(print_ticket_stream
->Write(print_ticket
.c_str(),
470 print_ticket
.length(),
471 &print_bytes_written
)))
473 DCHECK_EQ(print_ticket
.length(), print_bytes_written
);
474 if (FAILED(print_ticket_stream
->Close()))
477 std::string document_data
;
478 base::ReadFileToString(print_data_file_path
, &document_data
);
479 ULONG doc_bytes_written
= 0;
480 if (FAILED(doc_stream
->Write(document_data
.c_str(),
481 document_data
.length(),
482 &doc_bytes_written
)))
484 DCHECK_EQ(document_data
.length(), doc_bytes_written
);
485 if (FAILED(doc_stream
->Close()))
488 job_progress_watcher_
.StartWatching(job_progress_event_
.Get(), this);
489 job_canceler
.reset();
493 PlatformJobId job_id_
;
494 PrintSystem::JobSpooler::Delegate
* delegate_
;
496 base::win::ScopedCreateDC printer_dc_
;
497 base::FilePath print_data_file_path_
;
498 base::win::ScopedHandle job_progress_event_
;
499 base::win::ObjectWatcher job_progress_watcher_
;
500 base::win::ScopedComPtr
<IXpsPrintJob
> xps_print_job_
;
502 DISALLOW_COPY_AND_ASSIGN(Core
);
504 scoped_refptr
<Core
> core_
;
506 DISALLOW_COPY_AND_ASSIGN(JobSpoolerWin
);
509 // A helper class to handle the response from the utility process to the
510 // request to fetch printer capabilities and defaults.
511 class PrinterCapsHandler
: public ServiceUtilityProcessHost::Client
{
514 const std::string
& printer_name
,
515 const PrintSystem::PrinterCapsAndDefaultsCallback
& callback
)
516 : printer_name_(printer_name
), callback_(callback
) {
519 // ServiceUtilityProcessHost::Client implementation.
520 void OnChildDied() override
{
521 OnGetPrinterCapsAndDefaults(false, printer_name_
,
522 printing::PrinterCapsAndDefaults());
525 void OnGetPrinterCapsAndDefaults(
527 const std::string
& printer_name
,
528 const printing::PrinterCapsAndDefaults
& caps_and_defaults
) override
{
529 callback_
.Run(succeeded
, printer_name
, caps_and_defaults
);
534 void OnGetPrinterSemanticCapsAndDefaults(
536 const std::string
& printer_name
,
537 const printing::PrinterSemanticCapsAndDefaults
& semantic_info
) override
{
538 printing::PrinterCapsAndDefaults printer_info
;
540 printer_info
.caps_mime_type
= kContentTypeJSON
;
541 scoped_ptr
<base::DictionaryValue
> description(
542 PrinterSemanticCapsAndDefaultsToCdd(semantic_info
));
544 base::JSONWriter::WriteWithOptions(
545 *description
, base::JSONWriter::OPTIONS_PRETTY_PRINT
,
546 &printer_info
.printer_capabilities
);
549 callback_
.Run(succeeded
, printer_name
, printer_info
);
554 void StartGetPrinterCapsAndDefaults() {
555 g_service_process
->io_thread()->task_runner()->PostTask(
557 base::Bind(&PrinterCapsHandler::GetPrinterCapsAndDefaultsImpl
, this,
558 base::ThreadTaskRunnerHandle::Get()));
561 void StartGetPrinterSemanticCapsAndDefaults() {
562 g_service_process
->io_thread()->task_runner()->PostTask(
564 base::Bind(&PrinterCapsHandler::GetPrinterSemanticCapsAndDefaultsImpl
,
565 this, base::ThreadTaskRunnerHandle::Get()));
569 ~PrinterCapsHandler() override
{}
571 void GetPrinterCapsAndDefaultsImpl(
572 const scoped_refptr
<base::SingleThreadTaskRunner
>& client_task_runner
) {
573 DCHECK(g_service_process
->io_thread()
575 ->BelongsToCurrentThread());
576 scoped_ptr
<ServiceUtilityProcessHost
> utility_host(
577 new ServiceUtilityProcessHost(this, client_task_runner
.get()));
578 if (utility_host
->StartGetPrinterCapsAndDefaults(printer_name_
)) {
579 // The object will self-destruct when the child process dies.
580 utility_host
.release();
582 client_task_runner
->PostTask(
583 FROM_HERE
, base::Bind(&PrinterCapsHandler::OnChildDied
, this));
587 void GetPrinterSemanticCapsAndDefaultsImpl(
588 const scoped_refptr
<base::SingleThreadTaskRunner
>& client_task_runner
) {
589 DCHECK(g_service_process
->io_thread()
591 ->BelongsToCurrentThread());
592 scoped_ptr
<ServiceUtilityProcessHost
> utility_host(
593 new ServiceUtilityProcessHost(this, client_task_runner
.get()));
594 if (utility_host
->StartGetPrinterSemanticCapsAndDefaults(printer_name_
)) {
595 // The object will self-destruct when the child process dies.
596 utility_host
.release();
598 client_task_runner
->PostTask(
599 FROM_HERE
, base::Bind(&PrinterCapsHandler::OnChildDied
, this));
603 std::string printer_name_
;
604 PrintSystem::PrinterCapsAndDefaultsCallback callback_
;
607 class PrintSystemWin
: public PrintSystem
{
611 // PrintSystem implementation.
612 PrintSystemResult
Init() override
;
613 PrintSystem::PrintSystemResult
EnumeratePrinters(
614 printing::PrinterList
* printer_list
) override
;
615 void GetPrinterCapsAndDefaults(
616 const std::string
& printer_name
,
617 const PrinterCapsAndDefaultsCallback
& callback
) override
;
618 bool IsValidPrinter(const std::string
& printer_name
) override
;
619 bool ValidatePrintTicket(
620 const std::string
& printer_name
,
621 const std::string
& print_ticket_data
,
622 const std::string
& print_ticket_data_mime_type
) override
;
623 bool GetJobDetails(const std::string
& printer_name
,
624 PlatformJobId job_id
,
625 PrintJobDetails
* job_details
) override
;
626 PrintSystem::PrintServerWatcher
* CreatePrintServerWatcher() override
;
627 PrintSystem::PrinterWatcher
* CreatePrinterWatcher(
628 const std::string
& printer_name
) override
;
629 PrintSystem::JobSpooler
* CreateJobSpooler() override
;
630 bool UseCddAndCjt() override
;
631 std::string
GetSupportedMimeTypes() override
;
634 ~PrintSystemWin() override
{}
636 std::string
GetPrinterDriverInfo(const std::string
& printer_name
) const;
638 scoped_refptr
<printing::PrintBackend
> print_backend_
;
640 DISALLOW_COPY_AND_ASSIGN(PrintSystemWin
);
643 PrintSystemWin::PrintSystemWin() : use_cdd_(true) {
644 print_backend_
= printing::PrintBackend::CreateInstance(NULL
);
647 PrintSystem::PrintSystemResult
PrintSystemWin::Init() {
648 use_cdd_
= !base::CommandLine::ForCurrentProcess()->HasSwitch(
649 switches::kEnableCloudPrintXps
);
652 use_cdd_
= !printing::XPSModule::Init();
655 HPTPROVIDER provider
= NULL
;
656 HRESULT hr
= printing::XPSModule::OpenProvider(L
"", 1, &provider
);
658 printing::XPSModule::CloseProvider(provider
);
659 // Use cdd if error is different from expected.
660 use_cdd_
= (hr
!= HRESULT_FROM_WIN32(ERROR_INVALID_PRINTER_NAME
));
663 return PrintSystemResult(true, std::string());
666 PrintSystem::PrintSystemResult
PrintSystemWin::EnumeratePrinters(
667 printing::PrinterList
* printer_list
) {
668 bool ret
= print_backend_
->EnumeratePrinters(printer_list
);
669 return PrintSystemResult(ret
, std::string());
672 void PrintSystemWin::GetPrinterCapsAndDefaults(
673 const std::string
& printer_name
,
674 const PrinterCapsAndDefaultsCallback
& callback
) {
675 // Launch as child process to retrieve the capabilities and defaults because
676 // this involves invoking a printer driver DLL and crashes have been known to
678 PrinterCapsHandler
* handler
= new PrinterCapsHandler(printer_name
, callback
);
681 handler
->StartGetPrinterSemanticCapsAndDefaults();
683 handler
->StartGetPrinterCapsAndDefaults();
686 bool PrintSystemWin::IsValidPrinter(const std::string
& printer_name
) {
687 return print_backend_
->IsValidPrinter(printer_name
);
690 bool PrintSystemWin::ValidatePrintTicket(
691 const std::string
& printer_name
,
692 const std::string
& print_ticket_data
,
693 const std::string
& print_ticket_data_mime_type
) {
694 crash_keys::ScopedPrinterInfo
crash_key(GetPrinterDriverInfo(printer_name
));
697 return print_ticket_data_mime_type
== kContentTypeJSON
&&
698 IsValidCjt(print_ticket_data
);
700 DCHECK(print_ticket_data_mime_type
== kContentTypeXML
);
702 printing::ScopedXPSInitializer xps_initializer
;
703 if (!xps_initializer
.initialized()) {
704 // TODO(sanjeevr): Handle legacy proxy case (with no prntvpt.dll)
708 HPTPROVIDER provider
= NULL
;
709 printing::XPSModule::OpenProvider(base::UTF8ToWide(printer_name
), 1,
712 base::win::ScopedComPtr
<IStream
> print_ticket_stream
;
713 CreateStreamOnHGlobal(NULL
, TRUE
, print_ticket_stream
.Receive());
714 ULONG bytes_written
= 0;
715 print_ticket_stream
->Write(print_ticket_data
.c_str(),
716 print_ticket_data
.length(),
718 DCHECK(bytes_written
== print_ticket_data
.length());
719 LARGE_INTEGER pos
= {};
720 ULARGE_INTEGER new_pos
= {};
721 print_ticket_stream
->Seek(pos
, STREAM_SEEK_SET
, &new_pos
);
722 base::win::ScopedBstr error
;
723 base::win::ScopedComPtr
<IStream
> result_ticket_stream
;
724 CreateStreamOnHGlobal(NULL
, TRUE
, result_ticket_stream
.Receive());
725 ret
= SUCCEEDED(printing::XPSModule::MergeAndValidatePrintTicket(
727 print_ticket_stream
.get(),
730 result_ticket_stream
.get(),
732 printing::XPSModule::CloseProvider(provider
);
737 bool PrintSystemWin::GetJobDetails(const std::string
& printer_name
,
738 PlatformJobId job_id
,
739 PrintJobDetails
*job_details
) {
740 crash_keys::ScopedPrinterInfo
crash_key(
741 print_backend_
->GetPrinterDriverInfo(printer_name
));
743 printing::ScopedPrinterHandle printer_handle
;
744 std::wstring printer_name_wide
= base::UTF8ToWide(printer_name
);
745 printer_handle
.OpenPrinter(printer_name_wide
.c_str());
746 DCHECK(printer_handle
.IsValid());
748 if (printer_handle
.IsValid()) {
749 DWORD bytes_needed
= 0;
750 GetJob(printer_handle
.Get(), job_id
, 1, NULL
, 0, &bytes_needed
);
751 DWORD last_error
= GetLastError();
752 if (ERROR_INVALID_PARAMETER
!= last_error
) {
753 // ERROR_INVALID_PARAMETER normally means that the job id is not valid.
754 DCHECK(last_error
== ERROR_INSUFFICIENT_BUFFER
);
755 scoped_ptr
<BYTE
[]> job_info_buffer(new BYTE
[bytes_needed
]);
756 if (GetJob(printer_handle
.Get(), job_id
, 1, job_info_buffer
.get(),
757 bytes_needed
, &bytes_needed
)) {
758 JOB_INFO_1
*job_info
=
759 reinterpret_cast<JOB_INFO_1
*>(job_info_buffer
.get());
760 if (job_info
->pStatus
) {
761 base::WideToUTF8(job_info
->pStatus
, wcslen(job_info
->pStatus
),
762 &job_details
->status_message
);
764 job_details
->platform_status_flags
= job_info
->Status
;
765 if ((job_info
->Status
& JOB_STATUS_COMPLETE
) ||
766 (job_info
->Status
& JOB_STATUS_PRINTED
)) {
767 job_details
->status
= PRINT_JOB_STATUS_COMPLETED
;
768 } else if (job_info
->Status
& JOB_STATUS_ERROR
) {
769 job_details
->status
= PRINT_JOB_STATUS_ERROR
;
771 job_details
->status
= PRINT_JOB_STATUS_IN_PROGRESS
;
773 job_details
->total_pages
= job_info
->TotalPages
;
774 job_details
->pages_printed
= job_info
->PagesPrinted
;
782 PrintSystem::PrintServerWatcher
*
783 PrintSystemWin::CreatePrintServerWatcher() {
784 return new PrintServerWatcherWin();
787 PrintSystem::PrinterWatcher
* PrintSystemWin::CreatePrinterWatcher(
788 const std::string
& printer_name
) {
789 DCHECK(!printer_name
.empty());
790 return new PrinterWatcherWin(printer_name
);
793 PrintSystem::JobSpooler
* PrintSystemWin::CreateJobSpooler() {
794 return new JobSpoolerWin();
797 bool PrintSystemWin::UseCddAndCjt() {
801 std::string
PrintSystemWin::GetSupportedMimeTypes() {
804 result
= kContentTypeXPS
;
807 result
+= kContentTypePDF
;
811 std::string
PrintSystemWin::GetPrinterDriverInfo(
812 const std::string
& printer_name
) const {
813 return print_backend_
->GetPrinterDriverInfo(printer_name
);
818 scoped_refptr
<PrintSystem
> PrintSystem::CreateInstance(
819 const base::DictionaryValue
* print_system_settings
) {
820 return new PrintSystemWin
;
823 } // namespace cloud_print