diff options
author | sanjeevr@chromium.org <sanjeevr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-02-17 17:48:24 +0000 |
---|---|---|
committer | sanjeevr@chromium.org <sanjeevr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-02-17 17:48:24 +0000 |
commit | 58310639ddc719c51bcd152966a01723ca16e4c5 (patch) | |
tree | 9960980d149c59317d177fb0f5032ab363025b4a | |
parent | 685dffb92f13c973310f36800384701122812e7b (diff) | |
download | chromium_src-58310639ddc719c51bcd152966a01723ca16e4c5.zip chromium_src-58310639ddc719c51bcd152966a01723ca16e4c5.tar.gz chromium_src-58310639ddc719c51bcd152966a01723ca16e4c5.tar.bz2 |
Added support to the Windows cloud print proxy to print XPS documents directly without any conversion (only works on Windows 7). The proxy uses the Accept: header to specify what data types it can accept.
BUG=None.
TEST=When the cloud print service supports this, submitting an XPS document should go through to the Win 7 proxy without any conversions.
Review URL: http://codereview.chromium.org/6523040
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@75286 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/service/cloud_print/cloud_print_proxy_backend.cc | 27 | ||||
-rw-r--r-- | chrome/service/cloud_print/cloud_print_url_fetcher.cc | 24 | ||||
-rw-r--r-- | chrome/service/cloud_print/cloud_print_url_fetcher.h | 9 | ||||
-rw-r--r-- | chrome/service/cloud_print/cloud_print_url_fetcher_unittest.cc | 4 | ||||
-rw-r--r-- | chrome/service/cloud_print/job_status_updater.cc | 5 | ||||
-rw-r--r-- | chrome/service/cloud_print/print_system.h | 5 | ||||
-rw-r--r-- | chrome/service/cloud_print/print_system_cups.cc | 9 | ||||
-rw-r--r-- | chrome/service/cloud_print/print_system_win.cc | 199 | ||||
-rw-r--r-- | chrome/service/cloud_print/printer_job_handler.cc | 28 | ||||
-rw-r--r-- | printing/backend/win_helper.cc | 53 | ||||
-rw-r--r-- | printing/backend/win_helper.h | 25 |
11 files changed, 320 insertions, 68 deletions
diff --git a/chrome/service/cloud_print/cloud_print_proxy_backend.cc b/chrome/service/cloud_print/cloud_print_proxy_backend.cc index 7890fee..e9d05c3 100644 --- a/chrome/service/cloud_print/cloud_print_proxy_backend.cc +++ b/chrome/service/cloud_print/cloud_print_proxy_backend.cc @@ -475,8 +475,11 @@ void CloudPrintProxyBackend::Core::GetRegisteredPrinters() { next_response_handler_ = &CloudPrintProxyBackend::Core::HandlePrinterListResponse; request_ = new CloudPrintURLFetcher; - request_->StartGetRequest(printer_list_url, this, auth_token_, - kCloudPrintAPIMaxRetryCount); + request_->StartGetRequest(printer_list_url, + this, + auth_token_, + kCloudPrintAPIMaxRetryCount, + std::string()); } void CloudPrintProxyBackend::Core::RegisterNextPrinter() { @@ -565,9 +568,13 @@ void CloudPrintProxyBackend::Core::OnReceivePrinterCaps( std::string mime_type("multipart/form-data; boundary="); mime_type += mime_boundary; request_ = new CloudPrintURLFetcher; - request_->StartPostRequest(post_url, this, auth_token_, - kCloudPrintAPIMaxRetryCount, mime_type, - post_data); + request_->StartPostRequest(post_url, + this, + auth_token_, + kCloudPrintAPIMaxRetryCount, + mime_type, + post_data, + std::string()); } else { LOG(ERROR) << "CP_PROXY: Failed to get printer info for: " << printer_name; @@ -774,9 +781,13 @@ void CloudPrintProxyBackend::Core::ReportUserMessage( std::string mime_type("multipart/form-data; boundary="); mime_type += mime_boundary; request_ = new CloudPrintURLFetcher; - request_->StartPostRequest(post_url, this, auth_token_, - kCloudPrintAPIMaxRetryCount, mime_type, - post_data); + request_->StartPostRequest(post_url, + this, + auth_token_, + kCloudPrintAPIMaxRetryCount, + mime_type, + post_data, + std::string()); } CloudPrintURLFetcher::ResponseAction diff --git a/chrome/service/cloud_print/cloud_print_url_fetcher.cc b/chrome/service/cloud_print/cloud_print_url_fetcher.cc index 9840e14..0d81e17 100644 --- a/chrome/service/cloud_print/cloud_print_url_fetcher.cc +++ b/chrome/service/cloud_print/cloud_print_url_fetcher.cc @@ -18,12 +18,14 @@ CloudPrintURLFetcher::CloudPrintURLFetcher() num_retries_(0) { } -void CloudPrintURLFetcher::StartGetRequest(const GURL& url, - Delegate* delegate, - const std::string& auth_token, - int max_retries) { +void CloudPrintURLFetcher::StartGetRequest( + const GURL& url, + Delegate* delegate, + const std::string& auth_token, + int max_retries, + const std::string& additional_headers) { StartRequestHelper(url, URLFetcher::GET, delegate, auth_token, max_retries, - std::string(), std::string()); + std::string(), std::string(), additional_headers); } void CloudPrintURLFetcher::StartPostRequest( @@ -32,9 +34,10 @@ void CloudPrintURLFetcher::StartPostRequest( const std::string& auth_token, int max_retries, const std::string& post_data_mime_type, - const std::string& post_data) { + const std::string& post_data, + const std::string& additional_headers) { StartRequestHelper(url, URLFetcher::POST, delegate, auth_token, max_retries, - post_data_mime_type, post_data); + post_data_mime_type, post_data, additional_headers); } // URLFetcher::Delegate implementation. @@ -113,7 +116,8 @@ void CloudPrintURLFetcher::StartRequestHelper( const std::string& auth_token, int max_retries, const std::string& post_data_mime_type, - const std::string& post_data) { + const std::string& post_data, + const std::string& additional_headers) { DCHECK(delegate); request_.reset(new URLFetcher(url, request_type, this)); request_->set_request_context(GetRequestContextGetter()); @@ -125,6 +129,10 @@ void CloudPrintURLFetcher::StartRequestHelper( headers += auth_token; headers += "\r\n"; headers += kChromeCloudPrintProxyHeader; + if (!additional_headers.empty()) { + headers += "\r\n"; + headers += additional_headers; + } request_->set_extra_request_headers(headers); if (request_type == URLFetcher::POST) { request_->set_upload_data(post_data_mime_type, post_data); diff --git a/chrome/service/cloud_print/cloud_print_url_fetcher.h b/chrome/service/cloud_print/cloud_print_url_fetcher.h index 850265e..12e97b7 100644 --- a/chrome/service/cloud_print/cloud_print_url_fetcher.h +++ b/chrome/service/cloud_print/cloud_print_url_fetcher.h @@ -81,13 +81,15 @@ class CloudPrintURLFetcher void StartGetRequest(const GURL& url, Delegate* delegate, const std::string& auth_token, - int max_retries); + int max_retries, + const std::string& additional_headers); void StartPostRequest(const GURL& url, Delegate* delegate, const std::string& auth_token, int max_retries, const std::string& post_data_mime_type, - const std::string& post_data); + const std::string& post_data, + const std::string& additional_headers); // URLFetcher::Delegate implementation. virtual void OnURLFetchComplete(const URLFetcher* source, const GURL& url, @@ -109,7 +111,8 @@ class CloudPrintURLFetcher const std::string& auth_token, int max_retries, const std::string& post_data_mime_type, - const std::string& post_data); + const std::string& post_data, + const std::string& additional_headers); scoped_ptr<URLFetcher> request_; Delegate* delegate_; diff --git a/chrome/service/cloud_print/cloud_print_url_fetcher_unittest.cc b/chrome/service/cloud_print/cloud_print_url_fetcher_unittest.cc index 6d399b0..7a8e233 100644 --- a/chrome/service/cloud_print/cloud_print_url_fetcher_unittest.cc +++ b/chrome/service/cloud_print/cloud_print_url_fetcher_unittest.cc @@ -192,7 +192,7 @@ void CloudPrintURLFetcherTest::CreateFetcher(const GURL& url, int max_retries) { fetcher_ = new TestCloudPrintURLFetcher(io_message_loop_proxy()); max_retries_ = max_retries; start_time_ = Time::Now(); - fetcher_->StartGetRequest(url, this, "", max_retries_); + fetcher_->StartGetRequest(url, this, "", max_retries_, std::string()); } CloudPrintURLFetcher::ResponseAction @@ -264,7 +264,7 @@ CloudPrintURLFetcherOverloadTest::HandleRawData(const URLFetcher* source, const TimeDelta one_second = TimeDelta::FromMilliseconds(1000); response_count_++; if (response_count_ < 20) { - fetcher_->StartGetRequest(url, this, "", max_retries_); + fetcher_->StartGetRequest(url, this, "", max_retries_, std::string()); } else { // We have already sent 20 requests continuously. And we expect that // it takes more than 1 second due to the overload protection settings. diff --git a/chrome/service/cloud_print/job_status_updater.cc b/chrome/service/cloud_print/job_status_updater.cc index f717f29..56632b1 100644 --- a/chrome/service/cloud_print/job_status_updater.cc +++ b/chrome/service/cloud_print/job_status_updater.cc @@ -62,7 +62,10 @@ void JobStatusUpdater::UpdateStatus() { request_->StartGetRequest( CloudPrintHelpers::GetUrlForJobStatusUpdate( cloud_print_server_url_, job_id_, last_job_details_), - this, auth_token_, kCloudPrintAPIMaxRetryCount); + this, + auth_token_, + kCloudPrintAPIMaxRetryCount, + std::string()); } } } diff --git a/chrome/service/cloud_print/print_system.h b/chrome/service/cloud_print/print_system.h index d3de6bc9..d744826 100644 --- a/chrome/service/cloud_print/print_system.h +++ b/chrome/service/cloud_print/print_system.h @@ -185,6 +185,11 @@ class PrintSystem : public base::RefCountedThreadSafe<PrintSystem> { const std::string& printer_name) = 0; virtual JobSpooler* CreateJobSpooler() = 0; + // Returns a comma separated list of mimetypes for print data that are + // supported by this print system. The format of this string is the same as + // that used for the HTTP Accept: header. + virtual std::string GetSupportedMimeTypes() = 0; + // Generate unique for proxy. static std::string GenerateProxyId(); diff --git a/chrome/service/cloud_print/print_system_cups.cc b/chrome/service/cloud_print/print_system_cups.cc index 6cb26e1..7d51908 100644 --- a/chrome/service/cloud_print/print_system_cups.cc +++ b/chrome/service/cloud_print/print_system_cups.cc @@ -95,6 +95,7 @@ class PrintSystemCUPS : public PrintSystem { virtual PrintSystem::PrinterWatcher* CreatePrinterWatcher( const std::string& printer_name); virtual PrintSystem::JobSpooler* CreateJobSpooler(); + virtual std::string GetSupportedMimeTypes(); // Helper functions. PlatformJobId SpoolPrintJob(const std::string& print_ticket, @@ -644,6 +645,14 @@ PrintSystem::JobSpooler* PrintSystemCUPS::CreateJobSpooler() { return new JobSpoolerCUPS(this); } +std::string PrintSystemCUPS::GetSupportedMimeTypes() { + // Since we hand off the document to the CUPS server directly, list some types + // that we know CUPS supports (http://www.cups.org/articles.php?L205+TFAQ+Q) + // TODO(sanjeevr): Determine this dynamically (http://crbug.com/73240). + return + "application/pdf,application/postscript,image/jpeg,image/png,image/gif"; +} + std::string PrintSystem::GenerateProxyId() { // TODO(gene): This code should generate a unique id for proxy. ID should be // unique for this user. Rand may return the same number. We'll need to change diff --git a/chrome/service/cloud_print/print_system_win.cc b/chrome/service/cloud_print/print_system_win.cc index 62f4ddf..4a09ff5 100644 --- a/chrome/service/cloud_print/print_system_win.cc +++ b/chrome/service/cloud_print/print_system_win.cc @@ -6,8 +6,14 @@ #include <objidl.h> #include <winspool.h> +#if defined(_WIN32_WINNT) +#undef _WIN32_WINNT +#endif // defined(_WIN32_WINNT) +#define _WIN32_WINNT _WIN32_WINNT_WIN7 +#include <xpsprint.h> #include "base/file_path.h" +#include "base/file_util.h" #include "base/scoped_ptr.h" #include "base/utf_string_conversions.h" #include "base/win/object_watcher.h" @@ -366,10 +372,15 @@ class PrintSystemWin : public PrintSystem { private: // We use a Core class because we want a separate RefCountedThreadSafe // implementation for ServiceUtilityProcessHost::Client. - class Core : public ServiceUtilityProcessHost::Client { + class Core : public ServiceUtilityProcessHost::Client, + public base::win::ObjectWatcher::Delegate { public: Core() - : last_page_printed_(-1), job_id_(-1), delegate_(NULL), saved_dc_(0) { + : last_page_printed_(-1), + job_id_(-1), + delegate_(NULL), + saved_dc_(0), + should_couninit_(false) { } ~Core() { } @@ -385,47 +396,54 @@ class PrintSystemWin : public PrintSystem { return false; } last_page_printed_ = -1; - // We only support PDFs for now. - if (print_data_mime_type != "application/pdf") { - NOTREACHED(); - return false; - } - - DevMode pt_dev_mode; - HRESULT hr = PrintTicketToDevMode(printer_name, print_ticket, - &pt_dev_mode); - if (FAILED(hr)) { - NOTREACHED(); - return false; - } - - HDC dc = CreateDC(L"WINSPOOL", UTF8ToWide(printer_name).c_str(), - NULL, pt_dev_mode.dm_); - if (!dc) { + // We only support PDF and XPS documents for now. + if (print_data_mime_type == "application/pdf") { + DevMode pt_dev_mode; + HRESULT hr = PrintTicketToDevMode(printer_name, print_ticket, + &pt_dev_mode); + if (FAILED(hr)) { + NOTREACHED(); + return false; + } + + HDC dc = CreateDC(L"WINSPOOL", UTF8ToWide(printer_name).c_str(), + NULL, pt_dev_mode.dm_); + if (!dc) { + NOTREACHED(); + return false; + } + hr = E_FAIL; + DOCINFO di = {0}; + di.cbSize = sizeof(DOCINFO); + std::wstring doc_name = UTF8ToWide(job_title); + di.lpszDocName = doc_name.c_str(); + job_id_ = StartDoc(dc, &di); + if (job_id_ <= 0) + return false; + + printer_dc_.Set(dc); + int printer_dpi = ::GetDeviceCaps(printer_dc_.Get(), LOGPIXELSX); + saved_dc_ = SaveDC(printer_dc_.Get()); + SetGraphicsMode(printer_dc_.Get(), GM_ADVANCED); + XFORM xform = {0}; + xform.eM11 = xform.eM22 = static_cast<float>(printer_dpi) / + static_cast<float>(GetDeviceCaps(GetDC(NULL), LOGPIXELSX)); + ModifyWorldTransform(printer_dc_.Get(), &xform, MWT_LEFTMULTIPLY); + print_data_file_path_ = print_data_file_path; + delegate_ = delegate; + RenderNextPDFPages(); + } else if (print_data_mime_type == "application/vnd.ms-xpsdocument") { + bool ret = PrintXPSDocument(printer_name, + job_title, + print_data_file_path, + print_ticket); + if (ret) + delegate_ = delegate; + return ret; + } else { NOTREACHED(); return false; } - hr = E_FAIL; - DOCINFO di = {0}; - di.cbSize = sizeof(DOCINFO); - std::wstring doc_name = UTF8ToWide(job_title); - di.lpszDocName = doc_name.c_str(); - job_id_ = StartDoc(dc, &di); - if (job_id_ <= 0) - return false; - - printer_dc_.Set(dc); - - int printer_dpi = ::GetDeviceCaps(printer_dc_.Get(), LOGPIXELSX); - saved_dc_ = SaveDC(printer_dc_.Get()); - SetGraphicsMode(printer_dc_.Get(), GM_ADVANCED); - XFORM xform = {0}; - xform.eM11 = xform.eM22 = static_cast<float>(printer_dpi) / - static_cast<float>(GetDeviceCaps(GetDC(NULL), LOGPIXELSX)); - ModifyWorldTransform(printer_dc_.Get(), &xform, MWT_LEFTMULTIPLY); - print_data_file_path_ = print_data_file_path; - delegate_ = delegate; - RenderNextPDFPages(); return true; } @@ -442,6 +460,33 @@ class PrintSystemWin : public PrintSystem { else RenderNextPDFPages(); } + + // base::win::ObjectWatcher::Delegate inplementation. + virtual void OnObjectSignaled(HANDLE object) { + DCHECK(xps_print_job_); + if (!delegate_) + return; + XPS_JOB_STATUS job_status = {0}; + xps_print_job_->GetJobStatus(&job_status); + bool done = false; + if ((job_status.completion == XPS_JOB_CANCELLED) || + (job_status.completion == XPS_JOB_FAILED)) { + delegate_->OnJobSpoolFailed(); + done = true; + } else if (job_status.jobId) { + delegate_->OnJobSpoolSucceeded(job_status.jobId); + done = true; + } else { + ResetEvent(job_progress_event_.Get()); + job_progress_watcher_.StopWatching(); + job_progress_watcher_.StartWatching(job_progress_event_.Get(), this); + } + if (done && should_couninit_) { + CoUninitialize(); + should_couninit_ = false; + } + } + virtual void OnRenderPDFPagesToMetafileFailed() { PrintJobDone(); } @@ -503,6 +548,67 @@ class PrintSystemWin : public PrintSystem { utility_host.release(); } } + bool PrintXPSDocument(const std::string& printer_name, + const std::string& job_title, + const FilePath& print_data_file_path, + const std::string& print_ticket) { + if (!printing::XPSPrintModule::Init()) + return false; + job_progress_event_.Set(CreateEvent(NULL, TRUE, FALSE, NULL)); + if (!job_progress_event_.Get()) + return false; + should_couninit_ = SUCCEEDED(CoInitializeEx(NULL, + COINIT_MULTITHREADED)); + ScopedComPtr<IXpsPrintJobStream> doc_stream; + ScopedComPtr<IXpsPrintJobStream> print_ticket_stream; + bool ret = false; + // Use nested SUCCEEDED checks because we want a common return point. + if (SUCCEEDED(printing::XPSPrintModule::StartXpsPrintJob( + UTF8ToWide(printer_name).c_str(), + UTF8ToWide(job_title).c_str(), + NULL, + job_progress_event_.Get(), + NULL, + NULL, + NULL, + xps_print_job_.Receive(), + doc_stream.Receive(), + print_ticket_stream.Receive()))) { + ULONG bytes_written = 0; + if (SUCCEEDED(print_ticket_stream->Write(print_ticket.c_str(), + print_ticket.length(), + &bytes_written))) { + DCHECK(bytes_written == print_ticket.length()); + if (SUCCEEDED(print_ticket_stream->Close())) { + std::string document_data; + file_util::ReadFileToString(print_data_file_path, &document_data); + bytes_written = 0; + if (SUCCEEDED(doc_stream->Write(document_data.c_str(), + document_data.length(), + &bytes_written))) { + DCHECK(bytes_written == document_data.length()); + if (SUCCEEDED(doc_stream->Close())) { + job_progress_watcher_.StartWatching(job_progress_event_.Get(), + this); + ret = true; + } + } + } + } + } + if (!ret) { + if (xps_print_job_) { + xps_print_job_->Cancel(); + xps_print_job_.Release(); + } + if (should_couninit_) { + CoUninitialize(); + should_couninit_ = false; + } + } + return ret; + } + // Some Cairo-generated PDFs from Chrome OS result in huge metafiles. // So the PageCountPerBatch is set to 1 for now. // TODO(sanjeevr): Figure out a smarter way to determine the pages per @@ -515,6 +621,10 @@ class PrintSystemWin : public PrintSystem { int saved_dc_; base::win::ScopedHDC printer_dc_; FilePath print_data_file_path_; + base::win::ScopedHandle job_progress_event_; + base::win::ObjectWatcher job_progress_watcher_; + ScopedComPtr<IXpsPrintJob> xps_print_job_; + bool should_couninit_; DISALLOW_COPY_AND_ASSIGN(JobSpoolerWin::Core); }; scoped_refptr<Core> core_; @@ -588,6 +698,8 @@ class PrintSystemWin : public PrintSystem { virtual PrintSystem::PrinterWatcher* CreatePrinterWatcher( const std::string& printer_name); virtual PrintSystem::JobSpooler* CreateJobSpooler(); + virtual std::string GetSupportedMimeTypes(); + private: scoped_refptr<printing::PrintBackend> print_backend_; @@ -728,6 +840,13 @@ PrintSystemWin::CreateJobSpooler() { return new JobSpoolerWin(); } +std::string PrintSystemWin::GetSupportedMimeTypes() { + if (printing::XPSPrintModule::Init()) + return "application/vnd.ms-xpsdocument,application/pdf"; + return "application/pdf"; +} + + std::string PrintSystem::GenerateProxyId() { GUID proxy_id = {0}; HRESULT hr = UuidCreate(&proxy_id); diff --git a/chrome/service/cloud_print/printer_job_handler.cc b/chrome/service/cloud_print/printer_job_handler.cc index c99d1b6..572accc 100644 --- a/chrome/service/cloud_print/printer_job_handler.cc +++ b/chrome/service/cloud_print/printer_job_handler.cc @@ -109,7 +109,10 @@ void PrinterJobHandler::Start() { request_->StartGetRequest( CloudPrintHelpers::GetUrlForPrinterDelete( cloud_print_server_url_, printer_info_cloud_.printer_id), - this, auth_token_, kCloudPrintAPIMaxRetryCount); + this, + auth_token_, + kCloudPrintAPIMaxRetryCount, + std::string()); } if (!task_in_progress_ && printer_update_pending_) { printer_update_pending_ = false; @@ -125,7 +128,10 @@ void PrinterJobHandler::Start() { CloudPrintHelpers::GetUrlForJobFetch( cloud_print_server_url_, printer_info_cloud_.printer_id, job_fetch_reason_), - this, auth_token_, kCloudPrintAPIMaxRetryCount); + this, + auth_token_, + kCloudPrintAPIMaxRetryCount, + std::string()); last_job_fetch_time_ = base::TimeTicks::Now(); VLOG(1) << "Last job fetch time for printer " << printer_info_.printer_name.c_str() << " is " @@ -254,7 +260,12 @@ void PrinterJobHandler::OnReceivePrinterCaps( request_->StartPostRequest( CloudPrintHelpers::GetUrlForPrinterUpdate( cloud_print_server_url_, printer_info_cloud_.printer_id), - this, auth_token_, kCloudPrintAPIMaxRetryCount, mime_type, post_data); + this, + auth_token_, + kCloudPrintAPIMaxRetryCount, + mime_type, + post_data, + std::string()); } else { // We are done here. Go to the Stop state MessageLoop::current()->PostTask( @@ -408,7 +419,8 @@ PrinterJobHandler::HandleJobMetadataResponse( request_->StartGetRequest(GURL(print_ticket_url.c_str()), this, auth_token_, - kCloudPrintAPIMaxRetryCount); + kCloudPrintAPIMaxRetryCount, + std::string()); } } } @@ -429,10 +441,13 @@ PrinterJobHandler::HandlePrintTicketResponse(const URLFetcher* source, job_details_.print_ticket_ = data; SetNextDataHandler(&PrinterJobHandler::HandlePrintDataResponse); request_ = new CloudPrintURLFetcher; + std::string accept_headers = "Accept: "; + accept_headers += print_system_->GetSupportedMimeTypes(); request_->StartGetRequest(GURL(print_data_url_.c_str()), this, auth_token_, - kJobDataMaxRetryCount); + kJobDataMaxRetryCount, + accept_headers); } else { // The print ticket was not valid. We are done here. FailedFetchingJobData(); @@ -580,7 +595,8 @@ void PrinterJobHandler::UpdateJobStatus(cloud_print::PrintJobStatus status, status), this, auth_token_, - kCloudPrintAPIMaxRetryCount); + kCloudPrintAPIMaxRetryCount, + std::string()); } } } diff --git a/printing/backend/win_helper.cc b/printing/backend/win_helper.cc index e63b45f..b163a65 100644 --- a/printing/backend/win_helper.cc +++ b/printing/backend/win_helper.cc @@ -37,6 +37,17 @@ typedef HRESULT (WINAPI *PTMergeAndValidatePrintTicketProc)( BSTR* error_message); typedef HRESULT (WINAPI *PTReleaseMemoryProc)(PVOID buffer); typedef HRESULT (WINAPI *PTCloseProviderProc)(HPTPROVIDER provider); +typedef HRESULT (WINAPI *StartXpsPrintJobProc)( + const LPCWSTR printer_name, + const LPCWSTR job_name, + const LPCWSTR output_file_name, + HANDLE progress_event, + HANDLE completion_event, + UINT8 *printable_pages_on, + UINT32 printable_pages_on_count, + IXpsPrintJob **xps_print_job, + IXpsPrintJobStream **document_stream, + IXpsPrintJobStream **print_ticket_stream); PTOpenProviderProc g_open_provider_proc = NULL; PTGetPrintCapabilitiesProc g_get_print_capabilities_proc = NULL; @@ -45,6 +56,7 @@ PTConvertPrintTicketToDevModeProc g_convert_print_ticket_to_devmode_proc = NULL; PTMergeAndValidatePrintTicketProc g_merge_and_validate_print_ticket_proc = NULL; PTReleaseMemoryProc g_release_memory_proc = NULL; PTCloseProviderProc g_close_provider_proc = NULL; +StartXpsPrintJobProc g_start_xps_print_job_proc = NULL; } namespace printing { @@ -207,4 +219,45 @@ ScopedXPSInitializer::~ScopedXPSInitializer() { initialized_ = false; } +bool XPSPrintModule::Init() { + static bool initialized = InitImpl(); + return initialized; +} + +bool XPSPrintModule::InitImpl() { + HMODULE xpsprint_module = LoadLibrary(L"xpsprint.dll"); + if (xpsprint_module == NULL) + return false; + g_start_xps_print_job_proc = reinterpret_cast<StartXpsPrintJobProc>( + GetProcAddress(xpsprint_module, "StartXpsPrintJob")); + if (!g_start_xps_print_job_proc) { + NOTREACHED(); + return false; + } + return true; +} + +HRESULT XPSPrintModule::StartXpsPrintJob( + const LPCWSTR printer_name, + const LPCWSTR job_name, + const LPCWSTR output_file_name, + HANDLE progress_event, + HANDLE completion_event, + UINT8 *printable_pages_on, + UINT32 printable_pages_on_count, + IXpsPrintJob **xps_print_job, + IXpsPrintJobStream **document_stream, + IXpsPrintJobStream **print_ticket_stream) { + return g_start_xps_print_job_proc(printer_name, + job_name, + output_file_name, + progress_event, + completion_event, + printable_pages_on, + printable_pages_on_count, + xps_print_job, + document_stream, + print_ticket_stream); +} + } // namespace printing diff --git a/printing/backend/win_helper.h b/printing/backend/win_helper.h index 891f833..28e57f7 100644 --- a/printing/backend/win_helper.h +++ b/printing/backend/win_helper.h @@ -9,6 +9,7 @@ #include <objidl.h> #include <winspool.h> #include <prntvpt.h> +#include <xpsprint.h> #include "base/string16.h" @@ -70,6 +71,30 @@ class ScopedXPSInitializer { bool initialized_; }; +// Wrapper class to wrap the XPS Print APIs (these are different from the PTxxx +// which deal with the XML Print Schema). This is needed because these +// APIs are only available on Windows 7 and higher. +class XPSPrintModule { + public: + // All the other methods can ONLY be called after a successful call to Init. + // Init can be called many times and by multiple threads. + static bool Init(); + static HRESULT StartXpsPrintJob( + const LPCWSTR printer_name, + const LPCWSTR job_name, + const LPCWSTR output_file_name, + HANDLE progress_event, + HANDLE completion_event, + UINT8 *printable_pages_on, + UINT32 printable_pages_on_count, + IXpsPrintJob **xps_print_job, + IXpsPrintJobStream **document_stream, + IXpsPrintJobStream **print_ticket_stream); + private: + XPSPrintModule() { } + static bool InitImpl(); +}; + } // namespace printing #endif // PRINTING_BACKEND_WIN_HELPER_H_ |