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()
41 ~PrintSystemWatcherWin() override
{ Stop(); }
45 virtual ~Delegate() {}
46 virtual void OnPrinterAdded() = 0;
47 virtual void OnPrinterDeleted() = 0;
48 virtual void OnPrinterChanged() = 0;
49 virtual void OnJobChanged() = 0;
52 bool Start(const std::string
& printer_name
, Delegate
* delegate
) {
53 scoped_refptr
<printing::PrintBackend
> print_backend(
54 printing::PrintBackend::CreateInstance(NULL
));
55 printer_info_
= print_backend
->GetPrinterDriverInfo(printer_name
);
56 crash_keys::ScopedPrinterInfo
crash_key(printer_info_
);
59 // An empty printer name means watch the current server, we need to pass
60 // NULL to OpenPrinter.
61 LPTSTR printer_name_to_use
= NULL
;
62 std::wstring printer_name_wide
;
63 if (!printer_name
.empty()) {
64 printer_name_wide
= base::UTF8ToWide(printer_name
);
65 printer_name_to_use
= const_cast<LPTSTR
>(printer_name_wide
.c_str());
68 if (printer_
.OpenPrinter(printer_name_to_use
)) {
69 printer_change_
.Set(FindFirstPrinterChangeNotification(
70 printer_
.Get(), PRINTER_CHANGE_PRINTER
|PRINTER_CHANGE_JOB
, 0, NULL
));
71 if (printer_change_
.IsValid()) {
72 ret
= watcher_
.StartWatching(printer_change_
.Get(), this);
82 watcher_
.StopWatching();
84 printer_change_
.Close();
88 // base::ObjectWatcher::Delegate method
89 void OnObjectSignaled(HANDLE object
) override
{
90 crash_keys::ScopedPrinterInfo
crash_key(printer_info_
);
92 FindNextPrinterChangeNotification(object
, &change
, NULL
, NULL
);
94 if (change
!= ((PRINTER_CHANGE_PRINTER
|PRINTER_CHANGE_JOB
) &
95 (~PRINTER_CHANGE_FAILED_CONNECTION_PRINTER
))) {
96 // For printer connections, we get spurious change notifications with
97 // all flags set except PRINTER_CHANGE_FAILED_CONNECTION_PRINTER.
99 if (change
& PRINTER_CHANGE_ADD_PRINTER
) {
100 delegate_
->OnPrinterAdded();
101 } else if (change
& PRINTER_CHANGE_DELETE_PRINTER
) {
102 delegate_
->OnPrinterDeleted();
103 } else if (change
& PRINTER_CHANGE_SET_PRINTER
) {
104 delegate_
->OnPrinterChanged();
106 if (change
& PRINTER_CHANGE_JOB
) {
107 delegate_
->OnJobChanged();
110 watcher_
.StartWatching(printer_change_
.Get(), this);
113 bool GetCurrentPrinterInfo(printing::PrinterBasicInfo
* printer_info
) {
114 DCHECK(printer_info
);
115 return InitBasicPrinterInfo(printer_
.Get(), printer_info
);
119 base::win::ObjectWatcher watcher_
;
120 printing::ScopedPrinterHandle printer_
; // The printer being watched
121 // Returned by FindFirstPrinterChangeNotifier.
122 printing::ScopedPrinterChangeHandle printer_change_
;
123 Delegate
* delegate_
; // Delegate to notify
124 bool did_signal_
; // DoneWaiting was called
125 std::string printer_info_
; // For crash reporting.
128 class PrintServerWatcherWin
129 : public PrintSystem::PrintServerWatcher
,
130 public PrintSystemWatcherWin::Delegate
{
132 PrintServerWatcherWin() : delegate_(NULL
) {}
134 // PrintSystem::PrintServerWatcher implementation.
136 PrintSystem::PrintServerWatcher::Delegate
* delegate
) override
{
137 delegate_
= delegate
;
138 return watcher_
.Start(std::string(), this);
141 bool StopWatching() override
{
142 bool ret
= watcher_
.Stop();
147 // PrintSystemWatcherWin::Delegate implementation.
148 void OnPrinterAdded() override
{
149 delegate_
->OnPrinterAdded();
151 void OnPrinterDeleted() override
{}
152 void OnPrinterChanged() override
{}
153 void OnJobChanged() override
{}
156 ~PrintServerWatcherWin() override
{}
159 PrintSystem::PrintServerWatcher::Delegate
* delegate_
;
160 PrintSystemWatcherWin watcher_
;
162 DISALLOW_COPY_AND_ASSIGN(PrintServerWatcherWin
);
165 class PrinterWatcherWin
166 : public PrintSystem::PrinterWatcher
,
167 public PrintSystemWatcherWin::Delegate
{
169 explicit PrinterWatcherWin(const std::string
& printer_name
)
170 : printer_name_(printer_name
),
174 // PrintSystem::PrinterWatcher implementation.
175 bool StartWatching(PrintSystem::PrinterWatcher::Delegate
* delegate
) override
{
176 delegate_
= delegate
;
177 return watcher_
.Start(printer_name_
, this);
180 bool StopWatching() override
{
181 bool ret
= watcher_
.Stop();
186 bool GetCurrentPrinterInfo(
187 printing::PrinterBasicInfo
* printer_info
) override
{
188 return watcher_
.GetCurrentPrinterInfo(printer_info
);
191 // PrintSystemWatcherWin::Delegate implementation.
192 void OnPrinterAdded() override
{
195 void OnPrinterDeleted() override
{
196 delegate_
->OnPrinterDeleted();
198 void OnPrinterChanged() override
{
199 delegate_
->OnPrinterChanged();
201 void OnJobChanged() override
{
202 delegate_
->OnJobChanged();
206 ~PrinterWatcherWin() override
{}
209 std::string printer_name_
;
210 PrintSystem::PrinterWatcher::Delegate
* delegate_
;
211 PrintSystemWatcherWin watcher_
;
213 DISALLOW_COPY_AND_ASSIGN(PrinterWatcherWin
);
216 class JobSpoolerWin
: public PrintSystem::JobSpooler
{
218 JobSpoolerWin() : core_(new Core
) {}
220 // PrintSystem::JobSpooler implementation.
221 bool Spool(const std::string
& print_ticket
,
222 const std::string
& print_ticket_mime_type
,
223 const base::FilePath
& print_data_file_path
,
224 const std::string
& print_data_mime_type
,
225 const std::string
& printer_name
,
226 const std::string
& job_title
,
227 const std::vector
<std::string
>& tags
,
228 JobSpooler::Delegate
* delegate
) override
{
229 // TODO(gene): add tags handling.
230 scoped_refptr
<printing::PrintBackend
> print_backend(
231 printing::PrintBackend::CreateInstance(NULL
));
232 crash_keys::ScopedPrinterInfo
crash_key(
233 print_backend
->GetPrinterDriverInfo(printer_name
));
234 return core_
->Spool(print_ticket
, print_ticket_mime_type
,
235 print_data_file_path
, print_data_mime_type
,
236 printer_name
, job_title
, delegate
);
240 ~JobSpoolerWin() override
{}
243 // We use a Core class because we want a separate RefCountedThreadSafe
244 // implementation for ServiceUtilityProcessHost::Client.
245 class Core
: public ServiceUtilityProcessHost::Client
,
246 public base::win::ObjectWatcher::Delegate
{
248 Core() : job_id_(-1), delegate_(NULL
), saved_dc_(0) {}
250 bool Spool(const std::string
& print_ticket
,
251 const std::string
& print_ticket_mime_type
,
252 const base::FilePath
& print_data_file_path
,
253 const std::string
& print_data_mime_type
,
254 const std::string
& printer_name
,
255 const std::string
& job_title
,
256 JobSpooler::Delegate
* delegate
) {
258 // We are already in the process of printing.
262 base::string16 printer_wide
= base::UTF8ToWide(printer_name
);
263 // We only support PDF and XPS documents for now.
264 if (print_data_mime_type
== kContentTypePDF
) {
265 scoped_ptr
<DEVMODE
, base::FreeDeleter
> dev_mode
;
266 if (print_ticket_mime_type
== kContentTypeJSON
) {
267 dev_mode
= CjtToDevMode(printer_wide
, print_ticket
);
269 DCHECK(print_ticket_mime_type
== kContentTypeXML
);
270 dev_mode
= printing::XpsTicketToDevMode(printer_wide
, print_ticket
);
278 HDC dc
= CreateDC(L
"WINSPOOL", printer_wide
.c_str(), NULL
,
285 di
.cbSize
= sizeof(DOCINFO
);
286 base::string16 doc_name
= base::UTF8ToUTF16(job_title
);
287 DCHECK(printing::SimplifyDocumentTitle(doc_name
) == doc_name
);
288 di
.lpszDocName
= doc_name
.c_str();
289 job_id_
= StartDoc(dc
, &di
);
294 saved_dc_
= SaveDC(printer_dc_
.Get());
295 print_data_file_path_
= print_data_file_path
;
296 delegate_
= delegate
;
298 } else if (print_data_mime_type
== kContentTypeXPS
) {
299 DCHECK(print_ticket_mime_type
== kContentTypeXML
);
300 bool ret
= PrintXPSDocument(printer_name
,
302 print_data_file_path
,
305 delegate_
= delegate
;
314 void PreparePageDCForPrinting(HDC
, float scale_factor
) {
315 SetGraphicsMode(printer_dc_
.Get(), GM_ADVANCED
);
316 // Setup the matrix to translate and scale to the right place. Take in
317 // account the scale factor.
318 // Note that the printing output is relative to printable area of
319 // the page. That is 0,0 is offset by PHYSICALOFFSETX/Y from the page.
320 int offset_x
= ::GetDeviceCaps(printer_dc_
.Get(), PHYSICALOFFSETX
);
321 int offset_y
= ::GetDeviceCaps(printer_dc_
.Get(), PHYSICALOFFSETY
);
323 xform
.eDx
= static_cast<float>(-offset_x
);
324 xform
.eDy
= static_cast<float>(-offset_y
);
325 xform
.eM11
= xform
.eM22
= 1.0f
/ scale_factor
;
326 SetWorldTransform(printer_dc_
.Get(), &xform
);
329 // ServiceUtilityProcessHost::Client implementation.
330 void OnRenderPDFPagesToMetafilePageDone(
332 const printing::MetafilePlayer
& emf
) override
{
333 PreparePageDCForPrinting(printer_dc_
.Get(), scale_factor
);
334 ::StartPage(printer_dc_
.Get());
335 emf
.SafePlayback(printer_dc_
.Get());
336 ::EndPage(printer_dc_
.Get());
339 // ServiceUtilityProcessHost::Client implementation.
340 void OnRenderPDFPagesToMetafileDone(bool success
) override
{
341 PrintJobDone(success
);
344 void OnChildDied() override
{ PrintJobDone(false); }
346 // base::win::ObjectWatcher::Delegate implementation.
347 void OnObjectSignaled(HANDLE object
) override
{
348 DCHECK(xps_print_job_
.get());
349 DCHECK(object
== job_progress_event_
.Get());
350 ResetEvent(job_progress_event_
.Get());
353 XPS_JOB_STATUS job_status
= {0};
354 xps_print_job_
->GetJobStatus(&job_status
);
355 if ((job_status
.completion
== XPS_JOB_CANCELLED
) ||
356 (job_status
.completion
== XPS_JOB_FAILED
)) {
357 delegate_
->OnJobSpoolFailed();
358 } else if (job_status
.jobId
||
359 (job_status
.completion
== XPS_JOB_COMPLETED
)) {
360 // Note: In the case of the XPS document being printed to the
361 // Microsoft XPS Document Writer, it seems to skip spooling the job
362 // and goes to the completed state without ever assigning a job id.
363 delegate_
->OnJobSpoolSucceeded(job_status
.jobId
);
365 job_progress_watcher_
.StopWatching();
366 job_progress_watcher_
.StartWatching(job_progress_event_
.Get(), this);
373 // Helper class to allow PrintXPSDocument() to have multiple exits.
374 class PrintJobCanceler
{
376 explicit PrintJobCanceler(
377 base::win::ScopedComPtr
<IXpsPrintJob
>* job_ptr
)
378 : job_ptr_(job_ptr
) {
380 ~PrintJobCanceler() {
381 if (job_ptr_
&& job_ptr_
->get()) {
382 (*job_ptr_
)->Cancel();
387 void reset() { job_ptr_
= NULL
; }
390 base::win::ScopedComPtr
<IXpsPrintJob
>* job_ptr_
;
392 DISALLOW_COPY_AND_ASSIGN(PrintJobCanceler
);
395 void PrintJobDone(bool success
) {
396 // If there is no delegate, then there is nothing pending to process.
399 RestoreDC(printer_dc_
.Get(), saved_dc_
);
400 EndDoc(printer_dc_
.Get());
402 delegate_
->OnJobSpoolSucceeded(job_id_
);
404 delegate_
->OnJobSpoolFailed();
409 void RenderPDFPages() {
410 int printer_dpi
= ::GetDeviceCaps(printer_dc_
.Get(), LOGPIXELSX
);
411 int dc_width
= GetDeviceCaps(printer_dc_
.Get(), PHYSICALWIDTH
);
412 int dc_height
= GetDeviceCaps(printer_dc_
.Get(), PHYSICALHEIGHT
);
413 gfx::Rect
render_area(0, 0, dc_width
, dc_height
);
414 g_service_process
->io_thread()->task_runner()->PostTask(
416 base::Bind(&JobSpoolerWin::Core::RenderPDFPagesInSandbox
, this,
417 print_data_file_path_
, render_area
, printer_dpi
,
418 base::ThreadTaskRunnerHandle::Get()));
421 // Called on the service process IO thread.
422 void RenderPDFPagesInSandbox(
423 const base::FilePath
& pdf_path
,
424 const gfx::Rect
& render_area
,
426 const scoped_refptr
<base::SingleThreadTaskRunner
>& client_task_runner
) {
427 DCHECK(g_service_process
->io_thread()
429 ->BelongsToCurrentThread());
430 scoped_ptr
<ServiceUtilityProcessHost
> utility_host(
431 new ServiceUtilityProcessHost(this, client_task_runner
.get()));
432 // TODO(gene): For now we disabling autorotation for CloudPrinting.
433 // Landscape/Portrait setting is passed in the print ticket and
434 // server is generating portrait PDF always.
435 // We should enable autorotation once server will be able to generate
436 // PDF that matches paper size and orientation.
437 if (utility_host
->StartRenderPDFPagesToMetafile(
439 printing::PdfRenderSettings(render_area
, render_dpi
, false))) {
440 // The object will self-destruct when the child process dies.
441 utility_host
.release();
443 client_task_runner
->PostTask(
444 FROM_HERE
, base::Bind(&Core::PrintJobDone
, this, false));
448 bool PrintXPSDocument(const std::string
& printer_name
,
449 const std::string
& job_title
,
450 const base::FilePath
& print_data_file_path
,
451 const std::string
& print_ticket
) {
452 if (!printing::XPSPrintModule::Init())
455 job_progress_event_
.Set(CreateEvent(NULL
, TRUE
, FALSE
, NULL
));
456 if (!job_progress_event_
.Get())
459 PrintJobCanceler
job_canceler(&xps_print_job_
);
460 base::win::ScopedComPtr
<IXpsPrintJobStream
> doc_stream
;
461 base::win::ScopedComPtr
<IXpsPrintJobStream
> print_ticket_stream
;
462 if (FAILED(printing::XPSPrintModule::StartXpsPrintJob(
463 base::UTF8ToWide(printer_name
).c_str(),
464 base::UTF8ToWide(job_title
).c_str(),
465 NULL
, job_progress_event_
.Get(), NULL
, NULL
, NULL
,
466 xps_print_job_
.Receive(), doc_stream
.Receive(),
467 print_ticket_stream
.Receive())))
470 ULONG print_bytes_written
= 0;
471 if (FAILED(print_ticket_stream
->Write(print_ticket
.c_str(),
472 print_ticket
.length(),
473 &print_bytes_written
)))
475 DCHECK_EQ(print_ticket
.length(), print_bytes_written
);
476 if (FAILED(print_ticket_stream
->Close()))
479 std::string document_data
;
480 base::ReadFileToString(print_data_file_path
, &document_data
);
481 ULONG doc_bytes_written
= 0;
482 if (FAILED(doc_stream
->Write(document_data
.c_str(),
483 document_data
.length(),
484 &doc_bytes_written
)))
486 DCHECK_EQ(document_data
.length(), doc_bytes_written
);
487 if (FAILED(doc_stream
->Close()))
490 job_progress_watcher_
.StartWatching(job_progress_event_
.Get(), this);
491 job_canceler
.reset();
495 PlatformJobId job_id_
;
496 PrintSystem::JobSpooler::Delegate
* delegate_
;
498 base::win::ScopedCreateDC printer_dc_
;
499 base::FilePath print_data_file_path_
;
500 base::win::ScopedHandle job_progress_event_
;
501 base::win::ObjectWatcher job_progress_watcher_
;
502 base::win::ScopedComPtr
<IXpsPrintJob
> xps_print_job_
;
504 DISALLOW_COPY_AND_ASSIGN(Core
);
506 scoped_refptr
<Core
> core_
;
508 DISALLOW_COPY_AND_ASSIGN(JobSpoolerWin
);
511 // A helper class to handle the response from the utility process to the
512 // request to fetch printer capabilities and defaults.
513 class PrinterCapsHandler
: public ServiceUtilityProcessHost::Client
{
516 const std::string
& printer_name
,
517 const PrintSystem::PrinterCapsAndDefaultsCallback
& callback
)
518 : printer_name_(printer_name
), callback_(callback
) {
521 // ServiceUtilityProcessHost::Client implementation.
522 void OnChildDied() override
{
523 OnGetPrinterCapsAndDefaults(false, printer_name_
,
524 printing::PrinterCapsAndDefaults());
527 void OnGetPrinterCapsAndDefaults(
529 const std::string
& printer_name
,
530 const printing::PrinterCapsAndDefaults
& caps_and_defaults
) override
{
531 callback_
.Run(succeeded
, printer_name
, caps_and_defaults
);
536 void OnGetPrinterSemanticCapsAndDefaults(
538 const std::string
& printer_name
,
539 const printing::PrinterSemanticCapsAndDefaults
& semantic_info
) override
{
540 printing::PrinterCapsAndDefaults printer_info
;
542 printer_info
.caps_mime_type
= kContentTypeJSON
;
543 scoped_ptr
<base::DictionaryValue
> description(
544 PrinterSemanticCapsAndDefaultsToCdd(semantic_info
));
546 base::JSONWriter::WriteWithOptions(
547 *description
, base::JSONWriter::OPTIONS_PRETTY_PRINT
,
548 &printer_info
.printer_capabilities
);
551 callback_
.Run(succeeded
, printer_name
, printer_info
);
556 void StartGetPrinterCapsAndDefaults() {
557 g_service_process
->io_thread()->task_runner()->PostTask(
559 base::Bind(&PrinterCapsHandler::GetPrinterCapsAndDefaultsImpl
, this,
560 base::ThreadTaskRunnerHandle::Get()));
563 void StartGetPrinterSemanticCapsAndDefaults() {
564 g_service_process
->io_thread()->task_runner()->PostTask(
566 base::Bind(&PrinterCapsHandler::GetPrinterSemanticCapsAndDefaultsImpl
,
567 this, base::ThreadTaskRunnerHandle::Get()));
571 ~PrinterCapsHandler() override
{}
573 void GetPrinterCapsAndDefaultsImpl(
574 const scoped_refptr
<base::SingleThreadTaskRunner
>& client_task_runner
) {
575 DCHECK(g_service_process
->io_thread()
577 ->BelongsToCurrentThread());
578 scoped_ptr
<ServiceUtilityProcessHost
> utility_host(
579 new ServiceUtilityProcessHost(this, client_task_runner
.get()));
580 if (utility_host
->StartGetPrinterCapsAndDefaults(printer_name_
)) {
581 // The object will self-destruct when the child process dies.
582 utility_host
.release();
584 client_task_runner
->PostTask(
585 FROM_HERE
, base::Bind(&PrinterCapsHandler::OnChildDied
, this));
589 void GetPrinterSemanticCapsAndDefaultsImpl(
590 const scoped_refptr
<base::SingleThreadTaskRunner
>& client_task_runner
) {
591 DCHECK(g_service_process
->io_thread()
593 ->BelongsToCurrentThread());
594 scoped_ptr
<ServiceUtilityProcessHost
> utility_host(
595 new ServiceUtilityProcessHost(this, client_task_runner
.get()));
596 if (utility_host
->StartGetPrinterSemanticCapsAndDefaults(printer_name_
)) {
597 // The object will self-destruct when the child process dies.
598 utility_host
.release();
600 client_task_runner
->PostTask(
601 FROM_HERE
, base::Bind(&PrinterCapsHandler::OnChildDied
, this));
605 std::string printer_name_
;
606 PrintSystem::PrinterCapsAndDefaultsCallback callback_
;
609 class PrintSystemWin
: public PrintSystem
{
613 // PrintSystem implementation.
614 PrintSystemResult
Init() override
;
615 PrintSystem::PrintSystemResult
EnumeratePrinters(
616 printing::PrinterList
* printer_list
) override
;
617 void GetPrinterCapsAndDefaults(
618 const std::string
& printer_name
,
619 const PrinterCapsAndDefaultsCallback
& callback
) override
;
620 bool IsValidPrinter(const std::string
& printer_name
) override
;
621 bool ValidatePrintTicket(
622 const std::string
& printer_name
,
623 const std::string
& print_ticket_data
,
624 const std::string
& print_ticket_data_mime_type
) override
;
625 bool GetJobDetails(const std::string
& printer_name
,
626 PlatformJobId job_id
,
627 PrintJobDetails
* job_details
) override
;
628 PrintSystem::PrintServerWatcher
* CreatePrintServerWatcher() override
;
629 PrintSystem::PrinterWatcher
* CreatePrinterWatcher(
630 const std::string
& printer_name
) override
;
631 PrintSystem::JobSpooler
* CreateJobSpooler() override
;
632 bool UseCddAndCjt() override
;
633 std::string
GetSupportedMimeTypes() override
;
636 ~PrintSystemWin() override
{}
638 std::string
PrintSystemWin::GetPrinterDriverInfo(
639 const std::string
& printer_name
) const;
641 scoped_refptr
<printing::PrintBackend
> print_backend_
;
643 DISALLOW_COPY_AND_ASSIGN(PrintSystemWin
);
646 PrintSystemWin::PrintSystemWin() : use_cdd_(true) {
647 print_backend_
= printing::PrintBackend::CreateInstance(NULL
);
650 PrintSystem::PrintSystemResult
PrintSystemWin::Init() {
651 use_cdd_
= !base::CommandLine::ForCurrentProcess()->HasSwitch(
652 switches::kEnableCloudPrintXps
);
655 use_cdd_
= !printing::XPSModule::Init();
658 HPTPROVIDER provider
= NULL
;
659 HRESULT hr
= printing::XPSModule::OpenProvider(L
"", 1, &provider
);
661 printing::XPSModule::CloseProvider(provider
);
662 // Use cdd if error is different from expected.
663 use_cdd_
= (hr
!= HRESULT_FROM_WIN32(ERROR_INVALID_PRINTER_NAME
));
666 return PrintSystemResult(true, std::string());
669 PrintSystem::PrintSystemResult
PrintSystemWin::EnumeratePrinters(
670 printing::PrinterList
* printer_list
) {
671 bool ret
= print_backend_
->EnumeratePrinters(printer_list
);
672 return PrintSystemResult(ret
, std::string());
675 void PrintSystemWin::GetPrinterCapsAndDefaults(
676 const std::string
& printer_name
,
677 const PrinterCapsAndDefaultsCallback
& callback
) {
678 // Launch as child process to retrieve the capabilities and defaults because
679 // this involves invoking a printer driver DLL and crashes have been known to
681 PrinterCapsHandler
* handler
= new PrinterCapsHandler(printer_name
, callback
);
684 handler
->StartGetPrinterSemanticCapsAndDefaults();
686 handler
->StartGetPrinterCapsAndDefaults();
689 bool PrintSystemWin::IsValidPrinter(const std::string
& printer_name
) {
690 return print_backend_
->IsValidPrinter(printer_name
);
693 bool PrintSystemWin::ValidatePrintTicket(
694 const std::string
& printer_name
,
695 const std::string
& print_ticket_data
,
696 const std::string
& print_ticket_data_mime_type
) {
697 crash_keys::ScopedPrinterInfo
crash_key(GetPrinterDriverInfo(printer_name
));
700 return print_ticket_data_mime_type
== kContentTypeJSON
&&
701 IsValidCjt(print_ticket_data
);
703 DCHECK(print_ticket_data_mime_type
== kContentTypeXML
);
705 printing::ScopedXPSInitializer xps_initializer
;
706 if (!xps_initializer
.initialized()) {
707 // TODO(sanjeevr): Handle legacy proxy case (with no prntvpt.dll)
711 HPTPROVIDER provider
= NULL
;
712 printing::XPSModule::OpenProvider(base::UTF8ToWide(printer_name
), 1,
715 base::win::ScopedComPtr
<IStream
> print_ticket_stream
;
716 CreateStreamOnHGlobal(NULL
, TRUE
, print_ticket_stream
.Receive());
717 ULONG bytes_written
= 0;
718 print_ticket_stream
->Write(print_ticket_data
.c_str(),
719 print_ticket_data
.length(),
721 DCHECK(bytes_written
== print_ticket_data
.length());
722 LARGE_INTEGER pos
= {0};
723 ULARGE_INTEGER new_pos
= {0};
724 print_ticket_stream
->Seek(pos
, STREAM_SEEK_SET
, &new_pos
);
725 base::win::ScopedBstr error
;
726 base::win::ScopedComPtr
<IStream
> result_ticket_stream
;
727 CreateStreamOnHGlobal(NULL
, TRUE
, result_ticket_stream
.Receive());
728 ret
= SUCCEEDED(printing::XPSModule::MergeAndValidatePrintTicket(
730 print_ticket_stream
.get(),
733 result_ticket_stream
.get(),
735 printing::XPSModule::CloseProvider(provider
);
740 bool PrintSystemWin::GetJobDetails(const std::string
& printer_name
,
741 PlatformJobId job_id
,
742 PrintJobDetails
*job_details
) {
743 crash_keys::ScopedPrinterInfo
crash_key(
744 print_backend_
->GetPrinterDriverInfo(printer_name
));
746 printing::ScopedPrinterHandle printer_handle
;
747 std::wstring printer_name_wide
= base::UTF8ToWide(printer_name
);
748 printer_handle
.OpenPrinter(printer_name_wide
.c_str());
749 DCHECK(printer_handle
.IsValid());
751 if (printer_handle
.IsValid()) {
752 DWORD bytes_needed
= 0;
753 GetJob(printer_handle
.Get(), job_id
, 1, NULL
, 0, &bytes_needed
);
754 DWORD last_error
= GetLastError();
755 if (ERROR_INVALID_PARAMETER
!= last_error
) {
756 // ERROR_INVALID_PARAMETER normally means that the job id is not valid.
757 DCHECK(last_error
== ERROR_INSUFFICIENT_BUFFER
);
758 scoped_ptr
<BYTE
[]> job_info_buffer(new BYTE
[bytes_needed
]);
759 if (GetJob(printer_handle
.Get(), job_id
, 1, job_info_buffer
.get(),
760 bytes_needed
, &bytes_needed
)) {
761 JOB_INFO_1
*job_info
=
762 reinterpret_cast<JOB_INFO_1
*>(job_info_buffer
.get());
763 if (job_info
->pStatus
) {
764 base::WideToUTF8(job_info
->pStatus
, wcslen(job_info
->pStatus
),
765 &job_details
->status_message
);
767 job_details
->platform_status_flags
= job_info
->Status
;
768 if ((job_info
->Status
& JOB_STATUS_COMPLETE
) ||
769 (job_info
->Status
& JOB_STATUS_PRINTED
)) {
770 job_details
->status
= PRINT_JOB_STATUS_COMPLETED
;
771 } else if (job_info
->Status
& JOB_STATUS_ERROR
) {
772 job_details
->status
= PRINT_JOB_STATUS_ERROR
;
774 job_details
->status
= PRINT_JOB_STATUS_IN_PROGRESS
;
776 job_details
->total_pages
= job_info
->TotalPages
;
777 job_details
->pages_printed
= job_info
->PagesPrinted
;
785 PrintSystem::PrintServerWatcher
*
786 PrintSystemWin::CreatePrintServerWatcher() {
787 return new PrintServerWatcherWin();
790 PrintSystem::PrinterWatcher
* PrintSystemWin::CreatePrinterWatcher(
791 const std::string
& printer_name
) {
792 DCHECK(!printer_name
.empty());
793 return new PrinterWatcherWin(printer_name
);
796 PrintSystem::JobSpooler
* PrintSystemWin::CreateJobSpooler() {
797 return new JobSpoolerWin();
800 bool PrintSystemWin::UseCddAndCjt() {
804 std::string
PrintSystemWin::GetSupportedMimeTypes() {
807 result
= kContentTypeXPS
;
810 result
+= kContentTypePDF
;
814 std::string
PrintSystemWin::GetPrinterDriverInfo(
815 const std::string
& printer_name
) const {
816 return print_backend_
->GetPrinterDriverInfo(printer_name
);
821 scoped_refptr
<PrintSystem
> PrintSystem::CreateInstance(
822 const base::DictionaryValue
* print_system_settings
) {
823 return new PrintSystemWin
;
826 } // namespace cloud_print