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_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_task_runner()->BelongsToCurrentThread());
426 scoped_ptr
<ServiceUtilityProcessHost
> utility_host(
427 new ServiceUtilityProcessHost(this, client_task_runner
.get()));
428 // TODO(gene): For now we disabling autorotation for CloudPrinting.
429 // Landscape/Portrait setting is passed in the print ticket and
430 // server is generating portrait PDF always.
431 // We should enable autorotation once server will be able to generate
432 // PDF that matches paper size and orientation.
433 if (utility_host
->StartRenderPDFPagesToMetafile(
435 printing::PdfRenderSettings(render_area
, render_dpi
, false))) {
436 // The object will self-destruct when the child process dies.
437 utility_host
.release();
439 client_task_runner
->PostTask(
440 FROM_HERE
, base::Bind(&Core::PrintJobDone
, this, false));
444 bool PrintXPSDocument(const std::string
& printer_name
,
445 const std::string
& job_title
,
446 const base::FilePath
& print_data_file_path
,
447 const std::string
& print_ticket
) {
448 if (!printing::XPSPrintModule::Init())
451 job_progress_event_
.Set(CreateEvent(NULL
, TRUE
, FALSE
, NULL
));
452 if (!job_progress_event_
.Get())
455 PrintJobCanceler
job_canceler(&xps_print_job_
);
456 base::win::ScopedComPtr
<IXpsPrintJobStream
> doc_stream
;
457 base::win::ScopedComPtr
<IXpsPrintJobStream
> print_ticket_stream
;
458 if (FAILED(printing::XPSPrintModule::StartXpsPrintJob(
459 base::UTF8ToWide(printer_name
).c_str(),
460 base::UTF8ToWide(job_title
).c_str(),
461 NULL
, job_progress_event_
.Get(), NULL
, NULL
, NULL
,
462 xps_print_job_
.Receive(), doc_stream
.Receive(),
463 print_ticket_stream
.Receive())))
466 ULONG print_bytes_written
= 0;
467 if (FAILED(print_ticket_stream
->Write(print_ticket
.c_str(),
468 print_ticket
.length(),
469 &print_bytes_written
)))
471 DCHECK_EQ(print_ticket
.length(), print_bytes_written
);
472 if (FAILED(print_ticket_stream
->Close()))
475 std::string document_data
;
476 base::ReadFileToString(print_data_file_path
, &document_data
);
477 ULONG doc_bytes_written
= 0;
478 if (FAILED(doc_stream
->Write(document_data
.c_str(),
479 document_data
.length(),
480 &doc_bytes_written
)))
482 DCHECK_EQ(document_data
.length(), doc_bytes_written
);
483 if (FAILED(doc_stream
->Close()))
486 job_progress_watcher_
.StartWatching(job_progress_event_
.Get(), this);
487 job_canceler
.reset();
491 PlatformJobId job_id_
;
492 PrintSystem::JobSpooler::Delegate
* delegate_
;
494 base::win::ScopedCreateDC printer_dc_
;
495 base::FilePath print_data_file_path_
;
496 base::win::ScopedHandle job_progress_event_
;
497 base::win::ObjectWatcher job_progress_watcher_
;
498 base::win::ScopedComPtr
<IXpsPrintJob
> xps_print_job_
;
500 DISALLOW_COPY_AND_ASSIGN(Core
);
502 scoped_refptr
<Core
> core_
;
504 DISALLOW_COPY_AND_ASSIGN(JobSpoolerWin
);
507 // A helper class to handle the response from the utility process to the
508 // request to fetch printer capabilities and defaults.
509 class PrinterCapsHandler
: public ServiceUtilityProcessHost::Client
{
512 const std::string
& printer_name
,
513 const PrintSystem::PrinterCapsAndDefaultsCallback
& callback
)
514 : printer_name_(printer_name
), callback_(callback
) {
517 // ServiceUtilityProcessHost::Client implementation.
518 void OnChildDied() override
{
519 OnGetPrinterCapsAndDefaults(false, printer_name_
,
520 printing::PrinterCapsAndDefaults());
523 void OnGetPrinterCapsAndDefaults(
525 const std::string
& printer_name
,
526 const printing::PrinterCapsAndDefaults
& caps_and_defaults
) override
{
527 callback_
.Run(succeeded
, printer_name
, caps_and_defaults
);
532 void OnGetPrinterSemanticCapsAndDefaults(
534 const std::string
& printer_name
,
535 const printing::PrinterSemanticCapsAndDefaults
& semantic_info
) override
{
536 printing::PrinterCapsAndDefaults printer_info
;
538 printer_info
.caps_mime_type
= kContentTypeJSON
;
539 scoped_ptr
<base::DictionaryValue
> description(
540 PrinterSemanticCapsAndDefaultsToCdd(semantic_info
));
542 base::JSONWriter::WriteWithOptions(
543 *description
, base::JSONWriter::OPTIONS_PRETTY_PRINT
,
544 &printer_info
.printer_capabilities
);
547 callback_
.Run(succeeded
, printer_name
, printer_info
);
552 void StartGetPrinterCapsAndDefaults() {
553 g_service_process
->io_task_runner()->PostTask(
555 base::Bind(&PrinterCapsHandler::GetPrinterCapsAndDefaultsImpl
, this,
556 base::ThreadTaskRunnerHandle::Get()));
559 void StartGetPrinterSemanticCapsAndDefaults() {
560 g_service_process
->io_task_runner()->PostTask(
562 base::Bind(&PrinterCapsHandler::GetPrinterSemanticCapsAndDefaultsImpl
,
563 this, base::ThreadTaskRunnerHandle::Get()));
567 ~PrinterCapsHandler() override
{}
569 void GetPrinterCapsAndDefaultsImpl(
570 const scoped_refptr
<base::SingleThreadTaskRunner
>& client_task_runner
) {
571 DCHECK(g_service_process
->io_task_runner()->BelongsToCurrentThread());
572 scoped_ptr
<ServiceUtilityProcessHost
> utility_host(
573 new ServiceUtilityProcessHost(this, client_task_runner
.get()));
574 if (utility_host
->StartGetPrinterCapsAndDefaults(printer_name_
)) {
575 // The object will self-destruct when the child process dies.
576 utility_host
.release();
578 client_task_runner
->PostTask(
579 FROM_HERE
, base::Bind(&PrinterCapsHandler::OnChildDied
, this));
583 void GetPrinterSemanticCapsAndDefaultsImpl(
584 const scoped_refptr
<base::SingleThreadTaskRunner
>& client_task_runner
) {
585 DCHECK(g_service_process
->io_task_runner()->BelongsToCurrentThread());
586 scoped_ptr
<ServiceUtilityProcessHost
> utility_host(
587 new ServiceUtilityProcessHost(this, client_task_runner
.get()));
588 if (utility_host
->StartGetPrinterSemanticCapsAndDefaults(printer_name_
)) {
589 // The object will self-destruct when the child process dies.
590 utility_host
.release();
592 client_task_runner
->PostTask(
593 FROM_HERE
, base::Bind(&PrinterCapsHandler::OnChildDied
, this));
597 std::string printer_name_
;
598 PrintSystem::PrinterCapsAndDefaultsCallback callback_
;
601 class PrintSystemWin
: public PrintSystem
{
605 // PrintSystem implementation.
606 PrintSystemResult
Init() override
;
607 PrintSystem::PrintSystemResult
EnumeratePrinters(
608 printing::PrinterList
* printer_list
) override
;
609 void GetPrinterCapsAndDefaults(
610 const std::string
& printer_name
,
611 const PrinterCapsAndDefaultsCallback
& callback
) override
;
612 bool IsValidPrinter(const std::string
& printer_name
) override
;
613 bool ValidatePrintTicket(
614 const std::string
& printer_name
,
615 const std::string
& print_ticket_data
,
616 const std::string
& print_ticket_data_mime_type
) override
;
617 bool GetJobDetails(const std::string
& printer_name
,
618 PlatformJobId job_id
,
619 PrintJobDetails
* job_details
) override
;
620 PrintSystem::PrintServerWatcher
* CreatePrintServerWatcher() override
;
621 PrintSystem::PrinterWatcher
* CreatePrinterWatcher(
622 const std::string
& printer_name
) override
;
623 PrintSystem::JobSpooler
* CreateJobSpooler() override
;
624 bool UseCddAndCjt() override
;
625 std::string
GetSupportedMimeTypes() override
;
628 ~PrintSystemWin() override
{}
630 std::string
GetPrinterDriverInfo(const std::string
& printer_name
) const;
632 scoped_refptr
<printing::PrintBackend
> print_backend_
;
634 DISALLOW_COPY_AND_ASSIGN(PrintSystemWin
);
637 PrintSystemWin::PrintSystemWin() : use_cdd_(true) {
638 print_backend_
= printing::PrintBackend::CreateInstance(NULL
);
641 PrintSystem::PrintSystemResult
PrintSystemWin::Init() {
642 use_cdd_
= !base::CommandLine::ForCurrentProcess()->HasSwitch(
643 switches::kEnableCloudPrintXps
);
646 use_cdd_
= !printing::XPSModule::Init();
649 HPTPROVIDER provider
= NULL
;
650 HRESULT hr
= printing::XPSModule::OpenProvider(L
"", 1, &provider
);
652 printing::XPSModule::CloseProvider(provider
);
653 // Use cdd if error is different from expected.
654 use_cdd_
= (hr
!= HRESULT_FROM_WIN32(ERROR_INVALID_PRINTER_NAME
));
657 return PrintSystemResult(true, std::string());
660 PrintSystem::PrintSystemResult
PrintSystemWin::EnumeratePrinters(
661 printing::PrinterList
* printer_list
) {
662 bool ret
= print_backend_
->EnumeratePrinters(printer_list
);
663 return PrintSystemResult(ret
, std::string());
666 void PrintSystemWin::GetPrinterCapsAndDefaults(
667 const std::string
& printer_name
,
668 const PrinterCapsAndDefaultsCallback
& callback
) {
669 // Launch as child process to retrieve the capabilities and defaults because
670 // this involves invoking a printer driver DLL and crashes have been known to
672 PrinterCapsHandler
* handler
= new PrinterCapsHandler(printer_name
, callback
);
675 handler
->StartGetPrinterSemanticCapsAndDefaults();
677 handler
->StartGetPrinterCapsAndDefaults();
680 bool PrintSystemWin::IsValidPrinter(const std::string
& printer_name
) {
681 return print_backend_
->IsValidPrinter(printer_name
);
684 bool PrintSystemWin::ValidatePrintTicket(
685 const std::string
& printer_name
,
686 const std::string
& print_ticket_data
,
687 const std::string
& print_ticket_data_mime_type
) {
688 crash_keys::ScopedPrinterInfo
crash_key(GetPrinterDriverInfo(printer_name
));
691 return print_ticket_data_mime_type
== kContentTypeJSON
&&
692 IsValidCjt(print_ticket_data
);
694 DCHECK(print_ticket_data_mime_type
== kContentTypeXML
);
696 printing::ScopedXPSInitializer xps_initializer
;
697 if (!xps_initializer
.initialized()) {
698 // TODO(sanjeevr): Handle legacy proxy case (with no prntvpt.dll)
702 HPTPROVIDER provider
= NULL
;
703 printing::XPSModule::OpenProvider(base::UTF8ToWide(printer_name
), 1,
706 base::win::ScopedComPtr
<IStream
> print_ticket_stream
;
707 CreateStreamOnHGlobal(NULL
, TRUE
, print_ticket_stream
.Receive());
708 ULONG bytes_written
= 0;
709 print_ticket_stream
->Write(print_ticket_data
.c_str(),
710 print_ticket_data
.length(),
712 DCHECK(bytes_written
== print_ticket_data
.length());
713 LARGE_INTEGER pos
= {};
714 ULARGE_INTEGER new_pos
= {};
715 print_ticket_stream
->Seek(pos
, STREAM_SEEK_SET
, &new_pos
);
716 base::win::ScopedBstr error
;
717 base::win::ScopedComPtr
<IStream
> result_ticket_stream
;
718 CreateStreamOnHGlobal(NULL
, TRUE
, result_ticket_stream
.Receive());
719 ret
= SUCCEEDED(printing::XPSModule::MergeAndValidatePrintTicket(
721 print_ticket_stream
.get(),
724 result_ticket_stream
.get(),
726 printing::XPSModule::CloseProvider(provider
);
731 bool PrintSystemWin::GetJobDetails(const std::string
& printer_name
,
732 PlatformJobId job_id
,
733 PrintJobDetails
*job_details
) {
734 crash_keys::ScopedPrinterInfo
crash_key(
735 print_backend_
->GetPrinterDriverInfo(printer_name
));
737 printing::ScopedPrinterHandle printer_handle
;
738 std::wstring printer_name_wide
= base::UTF8ToWide(printer_name
);
739 printer_handle
.OpenPrinter(printer_name_wide
.c_str());
740 DCHECK(printer_handle
.IsValid());
742 if (printer_handle
.IsValid()) {
743 DWORD bytes_needed
= 0;
744 GetJob(printer_handle
.Get(), job_id
, 1, NULL
, 0, &bytes_needed
);
745 DWORD last_error
= GetLastError();
746 if (ERROR_INVALID_PARAMETER
!= last_error
) {
747 // ERROR_INVALID_PARAMETER normally means that the job id is not valid.
748 DCHECK(last_error
== ERROR_INSUFFICIENT_BUFFER
);
749 scoped_ptr
<BYTE
[]> job_info_buffer(new BYTE
[bytes_needed
]);
750 if (GetJob(printer_handle
.Get(), job_id
, 1, job_info_buffer
.get(),
751 bytes_needed
, &bytes_needed
)) {
752 JOB_INFO_1
*job_info
=
753 reinterpret_cast<JOB_INFO_1
*>(job_info_buffer
.get());
754 if (job_info
->pStatus
) {
755 base::WideToUTF8(job_info
->pStatus
, wcslen(job_info
->pStatus
),
756 &job_details
->status_message
);
758 job_details
->platform_status_flags
= job_info
->Status
;
759 if ((job_info
->Status
& JOB_STATUS_COMPLETE
) ||
760 (job_info
->Status
& JOB_STATUS_PRINTED
)) {
761 job_details
->status
= PRINT_JOB_STATUS_COMPLETED
;
762 } else if (job_info
->Status
& JOB_STATUS_ERROR
) {
763 job_details
->status
= PRINT_JOB_STATUS_ERROR
;
765 job_details
->status
= PRINT_JOB_STATUS_IN_PROGRESS
;
767 job_details
->total_pages
= job_info
->TotalPages
;
768 job_details
->pages_printed
= job_info
->PagesPrinted
;
776 PrintSystem::PrintServerWatcher
*
777 PrintSystemWin::CreatePrintServerWatcher() {
778 return new PrintServerWatcherWin();
781 PrintSystem::PrinterWatcher
* PrintSystemWin::CreatePrinterWatcher(
782 const std::string
& printer_name
) {
783 DCHECK(!printer_name
.empty());
784 return new PrinterWatcherWin(printer_name
);
787 PrintSystem::JobSpooler
* PrintSystemWin::CreateJobSpooler() {
788 return new JobSpoolerWin();
791 bool PrintSystemWin::UseCddAndCjt() {
795 std::string
PrintSystemWin::GetSupportedMimeTypes() {
798 result
= kContentTypeXPS
;
801 result
+= kContentTypePDF
;
805 std::string
PrintSystemWin::GetPrinterDriverInfo(
806 const std::string
& printer_name
) const {
807 return print_backend_
->GetPrinterDriverInfo(printer_name
);
812 scoped_refptr
<PrintSystem
> PrintSystem::CreateInstance(
813 const base::DictionaryValue
* print_system_settings
) {
814 return new PrintSystemWin
;
817 } // namespace cloud_print