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/win/object_watcher.h"
13 #include "base/win/scoped_bstr.h"
14 #include "base/win/scoped_comptr.h"
15 #include "base/win/scoped_hdc.h"
16 #include "chrome/common/chrome_switches.h"
17 #include "chrome/common/cloud_print/cloud_print_cdd_conversion.h"
18 #include "chrome/common/cloud_print/cloud_print_constants.h"
19 #include "chrome/common/crash_keys.h"
20 #include "chrome/service/cloud_print/cdd_conversion_win.h"
21 #include "chrome/service/service_process.h"
22 #include "chrome/service/service_utility_process_host.h"
23 #include "printing/backend/win_helper.h"
24 #include "printing/emf_win.h"
25 #include "printing/page_range.h"
26 #include "printing/pdf_render_settings.h"
27 #include "printing/printing_utils.h"
28 #include "ui/gfx/geometry/rect.h"
30 namespace cloud_print
{
34 class PrintSystemWatcherWin
: public base::win::ObjectWatcher::Delegate
{
36 PrintSystemWatcherWin()
40 ~PrintSystemWatcherWin() {
46 virtual ~Delegate() {}
47 virtual void OnPrinterAdded() = 0;
48 virtual void OnPrinterDeleted() = 0;
49 virtual void OnPrinterChanged() = 0;
50 virtual void OnJobChanged() = 0;
53 bool Start(const std::string
& printer_name
, Delegate
* delegate
) {
54 scoped_refptr
<printing::PrintBackend
> print_backend(
55 printing::PrintBackend::CreateInstance(NULL
));
56 printer_info_
= print_backend
->GetPrinterDriverInfo(printer_name
);
57 crash_keys::ScopedPrinterInfo
crash_key(printer_info_
);
60 // An empty printer name means watch the current server, we need to pass
61 // NULL to OpenPrinter.
62 LPTSTR printer_name_to_use
= NULL
;
63 std::wstring printer_name_wide
;
64 if (!printer_name
.empty()) {
65 printer_name_wide
= base::UTF8ToWide(printer_name
);
66 printer_name_to_use
= const_cast<LPTSTR
>(printer_name_wide
.c_str());
69 if (printer_
.OpenPrinter(printer_name_to_use
)) {
70 printer_change_
.Set(FindFirstPrinterChangeNotification(
71 printer_
.Get(), PRINTER_CHANGE_PRINTER
|PRINTER_CHANGE_JOB
, 0, NULL
));
72 if (printer_change_
.IsValid()) {
73 ret
= watcher_
.StartWatching(printer_change_
.Get(), this);
83 watcher_
.StopWatching();
85 printer_change_
.Close();
89 // base::ObjectWatcher::Delegate method
90 virtual void OnObjectSignaled(HANDLE object
) {
91 crash_keys::ScopedPrinterInfo
crash_key(printer_info_
);
93 FindNextPrinterChangeNotification(object
, &change
, NULL
, NULL
);
95 if (change
!= ((PRINTER_CHANGE_PRINTER
|PRINTER_CHANGE_JOB
) &
96 (~PRINTER_CHANGE_FAILED_CONNECTION_PRINTER
))) {
97 // For printer connections, we get spurious change notifications with
98 // all flags set except PRINTER_CHANGE_FAILED_CONNECTION_PRINTER.
100 if (change
& PRINTER_CHANGE_ADD_PRINTER
) {
101 delegate_
->OnPrinterAdded();
102 } else if (change
& PRINTER_CHANGE_DELETE_PRINTER
) {
103 delegate_
->OnPrinterDeleted();
104 } else if (change
& PRINTER_CHANGE_SET_PRINTER
) {
105 delegate_
->OnPrinterChanged();
107 if (change
& PRINTER_CHANGE_JOB
) {
108 delegate_
->OnJobChanged();
111 watcher_
.StartWatching(printer_change_
.Get(), this);
114 bool GetCurrentPrinterInfo(printing::PrinterBasicInfo
* printer_info
) {
115 DCHECK(printer_info
);
116 return InitBasicPrinterInfo(printer_
.Get(), printer_info
);
120 base::win::ObjectWatcher watcher_
;
121 printing::ScopedPrinterHandle printer_
; // The printer being watched
122 // Returned by FindFirstPrinterChangeNotifier.
123 printing::ScopedPrinterChangeHandle printer_change_
;
124 Delegate
* delegate_
; // Delegate to notify
125 bool did_signal_
; // DoneWaiting was called
126 std::string printer_info_
; // For crash reporting.
129 class PrintServerWatcherWin
130 : public PrintSystem::PrintServerWatcher
,
131 public PrintSystemWatcherWin::Delegate
{
133 PrintServerWatcherWin() : delegate_(NULL
) {}
135 // PrintSystem::PrintServerWatcher implementation.
136 virtual bool StartWatching(
137 PrintSystem::PrintServerWatcher::Delegate
* delegate
) override
{
138 delegate_
= delegate
;
139 return watcher_
.Start(std::string(), this);
142 virtual bool StopWatching() override
{
143 bool ret
= watcher_
.Stop();
148 // PrintSystemWatcherWin::Delegate implementation.
149 virtual void OnPrinterAdded() override
{
150 delegate_
->OnPrinterAdded();
152 virtual void OnPrinterDeleted() override
{}
153 virtual void OnPrinterChanged() override
{}
154 virtual void OnJobChanged() override
{}
157 virtual ~PrintServerWatcherWin() {}
160 PrintSystem::PrintServerWatcher::Delegate
* delegate_
;
161 PrintSystemWatcherWin watcher_
;
163 DISALLOW_COPY_AND_ASSIGN(PrintServerWatcherWin
);
166 class PrinterWatcherWin
167 : public PrintSystem::PrinterWatcher
,
168 public PrintSystemWatcherWin::Delegate
{
170 explicit PrinterWatcherWin(const std::string
& printer_name
)
171 : printer_name_(printer_name
),
175 // PrintSystem::PrinterWatcher implementation.
176 virtual bool StartWatching(
177 PrintSystem::PrinterWatcher::Delegate
* delegate
) override
{
178 delegate_
= delegate
;
179 return watcher_
.Start(printer_name_
, this);
182 virtual bool StopWatching() override
{
183 bool ret
= watcher_
.Stop();
188 virtual bool GetCurrentPrinterInfo(
189 printing::PrinterBasicInfo
* printer_info
) override
{
190 return watcher_
.GetCurrentPrinterInfo(printer_info
);
193 // PrintSystemWatcherWin::Delegate implementation.
194 virtual void OnPrinterAdded() override
{
197 virtual void OnPrinterDeleted() override
{
198 delegate_
->OnPrinterDeleted();
200 virtual void OnPrinterChanged() override
{
201 delegate_
->OnPrinterChanged();
203 virtual void OnJobChanged() override
{
204 delegate_
->OnJobChanged();
208 virtual ~PrinterWatcherWin() {}
211 std::string printer_name_
;
212 PrintSystem::PrinterWatcher::Delegate
* delegate_
;
213 PrintSystemWatcherWin watcher_
;
215 DISALLOW_COPY_AND_ASSIGN(PrinterWatcherWin
);
218 class JobSpoolerWin
: public PrintSystem::JobSpooler
{
220 JobSpoolerWin() : core_(new Core
) {}
222 // PrintSystem::JobSpooler implementation.
223 virtual bool Spool(const std::string
& print_ticket
,
224 const std::string
& print_ticket_mime_type
,
225 const base::FilePath
& print_data_file_path
,
226 const std::string
& print_data_mime_type
,
227 const std::string
& printer_name
,
228 const std::string
& job_title
,
229 const std::vector
<std::string
>& tags
,
230 JobSpooler::Delegate
* delegate
) override
{
231 // TODO(gene): add tags handling.
232 scoped_refptr
<printing::PrintBackend
> print_backend(
233 printing::PrintBackend::CreateInstance(NULL
));
234 crash_keys::ScopedPrinterInfo
crash_key(
235 print_backend
->GetPrinterDriverInfo(printer_name
));
236 return core_
->Spool(print_ticket
, print_ticket_mime_type
,
237 print_data_file_path
, print_data_mime_type
,
238 printer_name
, job_title
, delegate
);
242 virtual ~JobSpoolerWin() {}
245 // We use a Core class because we want a separate RefCountedThreadSafe
246 // implementation for ServiceUtilityProcessHost::Client.
247 class Core
: public ServiceUtilityProcessHost::Client
,
248 public base::win::ObjectWatcher::Delegate
{
250 Core() : job_id_(-1), delegate_(NULL
), saved_dc_(0) {}
254 bool Spool(const std::string
& print_ticket
,
255 const std::string
& print_ticket_mime_type
,
256 const base::FilePath
& print_data_file_path
,
257 const std::string
& print_data_mime_type
,
258 const std::string
& printer_name
,
259 const std::string
& job_title
,
260 JobSpooler::Delegate
* delegate
) {
262 // We are already in the process of printing.
266 base::string16 printer_wide
= base::UTF8ToWide(printer_name
);
267 // We only support PDF and XPS documents for now.
268 if (print_data_mime_type
== kContentTypePDF
) {
269 scoped_ptr
<DEVMODE
, base::FreeDeleter
> dev_mode
;
270 if (print_ticket_mime_type
== kContentTypeJSON
) {
271 dev_mode
= CjtToDevMode(printer_wide
, print_ticket
);
273 DCHECK(print_ticket_mime_type
== kContentTypeXML
);
274 dev_mode
= printing::XpsTicketToDevMode(printer_wide
, print_ticket
);
282 HDC dc
= CreateDC(L
"WINSPOOL", printer_wide
.c_str(), NULL
,
289 di
.cbSize
= sizeof(DOCINFO
);
290 base::string16 doc_name
= base::UTF8ToUTF16(job_title
);
291 DCHECK(printing::SimplifyDocumentTitle(doc_name
) == doc_name
);
292 di
.lpszDocName
= doc_name
.c_str();
293 job_id_
= StartDoc(dc
, &di
);
298 saved_dc_
= SaveDC(printer_dc_
.Get());
299 print_data_file_path_
= print_data_file_path
;
300 delegate_
= delegate
;
302 } else if (print_data_mime_type
== kContentTypeXPS
) {
303 DCHECK(print_ticket_mime_type
== kContentTypeXML
);
304 bool ret
= PrintXPSDocument(printer_name
,
306 print_data_file_path
,
309 delegate_
= delegate
;
318 void PreparePageDCForPrinting(HDC
, float scale_factor
) {
319 SetGraphicsMode(printer_dc_
.Get(), GM_ADVANCED
);
320 // Setup the matrix to translate and scale to the right place. Take in
321 // account the scale factor.
322 // Note that the printing output is relative to printable area of
323 // the page. That is 0,0 is offset by PHYSICALOFFSETX/Y from the page.
324 int offset_x
= ::GetDeviceCaps(printer_dc_
.Get(), PHYSICALOFFSETX
);
325 int offset_y
= ::GetDeviceCaps(printer_dc_
.Get(), PHYSICALOFFSETY
);
327 xform
.eDx
= static_cast<float>(-offset_x
);
328 xform
.eDy
= static_cast<float>(-offset_y
);
329 xform
.eM11
= xform
.eM22
= 1.0f
/ scale_factor
;
330 SetWorldTransform(printer_dc_
.Get(), &xform
);
333 // ServiceUtilityProcessHost::Client implementation.
334 virtual void OnRenderPDFPagesToMetafilePageDone(
336 const printing::MetafilePlayer
& emf
) override
{
337 PreparePageDCForPrinting(printer_dc_
.Get(), scale_factor
);
338 ::StartPage(printer_dc_
.Get());
339 emf
.SafePlayback(printer_dc_
.Get());
340 ::EndPage(printer_dc_
.Get());
343 // ServiceUtilityProcessHost::Client implementation.
344 virtual void OnRenderPDFPagesToMetafileDone(bool success
) override
{
345 PrintJobDone(success
);
348 virtual void OnChildDied() override
{ PrintJobDone(false); }
350 // base::win::ObjectWatcher::Delegate implementation.
351 virtual void OnObjectSignaled(HANDLE object
) override
{
352 DCHECK(xps_print_job_
.get());
353 DCHECK(object
== job_progress_event_
.Get());
354 ResetEvent(job_progress_event_
.Get());
357 XPS_JOB_STATUS job_status
= {0};
358 xps_print_job_
->GetJobStatus(&job_status
);
359 if ((job_status
.completion
== XPS_JOB_CANCELLED
) ||
360 (job_status
.completion
== XPS_JOB_FAILED
)) {
361 delegate_
->OnJobSpoolFailed();
362 } else if (job_status
.jobId
||
363 (job_status
.completion
== XPS_JOB_COMPLETED
)) {
364 // Note: In the case of the XPS document being printed to the
365 // Microsoft XPS Document Writer, it seems to skip spooling the job
366 // and goes to the completed state without ever assigning a job id.
367 delegate_
->OnJobSpoolSucceeded(job_status
.jobId
);
369 job_progress_watcher_
.StopWatching();
370 job_progress_watcher_
.StartWatching(job_progress_event_
.Get(), this);
375 // Helper class to allow PrintXPSDocument() to have multiple exits.
376 class PrintJobCanceler
{
378 explicit PrintJobCanceler(
379 base::win::ScopedComPtr
<IXpsPrintJob
>* job_ptr
)
380 : job_ptr_(job_ptr
) {
382 ~PrintJobCanceler() {
383 if (job_ptr_
&& job_ptr_
->get()) {
384 (*job_ptr_
)->Cancel();
389 void reset() { job_ptr_
= NULL
; }
392 base::win::ScopedComPtr
<IXpsPrintJob
>* job_ptr_
;
394 DISALLOW_COPY_AND_ASSIGN(PrintJobCanceler
);
397 void PrintJobDone(bool success
) {
398 // If there is no delegate, then there is nothing pending to process.
401 RestoreDC(printer_dc_
.Get(), saved_dc_
);
402 EndDoc(printer_dc_
.Get());
404 delegate_
->OnJobSpoolSucceeded(job_id_
);
406 delegate_
->OnJobSpoolFailed();
411 void RenderPDFPages() {
412 int printer_dpi
= ::GetDeviceCaps(printer_dc_
.Get(), LOGPIXELSX
);
413 int dc_width
= GetDeviceCaps(printer_dc_
.Get(), PHYSICALWIDTH
);
414 int dc_height
= GetDeviceCaps(printer_dc_
.Get(), PHYSICALHEIGHT
);
415 gfx::Rect
render_area(0, 0, dc_width
, dc_height
);
416 g_service_process
->io_thread()->message_loop_proxy()->PostTask(
418 base::Bind(&JobSpoolerWin::Core::RenderPDFPagesInSandbox
,
420 print_data_file_path_
,
423 base::MessageLoopProxy::current()));
426 // Called on the service process IO thread.
427 void RenderPDFPagesInSandbox(const base::FilePath
& pdf_path
,
428 const gfx::Rect
& render_area
,
430 const scoped_refptr
<base::MessageLoopProxy
>&
431 client_message_loop_proxy
) {
432 DCHECK(g_service_process
->io_thread()->message_loop_proxy()->
433 BelongsToCurrentThread());
434 scoped_ptr
<ServiceUtilityProcessHost
> utility_host(
435 new ServiceUtilityProcessHost(this, client_message_loop_proxy
.get()));
436 // TODO(gene): For now we disabling autorotation for CloudPrinting.
437 // Landscape/Portrait setting is passed in the print ticket and
438 // server is generating portrait PDF always.
439 // We should enable autorotation once server will be able to generate
440 // PDF that matches paper size and orientation.
441 if (utility_host
->StartRenderPDFPagesToMetafile(
443 printing::PdfRenderSettings(render_area
, render_dpi
, false))) {
444 // The object will self-destruct when the child process dies.
445 utility_host
.release();
447 client_message_loop_proxy
->PostTask(
448 FROM_HERE
, base::Bind(&Core::PrintJobDone
, this, false));
452 bool PrintXPSDocument(const std::string
& printer_name
,
453 const std::string
& job_title
,
454 const base::FilePath
& print_data_file_path
,
455 const std::string
& print_ticket
) {
456 if (!printing::XPSPrintModule::Init())
459 job_progress_event_
.Set(CreateEvent(NULL
, TRUE
, FALSE
, NULL
));
460 if (!job_progress_event_
.Get())
463 PrintJobCanceler
job_canceler(&xps_print_job_
);
464 base::win::ScopedComPtr
<IXpsPrintJobStream
> doc_stream
;
465 base::win::ScopedComPtr
<IXpsPrintJobStream
> print_ticket_stream
;
466 if (FAILED(printing::XPSPrintModule::StartXpsPrintJob(
467 base::UTF8ToWide(printer_name
).c_str(),
468 base::UTF8ToWide(job_title
).c_str(),
469 NULL
, job_progress_event_
.Get(), NULL
, NULL
, NULL
,
470 xps_print_job_
.Receive(), doc_stream
.Receive(),
471 print_ticket_stream
.Receive())))
474 ULONG print_bytes_written
= 0;
475 if (FAILED(print_ticket_stream
->Write(print_ticket
.c_str(),
476 print_ticket
.length(),
477 &print_bytes_written
)))
479 DCHECK_EQ(print_ticket
.length(), print_bytes_written
);
480 if (FAILED(print_ticket_stream
->Close()))
483 std::string document_data
;
484 base::ReadFileToString(print_data_file_path
, &document_data
);
485 ULONG doc_bytes_written
= 0;
486 if (FAILED(doc_stream
->Write(document_data
.c_str(),
487 document_data
.length(),
488 &doc_bytes_written
)))
490 DCHECK_EQ(document_data
.length(), doc_bytes_written
);
491 if (FAILED(doc_stream
->Close()))
494 job_progress_watcher_
.StartWatching(job_progress_event_
.Get(), this);
495 job_canceler
.reset();
499 PlatformJobId job_id_
;
500 PrintSystem::JobSpooler::Delegate
* delegate_
;
502 base::win::ScopedCreateDC printer_dc_
;
503 base::FilePath print_data_file_path_
;
504 base::win::ScopedHandle job_progress_event_
;
505 base::win::ObjectWatcher job_progress_watcher_
;
506 base::win::ScopedComPtr
<IXpsPrintJob
> xps_print_job_
;
508 DISALLOW_COPY_AND_ASSIGN(Core
);
510 scoped_refptr
<Core
> core_
;
512 DISALLOW_COPY_AND_ASSIGN(JobSpoolerWin
);
515 // A helper class to handle the response from the utility process to the
516 // request to fetch printer capabilities and defaults.
517 class PrinterCapsHandler
: public ServiceUtilityProcessHost::Client
{
520 const std::string
& printer_name
,
521 const PrintSystem::PrinterCapsAndDefaultsCallback
& callback
)
522 : printer_name_(printer_name
), callback_(callback
) {
525 // ServiceUtilityProcessHost::Client implementation.
526 virtual void OnChildDied() override
{
527 OnGetPrinterCapsAndDefaults(false, printer_name_
,
528 printing::PrinterCapsAndDefaults());
531 virtual void OnGetPrinterCapsAndDefaults(
533 const std::string
& printer_name
,
534 const printing::PrinterCapsAndDefaults
& caps_and_defaults
) override
{
535 callback_
.Run(succeeded
, printer_name
, caps_and_defaults
);
540 virtual void OnGetPrinterSemanticCapsAndDefaults(
542 const std::string
& printer_name
,
543 const printing::PrinterSemanticCapsAndDefaults
& semantic_info
) override
{
544 printing::PrinterCapsAndDefaults printer_info
;
546 printer_info
.caps_mime_type
= kContentTypeJSON
;
547 scoped_ptr
<base::DictionaryValue
> description(
548 PrinterSemanticCapsAndDefaultsToCdd(semantic_info
));
550 base::JSONWriter::WriteWithOptions(
551 description
.get(), base::JSONWriter::OPTIONS_PRETTY_PRINT
,
552 &printer_info
.printer_capabilities
);
555 callback_
.Run(succeeded
, printer_name
, printer_info
);
560 void StartGetPrinterCapsAndDefaults() {
561 g_service_process
->io_thread()->message_loop_proxy()->PostTask(
563 base::Bind(&PrinterCapsHandler::GetPrinterCapsAndDefaultsImpl
, this,
564 base::MessageLoopProxy::current()));
567 void StartGetPrinterSemanticCapsAndDefaults() {
568 g_service_process
->io_thread()->message_loop_proxy()->PostTask(
570 base::Bind(&PrinterCapsHandler::GetPrinterSemanticCapsAndDefaultsImpl
,
571 this, base::MessageLoopProxy::current()));
575 void GetPrinterCapsAndDefaultsImpl(
576 const scoped_refptr
<base::MessageLoopProxy
>&
577 client_message_loop_proxy
) {
578 DCHECK(g_service_process
->io_thread()->message_loop_proxy()->
579 BelongsToCurrentThread());
580 scoped_ptr
<ServiceUtilityProcessHost
> utility_host(
581 new ServiceUtilityProcessHost(this, client_message_loop_proxy
.get()));
582 if (utility_host
->StartGetPrinterCapsAndDefaults(printer_name_
)) {
583 // The object will self-destruct when the child process dies.
584 utility_host
.release();
586 client_message_loop_proxy
->PostTask(
588 base::Bind(&PrinterCapsHandler::OnChildDied
, this));
592 void GetPrinterSemanticCapsAndDefaultsImpl(
593 const scoped_refptr
<base::MessageLoopProxy
>&
594 client_message_loop_proxy
) {
595 DCHECK(g_service_process
->io_thread()->message_loop_proxy()->
596 BelongsToCurrentThread());
597 scoped_ptr
<ServiceUtilityProcessHost
> utility_host(
598 new ServiceUtilityProcessHost(this, client_message_loop_proxy
.get()));
599 if (utility_host
->StartGetPrinterSemanticCapsAndDefaults(printer_name_
)) {
600 // The object will self-destruct when the child process dies.
601 utility_host
.release();
603 client_message_loop_proxy
->PostTask(
605 base::Bind(&PrinterCapsHandler::OnChildDied
, this));
609 std::string printer_name_
;
610 PrintSystem::PrinterCapsAndDefaultsCallback callback_
;
613 class PrintSystemWin
: public PrintSystem
{
617 // PrintSystem implementation.
618 virtual PrintSystemResult
Init() override
;
619 virtual PrintSystem::PrintSystemResult
EnumeratePrinters(
620 printing::PrinterList
* printer_list
) override
;
621 virtual void GetPrinterCapsAndDefaults(
622 const std::string
& printer_name
,
623 const PrinterCapsAndDefaultsCallback
& callback
) override
;
624 virtual bool IsValidPrinter(const std::string
& printer_name
) override
;
625 virtual bool ValidatePrintTicket(
626 const std::string
& printer_name
,
627 const std::string
& print_ticket_data
,
628 const std::string
& print_ticket_data_mime_type
) override
;
629 virtual bool GetJobDetails(const std::string
& printer_name
,
630 PlatformJobId job_id
,
631 PrintJobDetails
*job_details
) override
;
632 virtual PrintSystem::PrintServerWatcher
* CreatePrintServerWatcher() override
;
633 virtual PrintSystem::PrinterWatcher
* CreatePrinterWatcher(
634 const std::string
& printer_name
) override
;
635 virtual PrintSystem::JobSpooler
* CreateJobSpooler() override
;
636 virtual bool UseCddAndCjt() override
;
637 virtual std::string
GetSupportedMimeTypes() override
;
640 std::string
PrintSystemWin::GetPrinterDriverInfo(
641 const std::string
& printer_name
) const;
643 scoped_refptr
<printing::PrintBackend
> print_backend_
;
645 DISALLOW_COPY_AND_ASSIGN(PrintSystemWin
);
648 PrintSystemWin::PrintSystemWin() : use_cdd_(true) {
649 print_backend_
= printing::PrintBackend::CreateInstance(NULL
);
652 PrintSystem::PrintSystemResult
PrintSystemWin::Init() {
653 use_cdd_
= !base::CommandLine::ForCurrentProcess()->HasSwitch(
654 switches::kEnableCloudPrintXps
);
657 use_cdd_
= !printing::XPSModule::Init();
660 HPTPROVIDER provider
= NULL
;
661 HRESULT hr
= printing::XPSModule::OpenProvider(L
"", 1, &provider
);
663 printing::XPSModule::CloseProvider(provider
);
664 // Use cdd if error is different from expected.
665 use_cdd_
= (hr
!= HRESULT_FROM_WIN32(ERROR_INVALID_PRINTER_NAME
));
668 return PrintSystemResult(true, std::string());
671 PrintSystem::PrintSystemResult
PrintSystemWin::EnumeratePrinters(
672 printing::PrinterList
* printer_list
) {
673 bool ret
= print_backend_
->EnumeratePrinters(printer_list
);
674 return PrintSystemResult(ret
, std::string());
677 void PrintSystemWin::GetPrinterCapsAndDefaults(
678 const std::string
& printer_name
,
679 const PrinterCapsAndDefaultsCallback
& callback
) {
680 // Launch as child process to retrieve the capabilities and defaults because
681 // this involves invoking a printer driver DLL and crashes have been known to
683 PrinterCapsHandler
* handler
= new PrinterCapsHandler(printer_name
, callback
);
686 handler
->StartGetPrinterSemanticCapsAndDefaults();
688 handler
->StartGetPrinterCapsAndDefaults();
691 bool PrintSystemWin::IsValidPrinter(const std::string
& printer_name
) {
692 return print_backend_
->IsValidPrinter(printer_name
);
695 bool PrintSystemWin::ValidatePrintTicket(
696 const std::string
& printer_name
,
697 const std::string
& print_ticket_data
,
698 const std::string
& print_ticket_data_mime_type
) {
699 crash_keys::ScopedPrinterInfo
crash_key(GetPrinterDriverInfo(printer_name
));
702 return print_ticket_data_mime_type
== kContentTypeJSON
&&
703 IsValidCjt(print_ticket_data
);
705 DCHECK(print_ticket_data_mime_type
== kContentTypeXML
);
707 printing::ScopedXPSInitializer xps_initializer
;
708 if (!xps_initializer
.initialized()) {
709 // TODO(sanjeevr): Handle legacy proxy case (with no prntvpt.dll)
713 HPTPROVIDER provider
= NULL
;
714 printing::XPSModule::OpenProvider(base::UTF8ToWide(printer_name
), 1,
717 base::win::ScopedComPtr
<IStream
> print_ticket_stream
;
718 CreateStreamOnHGlobal(NULL
, TRUE
, print_ticket_stream
.Receive());
719 ULONG bytes_written
= 0;
720 print_ticket_stream
->Write(print_ticket_data
.c_str(),
721 print_ticket_data
.length(),
723 DCHECK(bytes_written
== print_ticket_data
.length());
724 LARGE_INTEGER pos
= {0};
725 ULARGE_INTEGER new_pos
= {0};
726 print_ticket_stream
->Seek(pos
, STREAM_SEEK_SET
, &new_pos
);
727 base::win::ScopedBstr error
;
728 base::win::ScopedComPtr
<IStream
> result_ticket_stream
;
729 CreateStreamOnHGlobal(NULL
, TRUE
, result_ticket_stream
.Receive());
730 ret
= SUCCEEDED(printing::XPSModule::MergeAndValidatePrintTicket(
732 print_ticket_stream
.get(),
735 result_ticket_stream
.get(),
737 printing::XPSModule::CloseProvider(provider
);
742 bool PrintSystemWin::GetJobDetails(const std::string
& printer_name
,
743 PlatformJobId job_id
,
744 PrintJobDetails
*job_details
) {
745 crash_keys::ScopedPrinterInfo
crash_key(
746 print_backend_
->GetPrinterDriverInfo(printer_name
));
748 printing::ScopedPrinterHandle printer_handle
;
749 std::wstring printer_name_wide
= base::UTF8ToWide(printer_name
);
750 printer_handle
.OpenPrinter(printer_name_wide
.c_str());
751 DCHECK(printer_handle
.IsValid());
753 if (printer_handle
.IsValid()) {
754 DWORD bytes_needed
= 0;
755 GetJob(printer_handle
.Get(), job_id
, 1, NULL
, 0, &bytes_needed
);
756 DWORD last_error
= GetLastError();
757 if (ERROR_INVALID_PARAMETER
!= last_error
) {
758 // ERROR_INVALID_PARAMETER normally means that the job id is not valid.
759 DCHECK(last_error
== ERROR_INSUFFICIENT_BUFFER
);
760 scoped_ptr
<BYTE
[]> job_info_buffer(new BYTE
[bytes_needed
]);
761 if (GetJob(printer_handle
.Get(), job_id
, 1, job_info_buffer
.get(),
762 bytes_needed
, &bytes_needed
)) {
763 JOB_INFO_1
*job_info
=
764 reinterpret_cast<JOB_INFO_1
*>(job_info_buffer
.get());
765 if (job_info
->pStatus
) {
766 base::WideToUTF8(job_info
->pStatus
, wcslen(job_info
->pStatus
),
767 &job_details
->status_message
);
769 job_details
->platform_status_flags
= job_info
->Status
;
770 if ((job_info
->Status
& JOB_STATUS_COMPLETE
) ||
771 (job_info
->Status
& JOB_STATUS_PRINTED
)) {
772 job_details
->status
= PRINT_JOB_STATUS_COMPLETED
;
773 } else if (job_info
->Status
& JOB_STATUS_ERROR
) {
774 job_details
->status
= PRINT_JOB_STATUS_ERROR
;
776 job_details
->status
= PRINT_JOB_STATUS_IN_PROGRESS
;
778 job_details
->total_pages
= job_info
->TotalPages
;
779 job_details
->pages_printed
= job_info
->PagesPrinted
;
787 PrintSystem::PrintServerWatcher
*
788 PrintSystemWin::CreatePrintServerWatcher() {
789 return new PrintServerWatcherWin();
792 PrintSystem::PrinterWatcher
* PrintSystemWin::CreatePrinterWatcher(
793 const std::string
& printer_name
) {
794 DCHECK(!printer_name
.empty());
795 return new PrinterWatcherWin(printer_name
);
798 PrintSystem::JobSpooler
* PrintSystemWin::CreateJobSpooler() {
799 return new JobSpoolerWin();
802 bool PrintSystemWin::UseCddAndCjt() {
806 std::string
PrintSystemWin::GetSupportedMimeTypes() {
809 result
= kContentTypeXPS
;
812 result
+= kContentTypePDF
;
816 std::string
PrintSystemWin::GetPrinterDriverInfo(
817 const std::string
& printer_name
) const {
818 return print_backend_
->GetPrinterDriverInfo(printer_name
);
823 scoped_refptr
<PrintSystem
> PrintSystem::CreateInstance(
824 const base::DictionaryValue
* print_system_settings
) {
825 return new PrintSystemWin
;
828 } // namespace cloud_print