chromeos: dbus: add Bluetooth properties support
[chromium-blink-merge.git] / printing / printing_context_win.cc
blob46093e77b41f0019180cf87a7db8978dff2da4b2
1 // Copyright (c) 2011 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 "printing/printing_context_win.h"
7 #include <winspool.h>
9 #include <algorithm>
11 #include "base/i18n/file_util_icu.h"
12 #include "base/i18n/time_formatting.h"
13 #include "base/message_loop.h"
14 #include "base/time.h"
15 #include "base/utf_string_conversions.h"
16 #include "base/values.h"
17 #include "printing/print_job_constants.h"
18 #include "printing/print_settings_initializer_win.h"
19 #include "printing/printed_document.h"
20 #include "printing/units.h"
21 #include "skia/ext/platform_device.h"
23 using base::Time;
25 namespace {
27 // Constants for setting default PDF settings.
28 const int kPDFDpi = 300; // 300 dpi
29 // LETTER: 8.5 x 11 inches
30 const int kPDFLetterWidth = 8.5 * kPDFDpi;
31 const int kPDFLetterHeight = 11 * kPDFDpi;
32 // LEGAL: 8.5 x 14 inches
33 const int kPDFLegalWidth = 8.5 * kPDFDpi;
34 const int kPDFLegalHeight = 14 * kPDFDpi;
35 // A4: 8.27 x 11.69 inches
36 const int kPDFA4Width = 8.27 * kPDFDpi;
37 const int kPDFA4Height = 11.69 * kPDFDpi;
38 // A3: 11.69 x 16.54 inches
39 const int kPDFA3Width = 11.69 * kPDFDpi;
40 const int kPDFA3Height = 16.54 * kPDFDpi;
42 // Retrieves the printer's PRINTER_INFO_* structure.
43 // Output |level| can be 9 (user-default), 8 (admin-default), or 2
44 // (printer-default).
45 // |devmode| is a pointer points to the start of DEVMODE structure in
46 // |buffer|.
47 bool GetPrinterInfo(HANDLE printer,
48 const std::wstring &device_name,
49 int* level,
50 scoped_array<uint8>* buffer,
51 DEVMODE** dev_mode) {
52 DCHECK(buffer);
54 // A PRINTER_INFO_9 structure specifying the per-user default printer
55 // settings.
56 printing::PrintingContextWin::GetPrinterHelper(printer, 9, buffer);
57 if (buffer->get()) {
58 PRINTER_INFO_9* info_9 = reinterpret_cast<PRINTER_INFO_9*>(buffer->get());
59 if (info_9->pDevMode != NULL) {
60 *level = 9;
61 *dev_mode = info_9->pDevMode;
62 return true;
64 buffer->reset();
67 // A PRINTER_INFO_8 structure specifying the global default printer settings.
68 printing::PrintingContextWin::GetPrinterHelper(printer, 8, buffer);
69 if (buffer->get()) {
70 PRINTER_INFO_8* info_8 = reinterpret_cast<PRINTER_INFO_8*>(buffer->get());
71 if (info_8->pDevMode != NULL) {
72 *level = 8;
73 *dev_mode = info_8->pDevMode;
74 return true;
76 buffer->reset();
79 // A PRINTER_INFO_2 structure specifying the driver's default printer
80 // settings.
81 printing::PrintingContextWin::GetPrinterHelper(printer, 2, buffer);
82 if (buffer->get()) {
83 PRINTER_INFO_2* info_2 = reinterpret_cast<PRINTER_INFO_2*>(buffer->get());
84 if (info_2->pDevMode != NULL) {
85 *level = 2;
86 *dev_mode = info_2->pDevMode;
87 return true;
89 buffer->reset();
92 return false;
95 } // anonymous namespace
97 namespace printing {
99 class PrintingContextWin::CallbackHandler : public IPrintDialogCallback,
100 public IObjectWithSite {
101 public:
102 CallbackHandler(PrintingContextWin& owner, HWND owner_hwnd)
103 : owner_(owner),
104 owner_hwnd_(owner_hwnd),
105 services_(NULL) {
108 ~CallbackHandler() {
109 if (services_)
110 services_->Release();
113 IUnknown* ToIUnknown() {
114 return static_cast<IUnknown*>(static_cast<IPrintDialogCallback*>(this));
117 // IUnknown
118 virtual HRESULT WINAPI QueryInterface(REFIID riid, void**object) {
119 if (riid == IID_IUnknown) {
120 *object = ToIUnknown();
121 } else if (riid == IID_IPrintDialogCallback) {
122 *object = static_cast<IPrintDialogCallback*>(this);
123 } else if (riid == IID_IObjectWithSite) {
124 *object = static_cast<IObjectWithSite*>(this);
125 } else {
126 return E_NOINTERFACE;
128 return S_OK;
131 // No real ref counting.
132 virtual ULONG WINAPI AddRef() {
133 return 1;
135 virtual ULONG WINAPI Release() {
136 return 1;
139 // IPrintDialogCallback methods
140 virtual HRESULT WINAPI InitDone() {
141 return S_OK;
144 virtual HRESULT WINAPI SelectionChange() {
145 if (services_) {
146 // TODO(maruel): Get the devmode for the new printer with
147 // services_->GetCurrentDevMode(&devmode, &size), send that information
148 // back to our client and continue. The client needs to recalculate the
149 // number of rendered pages and send back this information here.
151 return S_OK;
154 virtual HRESULT WINAPI HandleMessage(HWND dialog,
155 UINT message,
156 WPARAM wparam,
157 LPARAM lparam,
158 LRESULT* result) {
159 // Cheap way to retrieve the window handle.
160 if (!owner_.dialog_box_) {
161 // The handle we receive is the one of the groupbox in the General tab. We
162 // need to get the grand-father to get the dialog box handle.
163 owner_.dialog_box_ = GetAncestor(dialog, GA_ROOT);
164 // Trick to enable the owner window. This can cause issues with navigation
165 // events so it may have to be disabled if we don't fix the side-effects.
166 EnableWindow(owner_hwnd_, TRUE);
168 return S_FALSE;
171 virtual HRESULT WINAPI SetSite(IUnknown* site) {
172 if (!site) {
173 DCHECK(services_);
174 services_->Release();
175 services_ = NULL;
176 // The dialog box is destroying, PrintJob::Worker don't need the handle
177 // anymore.
178 owner_.dialog_box_ = NULL;
179 } else {
180 DCHECK(services_ == NULL);
181 HRESULT hr = site->QueryInterface(IID_IPrintDialogServices,
182 reinterpret_cast<void**>(&services_));
183 DCHECK(SUCCEEDED(hr));
185 return S_OK;
188 virtual HRESULT WINAPI GetSite(REFIID riid, void** site) {
189 return E_NOTIMPL;
192 private:
193 PrintingContextWin& owner_;
194 HWND owner_hwnd_;
195 IPrintDialogServices* services_;
197 DISALLOW_COPY_AND_ASSIGN(CallbackHandler);
200 // static
201 PrintingContext* PrintingContext::Create(const std::string& app_locale) {
202 return static_cast<PrintingContext*>(new PrintingContextWin(app_locale));
205 PrintingContextWin::PrintingContextWin(const std::string& app_locale)
206 : PrintingContext(app_locale),
207 context_(NULL),
208 dialog_box_(NULL),
209 print_dialog_func_(&PrintDlgEx) {
212 PrintingContextWin::~PrintingContextWin() {
213 ReleaseContext();
216 void PrintingContextWin::AskUserForSettings(
217 gfx::NativeView view, int max_pages, bool has_selection,
218 const PrintSettingsCallback& callback) {
219 #if !defined(USE_AURA)
220 DCHECK(!in_print_job_);
221 dialog_box_dismissed_ = false;
223 HWND window;
224 if (!view || !IsWindow(view)) {
225 // TODO(maruel): bug 1214347 Get the right browser window instead.
226 window = GetDesktopWindow();
227 } else {
228 window = GetAncestor(view, GA_ROOTOWNER);
230 DCHECK(window);
232 // Show the OS-dependent dialog box.
233 // If the user press
234 // - OK, the settings are reset and reinitialized with the new settings. OK is
235 // returned.
236 // - Apply then Cancel, the settings are reset and reinitialized with the new
237 // settings. CANCEL is returned.
238 // - Cancel, the settings are not changed, the previous setting, if it was
239 // initialized before, are kept. CANCEL is returned.
240 // On failure, the settings are reset and FAILED is returned.
241 PRINTDLGEX dialog_options = { sizeof(PRINTDLGEX) };
242 dialog_options.hwndOwner = window;
243 // Disable options we don't support currently.
244 // TODO(maruel): Reuse the previously loaded settings!
245 dialog_options.Flags = PD_RETURNDC | PD_USEDEVMODECOPIESANDCOLLATE |
246 PD_NOCURRENTPAGE | PD_HIDEPRINTTOFILE;
247 if (!has_selection)
248 dialog_options.Flags |= PD_NOSELECTION;
250 PRINTPAGERANGE ranges[32];
251 dialog_options.nStartPage = START_PAGE_GENERAL;
252 if (max_pages) {
253 // Default initialize to print all the pages.
254 memset(ranges, 0, sizeof(ranges));
255 ranges[0].nFromPage = 1;
256 ranges[0].nToPage = max_pages;
257 dialog_options.nPageRanges = 1;
258 dialog_options.nMaxPageRanges = arraysize(ranges);
259 dialog_options.nMinPage = 1;
260 dialog_options.nMaxPage = max_pages;
261 dialog_options.lpPageRanges = ranges;
262 } else {
263 // No need to bother, we don't know how many pages are available.
264 dialog_options.Flags |= PD_NOPAGENUMS;
267 if ((*print_dialog_func_)(&dialog_options) != S_OK) {
268 ResetSettings();
269 callback.Run(FAILED);
272 // TODO(maruel): Support PD_PRINTTOFILE.
273 callback.Run(ParseDialogResultEx(dialog_options));
274 #endif
277 PrintingContext::Result PrintingContextWin::UseDefaultSettings() {
278 DCHECK(!in_print_job_);
280 PRINTDLG dialog_options = { sizeof(PRINTDLG) };
281 dialog_options.Flags = PD_RETURNDC | PD_RETURNDEFAULT;
282 if (PrintDlg(&dialog_options))
283 return ParseDialogResult(dialog_options);
285 // No default printer configured, do we have any printers at all?
286 DWORD bytes_needed = 0;
287 DWORD count_returned = 0;
288 (void)::EnumPrinters(PRINTER_ENUM_LOCAL|PRINTER_ENUM_CONNECTIONS,
289 NULL, 2, NULL, 0, &bytes_needed, &count_returned);
290 if (bytes_needed) {
291 DCHECK(bytes_needed >= count_returned * sizeof(PRINTER_INFO_2));
292 scoped_array<BYTE> printer_info_buffer(new BYTE[bytes_needed]);
293 BOOL ret = ::EnumPrinters(PRINTER_ENUM_LOCAL|PRINTER_ENUM_CONNECTIONS,
294 NULL, 2, printer_info_buffer.get(),
295 bytes_needed, &bytes_needed,
296 &count_returned);
297 if (ret && count_returned) { // have printers
298 // Open the first successfully found printer.
299 for (DWORD count = 0; count < count_returned; ++count) {
300 PRINTER_INFO_2* info_2 = reinterpret_cast<PRINTER_INFO_2*>(
301 printer_info_buffer.get() + count * sizeof(PRINTER_INFO_2));
302 std::wstring printer_name = info_2->pPrinterName;
303 if (info_2->pDevMode == NULL || printer_name.length() == 0)
304 continue;
305 if (!AllocateContext(printer_name, info_2->pDevMode, &context_))
306 break;
307 if (InitializeSettings(*info_2->pDevMode, printer_name,
308 NULL, 0, false)) {
309 break;
311 ReleaseContext();
313 if (context_)
314 return OK;
318 ResetSettings();
319 return FAILED;
322 PrintingContext::Result PrintingContextWin::UpdatePrinterSettings(
323 const DictionaryValue& job_settings,
324 const PageRanges& ranges) {
325 DCHECK(!in_print_job_);
327 bool collate;
328 int color;
329 bool landscape;
330 bool print_to_pdf;
331 bool is_cloud_dialog;
332 int copies;
333 int duplex_mode;
334 string16 device_name;
336 if (!job_settings.GetBoolean(kSettingLandscape, &landscape) ||
337 !job_settings.GetBoolean(kSettingCollate, &collate) ||
338 !job_settings.GetInteger(kSettingColor, &color) ||
339 !job_settings.GetBoolean(kSettingPrintToPDF, &print_to_pdf) ||
340 !job_settings.GetInteger(kSettingDuplexMode, &duplex_mode) ||
341 !job_settings.GetInteger(kSettingCopies, &copies) ||
342 !job_settings.GetString(kSettingDeviceName, &device_name) ||
343 !job_settings.GetBoolean(kSettingCloudPrintDialog, &is_cloud_dialog)) {
344 return OnError();
347 bool print_to_cloud = job_settings.HasKey(kSettingCloudPrintId);
349 if (print_to_pdf || print_to_cloud || is_cloud_dialog) {
350 // Default fallback to Letter size.
351 gfx::Size paper_size;
352 gfx::Rect paper_rect;
353 paper_size.SetSize(kPDFLetterWidth, kPDFLetterHeight);
355 // Get settings from locale. Paper type buffer length is at most 4.
356 const int paper_type_buffer_len = 4;
357 wchar_t paper_type_buffer[paper_type_buffer_len] = {0};
358 GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_IPAPERSIZE, paper_type_buffer,
359 paper_type_buffer_len);
360 if (wcslen(paper_type_buffer)) { // The call succeeded.
361 int paper_code = _wtoi(paper_type_buffer);
362 switch (paper_code) {
363 case DMPAPER_LEGAL:
364 paper_size.SetSize(kPDFLegalWidth, kPDFLegalHeight);
365 break;
366 case DMPAPER_A4:
367 paper_size.SetSize(kPDFA4Width, kPDFA4Height);
368 break;
369 case DMPAPER_A3:
370 paper_size.SetSize(kPDFA3Width, kPDFA3Height);
371 break;
372 default: // DMPAPER_LETTER is used for default fallback.
373 break;
376 paper_rect.SetRect(0, 0, paper_size.width(), paper_size.height());
377 settings_.SetPrinterPrintableArea(paper_size, paper_rect, kPDFDpi);
378 settings_.set_dpi(kPDFDpi);
379 settings_.SetOrientation(landscape);
380 settings_.ranges = ranges;
381 return OK;
384 HANDLE printer;
385 LPWSTR device_name_wide = const_cast<wchar_t*>(device_name.c_str());
386 if (!OpenPrinter(device_name_wide, &printer, NULL))
387 return OnError();
389 // Make printer changes local to Chrome.
390 // See MSDN documentation regarding DocumentProperties.
391 scoped_array<uint8> buffer;
392 DEVMODE* dev_mode = NULL;
393 LONG buffer_size = DocumentProperties(NULL, printer, device_name_wide,
394 NULL, NULL, 0);
395 if (buffer_size > 0) {
396 buffer.reset(new uint8[buffer_size]);
397 memset(buffer.get(), 0, buffer_size);
398 if (DocumentProperties(NULL, printer, device_name_wide,
399 reinterpret_cast<PDEVMODE>(buffer.get()), NULL,
400 DM_OUT_BUFFER) == IDOK) {
401 dev_mode = reinterpret_cast<PDEVMODE>(buffer.get());
404 if (dev_mode == NULL) {
405 buffer.reset();
406 ClosePrinter(printer);
407 return OnError();
410 if (color == GRAY)
411 dev_mode->dmColor = DMCOLOR_MONOCHROME;
412 else
413 dev_mode->dmColor = DMCOLOR_COLOR;
415 dev_mode->dmCopies = std::max(copies, 1);
416 if (dev_mode->dmCopies > 1) // do not change collate unless multiple copies
417 dev_mode->dmCollate = collate ? DMCOLLATE_TRUE : DMCOLLATE_FALSE;
418 switch (duplex_mode) {
419 case LONG_EDGE:
420 dev_mode->dmDuplex = DMDUP_VERTICAL;
421 break;
422 case SHORT_EDGE:
423 dev_mode->dmDuplex = DMDUP_HORIZONTAL;
424 break;
425 case SIMPLEX:
426 dev_mode->dmDuplex = DMDUP_SIMPLEX;
427 break;
428 default: // UNKNOWN_DUPLEX_MODE
429 break;
431 dev_mode->dmOrientation = landscape ? DMORIENT_LANDSCAPE : DMORIENT_PORTRAIT;
433 // Update data using DocumentProperties.
434 if (DocumentProperties(NULL, printer, device_name_wide, dev_mode, dev_mode,
435 DM_IN_BUFFER | DM_OUT_BUFFER) != IDOK) {
436 ClosePrinter(printer);
437 return OnError();
440 // Set printer then refresh printer settings.
441 if (!AllocateContext(device_name, dev_mode, &context_)) {
442 ClosePrinter(printer);
443 return OnError();
445 PrintSettingsInitializerWin::InitPrintSettings(context_, *dev_mode,
446 ranges, device_name,
447 false, &settings_);
448 ClosePrinter(printer);
449 return OK;
452 PrintingContext::Result PrintingContextWin::InitWithSettings(
453 const PrintSettings& settings) {
454 DCHECK(!in_print_job_);
456 settings_ = settings;
458 // TODO(maruel): settings_.ToDEVMODE()
459 HANDLE printer;
460 if (!OpenPrinter(const_cast<wchar_t*>(settings_.device_name().c_str()),
461 &printer,
462 NULL))
463 return FAILED;
465 Result status = OK;
467 if (!GetPrinterSettings(printer, settings_.device_name()))
468 status = FAILED;
470 // Close the printer after retrieving the context.
471 ClosePrinter(printer);
473 if (status != OK)
474 ResetSettings();
475 return status;
478 PrintingContext::Result PrintingContextWin::NewDocument(
479 const string16& document_name) {
480 DCHECK(!in_print_job_);
481 if (!context_)
482 return OnError();
484 // Set the flag used by the AbortPrintJob dialog procedure.
485 abort_printing_ = false;
487 in_print_job_ = true;
489 // Register the application's AbortProc function with GDI.
490 if (SP_ERROR == SetAbortProc(context_, &AbortProc))
491 return OnError();
493 DOCINFO di = { sizeof(DOCINFO) };
494 const std::wstring& document_name_wide = UTF16ToWide(document_name);
495 di.lpszDocName = document_name_wide.c_str();
497 // Is there a debug dump directory specified? If so, force to print to a file.
498 FilePath debug_dump_path = PrintedDocument::debug_dump_path();
499 if (!debug_dump_path.empty()) {
500 // Create a filename.
501 std::wstring filename;
502 Time now(Time::Now());
503 filename = base::TimeFormatShortDateNumeric(now);
504 filename += L"_";
505 filename += base::TimeFormatTimeOfDay(now);
506 filename += L"_";
507 filename += UTF16ToWide(document_name);
508 filename += L"_";
509 filename += L"buffer.prn";
510 file_util::ReplaceIllegalCharactersInPath(&filename, '_');
511 debug_dump_path.Append(filename);
512 di.lpszOutput = debug_dump_path.value().c_str();
515 // No message loop running in unit tests.
516 DCHECK(!MessageLoop::current() ? true :
517 !MessageLoop::current()->NestableTasksAllowed());
519 // Begin a print job by calling the StartDoc function.
520 // NOTE: StartDoc() starts a message loop. That causes a lot of problems with
521 // IPC. Make sure recursive task processing is disabled.
522 if (StartDoc(context_, &di) <= 0)
523 return OnError();
525 return OK;
528 PrintingContext::Result PrintingContextWin::NewPage() {
529 if (abort_printing_)
530 return CANCEL;
531 DCHECK(context_);
532 DCHECK(in_print_job_);
534 // Intentional No-op. NativeMetafile::SafePlayback takes care of calling
535 // ::StartPage().
537 return OK;
540 PrintingContext::Result PrintingContextWin::PageDone() {
541 if (abort_printing_)
542 return CANCEL;
543 DCHECK(in_print_job_);
545 // Intentional No-op. NativeMetafile::SafePlayback takes care of calling
546 // ::EndPage().
548 return OK;
551 PrintingContext::Result PrintingContextWin::DocumentDone() {
552 if (abort_printing_)
553 return CANCEL;
554 DCHECK(in_print_job_);
555 DCHECK(context_);
557 // Inform the driver that document has ended.
558 if (EndDoc(context_) <= 0)
559 return OnError();
561 ResetSettings();
562 return OK;
565 void PrintingContextWin::Cancel() {
566 abort_printing_ = true;
567 in_print_job_ = false;
568 if (context_)
569 CancelDC(context_);
570 if (dialog_box_) {
571 DestroyWindow(dialog_box_);
572 dialog_box_dismissed_ = true;
576 void PrintingContextWin::ReleaseContext() {
577 if (context_) {
578 DeleteDC(context_);
579 context_ = NULL;
583 gfx::NativeDrawingContext PrintingContextWin::context() const {
584 return context_;
587 // static
588 BOOL PrintingContextWin::AbortProc(HDC hdc, int nCode) {
589 if (nCode) {
590 // TODO(maruel): Need a way to find the right instance to set. Should
591 // leverage PrintJobManager here?
592 // abort_printing_ = true;
594 return true;
597 bool PrintingContextWin::InitializeSettings(const DEVMODE& dev_mode,
598 const std::wstring& new_device_name,
599 const PRINTPAGERANGE* ranges,
600 int number_ranges,
601 bool selection_only) {
602 skia::InitializeDC(context_);
603 DCHECK(GetDeviceCaps(context_, CLIPCAPS));
604 DCHECK(GetDeviceCaps(context_, RASTERCAPS) & RC_STRETCHDIB);
605 DCHECK(GetDeviceCaps(context_, RASTERCAPS) & RC_BITMAP64);
606 // Some printers don't advertise these.
607 // DCHECK(GetDeviceCaps(context_, RASTERCAPS) & RC_SCALING);
608 // DCHECK(GetDeviceCaps(context_, SHADEBLENDCAPS) & SB_CONST_ALPHA);
609 // DCHECK(GetDeviceCaps(context_, SHADEBLENDCAPS) & SB_PIXEL_ALPHA);
611 // StretchDIBits() support is needed for printing.
612 if (!(GetDeviceCaps(context_, RASTERCAPS) & RC_STRETCHDIB) ||
613 !(GetDeviceCaps(context_, RASTERCAPS) & RC_BITMAP64)) {
614 NOTREACHED();
615 ResetSettings();
616 return false;
619 DCHECK(!in_print_job_);
620 DCHECK(context_);
621 PageRanges ranges_vector;
622 if (!selection_only) {
623 // Convert the PRINTPAGERANGE array to a PrintSettings::PageRanges vector.
624 ranges_vector.reserve(number_ranges);
625 for (int i = 0; i < number_ranges; ++i) {
626 PageRange range;
627 // Transfer from 1-based to 0-based.
628 range.from = ranges[i].nFromPage - 1;
629 range.to = ranges[i].nToPage - 1;
630 ranges_vector.push_back(range);
634 PrintSettingsInitializerWin::InitPrintSettings(context_,
635 dev_mode,
636 ranges_vector,
637 new_device_name,
638 selection_only,
639 &settings_);
641 return true;
644 bool PrintingContextWin::GetPrinterSettings(HANDLE printer,
645 const std::wstring& device_name) {
646 DCHECK(!in_print_job_);
647 scoped_array<uint8> buffer;
648 int level = 0;
649 DEVMODE* dev_mode = NULL;
651 if (GetPrinterInfo(printer, device_name, &level, &buffer, &dev_mode) &&
652 AllocateContext(device_name, dev_mode, &context_)) {
653 return InitializeSettings(*dev_mode, device_name, NULL, 0, false);
656 buffer.reset();
657 ResetSettings();
658 return false;
661 // static
662 bool PrintingContextWin::AllocateContext(const std::wstring& device_name,
663 const DEVMODE* dev_mode,
664 gfx::NativeDrawingContext* context) {
665 *context = CreateDC(L"WINSPOOL", device_name.c_str(), NULL, dev_mode);
666 DCHECK(*context);
667 return *context != NULL;
670 PrintingContext::Result PrintingContextWin::ParseDialogResultEx(
671 const PRINTDLGEX& dialog_options) {
672 // If the user clicked OK or Apply then Cancel, but not only Cancel.
673 if (dialog_options.dwResultAction != PD_RESULT_CANCEL) {
674 // Start fresh.
675 ResetSettings();
677 DEVMODE* dev_mode = NULL;
678 if (dialog_options.hDevMode) {
679 dev_mode =
680 reinterpret_cast<DEVMODE*>(GlobalLock(dialog_options.hDevMode));
681 DCHECK(dev_mode);
684 std::wstring device_name;
685 if (dialog_options.hDevNames) {
686 DEVNAMES* dev_names =
687 reinterpret_cast<DEVNAMES*>(GlobalLock(dialog_options.hDevNames));
688 DCHECK(dev_names);
689 if (dev_names) {
690 device_name =
691 reinterpret_cast<const wchar_t*>(
692 reinterpret_cast<const wchar_t*>(dev_names) +
693 dev_names->wDeviceOffset);
694 GlobalUnlock(dialog_options.hDevNames);
698 bool success = false;
699 if (dev_mode && !device_name.empty()) {
700 context_ = dialog_options.hDC;
701 PRINTPAGERANGE* page_ranges = NULL;
702 DWORD num_page_ranges = 0;
703 bool print_selection_only = false;
704 if (dialog_options.Flags & PD_PAGENUMS) {
705 page_ranges = dialog_options.lpPageRanges;
706 num_page_ranges = dialog_options.nPageRanges;
708 if (dialog_options.Flags & PD_SELECTION) {
709 print_selection_only = true;
711 success = InitializeSettings(*dev_mode,
712 device_name,
713 page_ranges,
714 num_page_ranges,
715 print_selection_only);
718 if (!success && dialog_options.hDC) {
719 DeleteDC(dialog_options.hDC);
720 context_ = NULL;
723 if (dev_mode) {
724 GlobalUnlock(dialog_options.hDevMode);
726 } else {
727 if (dialog_options.hDC) {
728 DeleteDC(dialog_options.hDC);
732 if (dialog_options.hDevMode != NULL)
733 GlobalFree(dialog_options.hDevMode);
734 if (dialog_options.hDevNames != NULL)
735 GlobalFree(dialog_options.hDevNames);
737 switch (dialog_options.dwResultAction) {
738 case PD_RESULT_PRINT:
739 return context_ ? OK : FAILED;
740 case PD_RESULT_APPLY:
741 return context_ ? CANCEL : FAILED;
742 case PD_RESULT_CANCEL:
743 return CANCEL;
744 default:
745 return FAILED;
749 PrintingContext::Result PrintingContextWin::ParseDialogResult(
750 const PRINTDLG& dialog_options) {
751 // If the user clicked OK or Apply then Cancel, but not only Cancel.
752 // Start fresh.
753 ResetSettings();
755 DEVMODE* dev_mode = NULL;
756 if (dialog_options.hDevMode) {
757 dev_mode =
758 reinterpret_cast<DEVMODE*>(GlobalLock(dialog_options.hDevMode));
759 DCHECK(dev_mode);
762 std::wstring device_name;
763 if (dialog_options.hDevNames) {
764 DEVNAMES* dev_names =
765 reinterpret_cast<DEVNAMES*>(GlobalLock(dialog_options.hDevNames));
766 DCHECK(dev_names);
767 if (dev_names) {
768 device_name =
769 reinterpret_cast<const wchar_t*>(
770 reinterpret_cast<const wchar_t*>(dev_names) +
771 dev_names->wDeviceOffset);
772 GlobalUnlock(dialog_options.hDevNames);
776 bool success = false;
777 if (dev_mode && !device_name.empty()) {
778 context_ = dialog_options.hDC;
779 success = InitializeSettings(*dev_mode, device_name, NULL, 0, false);
782 if (!success && dialog_options.hDC) {
783 DeleteDC(dialog_options.hDC);
784 context_ = NULL;
787 if (dev_mode) {
788 GlobalUnlock(dialog_options.hDevMode);
791 if (dialog_options.hDevMode != NULL)
792 GlobalFree(dialog_options.hDevMode);
793 if (dialog_options.hDevNames != NULL)
794 GlobalFree(dialog_options.hDevNames);
796 return context_ ? OK : FAILED;
799 // static
800 void PrintingContextWin::GetPrinterHelper(HANDLE printer, int level,
801 scoped_array<uint8>* buffer) {
802 DWORD buf_size = 0;
803 GetPrinter(printer, level, NULL, 0, &buf_size);
804 if (buf_size) {
805 buffer->reset(new uint8[buf_size]);
806 memset(buffer->get(), 0, buf_size);
807 if (!GetPrinter(printer, level, buffer->get(), buf_size, &buf_size)) {
808 buffer->reset();
813 } // namespace printing