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_win.h"
7 #include "base/strings/utf_string_conversions.h"
8 #include "base/win/object_watcher.h"
9 #include "chrome/common/crash_keys.h"
10 #include "printing/backend/win_helper.h"
12 namespace cloud_print
{
16 class PrintSystemWatcherWin
: public base::win::ObjectWatcher::Delegate
{
18 PrintSystemWatcherWin()
22 ~PrintSystemWatcherWin() {
28 virtual ~Delegate() {}
29 virtual void OnPrinterAdded() = 0;
30 virtual void OnPrinterDeleted() = 0;
31 virtual void OnPrinterChanged() = 0;
32 virtual void OnJobChanged() = 0;
35 bool Start(const std::string
& printer_name
, Delegate
* delegate
) {
36 scoped_refptr
<printing::PrintBackend
> print_backend(
37 printing::PrintBackend::CreateInstance(NULL
));
38 printer_info_
= print_backend
->GetPrinterDriverInfo(printer_name
);
39 crash_keys::ScopedPrinterInfo
crash_key(printer_info_
);
42 // An empty printer name means watch the current server, we need to pass
43 // NULL to OpenPrinter.
44 LPTSTR printer_name_to_use
= NULL
;
45 std::wstring printer_name_wide
;
46 if (!printer_name
.empty()) {
47 printer_name_wide
= base::UTF8ToWide(printer_name
);
48 printer_name_to_use
= const_cast<LPTSTR
>(printer_name_wide
.c_str());
51 if (printer_
.OpenPrinter(printer_name_to_use
)) {
52 printer_change_
.Set(FindFirstPrinterChangeNotification(
53 printer_
, PRINTER_CHANGE_PRINTER
|PRINTER_CHANGE_JOB
, 0, NULL
));
54 if (printer_change_
.IsValid()) {
55 ret
= watcher_
.StartWatching(printer_change_
, this);
65 watcher_
.StopWatching();
67 printer_change_
.Close();
71 // base::ObjectWatcher::Delegate method
72 virtual void OnObjectSignaled(HANDLE object
) {
73 crash_keys::ScopedPrinterInfo
crash_key(printer_info_
);
75 FindNextPrinterChangeNotification(object
, &change
, NULL
, NULL
);
77 if (change
!= ((PRINTER_CHANGE_PRINTER
|PRINTER_CHANGE_JOB
) &
78 (~PRINTER_CHANGE_FAILED_CONNECTION_PRINTER
))) {
79 // For printer connections, we get spurious change notifications with
80 // all flags set except PRINTER_CHANGE_FAILED_CONNECTION_PRINTER.
82 if (change
& PRINTER_CHANGE_ADD_PRINTER
) {
83 delegate_
->OnPrinterAdded();
84 } else if (change
& PRINTER_CHANGE_DELETE_PRINTER
) {
85 delegate_
->OnPrinterDeleted();
86 } else if (change
& PRINTER_CHANGE_SET_PRINTER
) {
87 delegate_
->OnPrinterChanged();
89 if (change
& PRINTER_CHANGE_JOB
) {
90 delegate_
->OnJobChanged();
93 watcher_
.StartWatching(printer_change_
, this);
96 bool GetCurrentPrinterInfo(printing::PrinterBasicInfo
* printer_info
) {
98 return InitBasicPrinterInfo(printer_
, printer_info
);
102 base::win::ObjectWatcher watcher_
;
103 printing::ScopedPrinterHandle printer_
; // The printer being watched
104 // Returned by FindFirstPrinterChangeNotifier.
105 printing::ScopedPrinterChangeHandle printer_change_
;
106 Delegate
* delegate_
; // Delegate to notify
107 bool did_signal_
; // DoneWaiting was called
108 std::string printer_info_
; // For crash reporting.
111 class PrintServerWatcherWin
112 : public PrintSystem::PrintServerWatcher
,
113 public PrintSystemWatcherWin::Delegate
{
115 PrintServerWatcherWin() : delegate_(NULL
) {}
117 // PrintSystem::PrintServerWatcher implementation.
118 virtual bool StartWatching(
119 PrintSystem::PrintServerWatcher::Delegate
* delegate
) OVERRIDE
{
120 delegate_
= delegate
;
121 return watcher_
.Start(std::string(), this);
124 virtual bool StopWatching() OVERRIDE
{
125 bool ret
= watcher_
.Stop();
130 // PrintSystemWatcherWin::Delegate implementation.
131 virtual void OnPrinterAdded() OVERRIDE
{
132 delegate_
->OnPrinterAdded();
134 virtual void OnPrinterDeleted() OVERRIDE
{}
135 virtual void OnPrinterChanged() OVERRIDE
{}
136 virtual void OnJobChanged() OVERRIDE
{}
139 virtual ~PrintServerWatcherWin() {}
142 PrintSystem::PrintServerWatcher::Delegate
* delegate_
;
143 PrintSystemWatcherWin watcher_
;
145 DISALLOW_COPY_AND_ASSIGN(PrintServerWatcherWin
);
148 class PrinterWatcherWin
149 : public PrintSystem::PrinterWatcher
,
150 public PrintSystemWatcherWin::Delegate
{
152 explicit PrinterWatcherWin(const std::string
& printer_name
)
153 : printer_name_(printer_name
),
157 // PrintSystem::PrinterWatcher implementation.
158 virtual bool StartWatching(
159 PrintSystem::PrinterWatcher::Delegate
* delegate
) OVERRIDE
{
160 delegate_
= delegate
;
161 return watcher_
.Start(printer_name_
, this);
164 virtual bool StopWatching() OVERRIDE
{
165 bool ret
= watcher_
.Stop();
170 virtual bool GetCurrentPrinterInfo(
171 printing::PrinterBasicInfo
* printer_info
) OVERRIDE
{
172 return watcher_
.GetCurrentPrinterInfo(printer_info
);
175 // PrintSystemWatcherWin::Delegate implementation.
176 virtual void OnPrinterAdded() OVERRIDE
{
179 virtual void OnPrinterDeleted() OVERRIDE
{
180 delegate_
->OnPrinterDeleted();
182 virtual void OnPrinterChanged() OVERRIDE
{
183 delegate_
->OnPrinterChanged();
185 virtual void OnJobChanged() OVERRIDE
{
186 delegate_
->OnJobChanged();
190 virtual ~PrinterWatcherWin() {}
193 std::string printer_name_
;
194 PrintSystem::PrinterWatcher::Delegate
* delegate_
;
195 PrintSystemWatcherWin watcher_
;
197 DISALLOW_COPY_AND_ASSIGN(PrinterWatcherWin
);
202 PrintSystemWin::PrintSystemWin() {
203 print_backend_
= printing::PrintBackend::CreateInstance(NULL
);
206 PrintSystemWin::~PrintSystemWin() {
209 PrintSystem::PrintSystemResult
PrintSystemWin::EnumeratePrinters(
210 printing::PrinterList
* printer_list
) {
211 bool ret
= print_backend_
->EnumeratePrinters(printer_list
);
212 return PrintSystemResult(ret
, std::string());
215 bool PrintSystemWin::IsValidPrinter(const std::string
& printer_name
) {
216 return print_backend_
->IsValidPrinter(printer_name
);
219 bool PrintSystemWin::GetJobDetails(const std::string
& printer_name
,
220 PlatformJobId job_id
,
221 PrintJobDetails
*job_details
) {
222 crash_keys::ScopedPrinterInfo
crash_key(
223 print_backend_
->GetPrinterDriverInfo(printer_name
));
225 printing::ScopedPrinterHandle printer_handle
;
226 std::wstring printer_name_wide
= base::UTF8ToWide(printer_name
);
227 printer_handle
.OpenPrinter(printer_name_wide
.c_str());
228 DCHECK(printer_handle
.IsValid());
230 if (printer_handle
.IsValid()) {
231 DWORD bytes_needed
= 0;
232 GetJob(printer_handle
, job_id
, 1, NULL
, 0, &bytes_needed
);
233 DWORD last_error
= GetLastError();
234 if (ERROR_INVALID_PARAMETER
!= last_error
) {
235 // ERROR_INVALID_PARAMETER normally means that the job id is not valid.
236 DCHECK(last_error
== ERROR_INSUFFICIENT_BUFFER
);
237 scoped_ptr
<BYTE
[]> job_info_buffer(new BYTE
[bytes_needed
]);
238 if (GetJob(printer_handle
, job_id
, 1, job_info_buffer
.get(), bytes_needed
,
240 JOB_INFO_1
*job_info
=
241 reinterpret_cast<JOB_INFO_1
*>(job_info_buffer
.get());
242 if (job_info
->pStatus
) {
243 base::WideToUTF8(job_info
->pStatus
, wcslen(job_info
->pStatus
),
244 &job_details
->status_message
);
246 job_details
->platform_status_flags
= job_info
->Status
;
247 if ((job_info
->Status
& JOB_STATUS_COMPLETE
) ||
248 (job_info
->Status
& JOB_STATUS_PRINTED
)) {
249 job_details
->status
= PRINT_JOB_STATUS_COMPLETED
;
250 } else if (job_info
->Status
& JOB_STATUS_ERROR
) {
251 job_details
->status
= PRINT_JOB_STATUS_ERROR
;
253 job_details
->status
= PRINT_JOB_STATUS_IN_PROGRESS
;
255 job_details
->total_pages
= job_info
->TotalPages
;
256 job_details
->pages_printed
= job_info
->PagesPrinted
;
264 PrintSystem::PrintServerWatcher
*
265 PrintSystemWin::CreatePrintServerWatcher() {
266 return new PrintServerWatcherWin();
269 PrintSystem::PrinterWatcher
* PrintSystemWin::CreatePrinterWatcher(
270 const std::string
& printer_name
) {
271 DCHECK(!printer_name
.empty());
272 return new PrinterWatcherWin(printer_name
);
275 std::string
PrintSystemWin::GetPrinterDriverInfo(
276 const std::string
& printer_name
) const {
277 return print_backend_
->GetPrinterDriverInfo(printer_name
);
280 } // namespace cloud_print