license.bot | bf09a50 | 2008-08-24 00:55:55 | [diff] [blame] | 1 | // Copyright (c) 2006-2008 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. |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 4 | |
[email protected] | 8ff1d42 | 2009-07-07 21:31:39 | [diff] [blame] | 5 | #include "printing/printing_context.h" |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 6 | |
| 7 | #include <winspool.h> |
| 8 | |
| 9 | #include "base/file_util.h" |
[email protected] | dcccb94 | 2009-02-01 18:23:00 | [diff] [blame] | 10 | #include "base/message_loop.h" |
| 11 | #include "base/time.h" |
[email protected] | 5cca3a5 | 2008-08-19 22:35:29 | [diff] [blame] | 12 | #include "base/time_format.h" |
[email protected] | 8ff1d42 | 2009-07-07 21:31:39 | [diff] [blame] | 13 | #include "printing/printed_document.h" |
[email protected] | c399a8a | 2008-11-22 19:38:00 | [diff] [blame] | 14 | #include "skia/ext/platform_device_win.h" |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 15 | |
[email protected] | e1acf6f | 2008-10-27 20:43:33 | [diff] [blame] | 16 | using base::Time; |
| 17 | |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 18 | namespace { |
| 19 | |
| 20 | // Retrieves the content of a GetPrinter call. |
| 21 | void GetPrinterHelper(HANDLE printer, int level, scoped_array<uint8>* buffer) { |
| 22 | DWORD buf_size = 0; |
| 23 | GetPrinter(printer, level, NULL, 0, &buf_size); |
| 24 | if (buf_size) { |
| 25 | buffer->reset(new uint8[buf_size]); |
| 26 | memset(buffer->get(), 0, buf_size); |
| 27 | if (!GetPrinter(printer, level, buffer->get(), buf_size, &buf_size)) { |
| 28 | buffer->reset(); |
| 29 | } |
| 30 | } |
| 31 | } |
| 32 | |
| 33 | } // namespace |
| 34 | |
| 35 | namespace printing { |
| 36 | |
| 37 | class PrintingContext::CallbackHandler |
| 38 | : public IPrintDialogCallback, |
| 39 | public IObjectWithSite { |
| 40 | public: |
| 41 | CallbackHandler(PrintingContext& owner, HWND owner_hwnd) |
| 42 | : owner_(owner), |
| 43 | owner_hwnd_(owner_hwnd), |
| 44 | services_(NULL) { |
| 45 | } |
| 46 | |
| 47 | ~CallbackHandler() { |
| 48 | if (services_) |
| 49 | services_->Release(); |
| 50 | } |
| 51 | |
| 52 | IUnknown* ToIUnknown() { |
| 53 | return static_cast<IUnknown*>(static_cast<IPrintDialogCallback*>(this)); |
| 54 | } |
| 55 | |
| 56 | // IUnknown |
| 57 | virtual HRESULT WINAPI QueryInterface(REFIID riid, void**object) { |
| 58 | if (riid == IID_IUnknown) { |
| 59 | *object = ToIUnknown(); |
| 60 | } else if (riid == IID_IPrintDialogCallback) { |
| 61 | *object = static_cast<IPrintDialogCallback*>(this); |
| 62 | } else if (riid == IID_IObjectWithSite) { |
| 63 | *object = static_cast<IObjectWithSite*>(this); |
| 64 | } else { |
| 65 | return E_NOINTERFACE; |
| 66 | } |
| 67 | return S_OK; |
| 68 | } |
| 69 | |
| 70 | // No real ref counting. |
| 71 | virtual ULONG WINAPI AddRef() { |
| 72 | return 1; |
| 73 | } |
| 74 | virtual ULONG WINAPI Release() { |
| 75 | return 1; |
| 76 | } |
| 77 | |
| 78 | // IPrintDialogCallback methods |
| 79 | virtual HRESULT WINAPI InitDone() { |
| 80 | return S_OK; |
| 81 | } |
| 82 | |
| 83 | virtual HRESULT WINAPI SelectionChange() { |
| 84 | if (services_) { |
| 85 | // TODO(maruel): Get the devmode for the new printer with |
| 86 | // services_->GetCurrentDevMode(&devmode, &size), send that information |
| 87 | // back to our client and continue. The client needs to recalculate the |
| 88 | // number of rendered pages and send back this information here. |
| 89 | } |
| 90 | return S_OK; |
| 91 | } |
| 92 | |
| 93 | virtual HRESULT WINAPI HandleMessage(HWND dialog, |
| 94 | UINT message, |
| 95 | WPARAM wparam, |
| 96 | LPARAM lparam, |
| 97 | LRESULT* result) { |
| 98 | // Cheap way to retrieve the window handle. |
| 99 | if (!owner_.dialog_box_) { |
| 100 | // The handle we receive is the one of the groupbox in the General tab. We |
| 101 | // need to get the grand-father to get the dialog box handle. |
| 102 | owner_.dialog_box_ = GetAncestor(dialog, GA_ROOT); |
| 103 | // Trick to enable the owner window. This can cause issues with navigation |
| 104 | // events so it may have to be disabled if we don't fix the side-effects. |
| 105 | EnableWindow(owner_hwnd_, TRUE); |
| 106 | } |
| 107 | return S_FALSE; |
| 108 | } |
| 109 | |
| 110 | virtual HRESULT WINAPI SetSite(IUnknown* site) { |
| 111 | if (!site) { |
| 112 | DCHECK(services_); |
| 113 | services_->Release(); |
| 114 | services_ = NULL; |
| 115 | // The dialog box is destroying, PrintJob::Worker don't need the handle |
| 116 | // anymore. |
| 117 | owner_.dialog_box_ = NULL; |
| 118 | } else { |
| 119 | DCHECK(services_ == NULL); |
| 120 | HRESULT hr = site->QueryInterface(IID_IPrintDialogServices, |
| 121 | reinterpret_cast<void**>(&services_)); |
| 122 | DCHECK(SUCCEEDED(hr)); |
| 123 | } |
| 124 | return S_OK; |
| 125 | } |
| 126 | |
| 127 | virtual HRESULT WINAPI GetSite(REFIID riid, void** site) { |
| 128 | return E_NOTIMPL; |
| 129 | } |
| 130 | |
| 131 | private: |
| 132 | PrintingContext& owner_; |
| 133 | HWND owner_hwnd_; |
| 134 | IPrintDialogServices* services_; |
| 135 | |
| 136 | DISALLOW_EVIL_CONSTRUCTORS(CallbackHandler); |
| 137 | }; |
| 138 | |
| 139 | PrintingContext::PrintingContext() |
| 140 | : hdc_(NULL), |
[email protected] | 0ae80b89 | 2008-10-15 17:56:40 | [diff] [blame] | 141 | #ifndef NDEBUG |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 142 | page_number_(-1), |
| 143 | #endif |
| 144 | dialog_box_(NULL), |
| 145 | dialog_box_dismissed_(false), |
[email protected] | 8ff1d42 | 2009-07-07 21:31:39 | [diff] [blame] | 146 | in_print_job_(false), |
| 147 | abort_printing_(false) { |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 148 | } |
| 149 | |
| 150 | PrintingContext::~PrintingContext() { |
| 151 | ResetSettings(); |
| 152 | } |
| 153 | |
[email protected] | c8ad40c | 2009-06-08 17:05:21 | [diff] [blame] | 154 | PrintingContext::Result PrintingContext::AskUserForSettings( |
| 155 | HWND window, |
| 156 | int max_pages, |
| 157 | bool has_selection) { |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 158 | DCHECK(window); |
| 159 | DCHECK(!in_print_job_); |
| 160 | dialog_box_dismissed_ = false; |
| 161 | // Show the OS-dependent dialog box. |
| 162 | // If the user press |
| 163 | // - OK, the settings are reset and reinitialized with the new settings. OK is |
| 164 | // returned. |
| 165 | // - Apply then Cancel, the settings are reset and reinitialized with the new |
| 166 | // settings. CANCEL is returned. |
| 167 | // - Cancel, the settings are not changed, the previous setting, if it was |
| 168 | // initialized before, are kept. CANCEL is returned. |
| 169 | // On failure, the settings are reset and FAILED is returned. |
| 170 | PRINTDLGEX dialog_options = { sizeof(PRINTDLGEX) }; |
| 171 | dialog_options.hwndOwner = window; |
[email protected] | c8ad40c | 2009-06-08 17:05:21 | [diff] [blame] | 172 | // Disable options we don't support currently. |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 173 | // TODO(maruel): Reuse the previously loaded settings! |
| 174 | dialog_options.Flags = PD_RETURNDC | PD_USEDEVMODECOPIESANDCOLLATE | |
[email protected] | c8ad40c | 2009-06-08 17:05:21 | [diff] [blame] | 175 | PD_NOCURRENTPAGE | PD_HIDEPRINTTOFILE; |
| 176 | if (!has_selection) |
| 177 | dialog_options.Flags |= PD_NOSELECTION; |
| 178 | |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 179 | PRINTPAGERANGE ranges[32]; |
| 180 | dialog_options.nStartPage = START_PAGE_GENERAL; |
| 181 | if (max_pages) { |
| 182 | // Default initialize to print all the pages. |
| 183 | memset(ranges, 0, sizeof(ranges)); |
| 184 | ranges[0].nFromPage = 1; |
| 185 | ranges[0].nToPage = max_pages; |
| 186 | dialog_options.nPageRanges = 1; |
| 187 | dialog_options.nMaxPageRanges = arraysize(ranges); |
[email protected] | 3a0e4a3 | 2009-06-09 19:07:05 | [diff] [blame] | 188 | dialog_options.nMinPage = 1; |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 189 | dialog_options.nMaxPage = max_pages; |
| 190 | dialog_options.lpPageRanges = ranges; |
| 191 | } else { |
| 192 | // No need to bother, we don't know how many pages are available. |
| 193 | dialog_options.Flags |= PD_NOPAGENUMS; |
| 194 | } |
| 195 | |
| 196 | { |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 197 | if (PrintDlgEx(&dialog_options) != S_OK) { |
| 198 | ResetSettings(); |
| 199 | return FAILED; |
| 200 | } |
| 201 | } |
| 202 | // TODO(maruel): Support PD_PRINTTOFILE. |
| 203 | return ParseDialogResultEx(dialog_options); |
| 204 | } |
| 205 | |
| 206 | PrintingContext::Result PrintingContext::UseDefaultSettings() { |
| 207 | DCHECK(!in_print_job_); |
| 208 | |
| 209 | PRINTDLG dialog_options = { sizeof(PRINTDLG) }; |
| 210 | dialog_options.Flags = PD_RETURNDC | PD_RETURNDEFAULT; |
| 211 | if (PrintDlg(&dialog_options) == 0) { |
| 212 | ResetSettings(); |
| 213 | return FAILED; |
| 214 | } |
| 215 | return ParseDialogResult(dialog_options); |
| 216 | } |
| 217 | |
| 218 | PrintingContext::Result PrintingContext::InitWithSettings( |
| 219 | const PrintSettings& settings) { |
| 220 | DCHECK(!in_print_job_); |
| 221 | settings_ = settings; |
| 222 | // TODO(maruel): settings_->ToDEVMODE() |
| 223 | HANDLE printer; |
| 224 | if (!OpenPrinter(const_cast<wchar_t*>(settings_.device_name().c_str()), |
| 225 | &printer, |
| 226 | NULL)) |
| 227 | return FAILED; |
| 228 | |
| 229 | Result status = OK; |
| 230 | |
| 231 | if (!GetPrinterSettings(printer, settings_.device_name())) |
| 232 | status = FAILED; |
| 233 | |
| 234 | // Close the printer after retrieving the context. |
| 235 | ClosePrinter(printer); |
| 236 | |
| 237 | if (status != OK) |
| 238 | ResetSettings(); |
| 239 | return status; |
| 240 | } |
| 241 | |
| 242 | void PrintingContext::ResetSettings() { |
| 243 | if (hdc_ != NULL) { |
| 244 | DeleteDC(hdc_); |
| 245 | hdc_ = NULL; |
| 246 | } |
| 247 | settings_.Clear(); |
| 248 | in_print_job_ = false; |
| 249 | |
[email protected] | 0ae80b89 | 2008-10-15 17:56:40 | [diff] [blame] | 250 | #ifndef NDEBUG |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 251 | page_number_ = -1; |
| 252 | #endif |
| 253 | } |
| 254 | |
| 255 | PrintingContext::Result PrintingContext::NewDocument( |
| 256 | const std::wstring& document_name) { |
| 257 | DCHECK(!in_print_job_); |
| 258 | if (!hdc_) |
[email protected] | c8ad40c | 2009-06-08 17:05:21 | [diff] [blame] | 259 | return OnError(); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 260 | |
| 261 | // Set the flag used by the AbortPrintJob dialog procedure. |
| 262 | abort_printing_ = false; |
| 263 | |
| 264 | in_print_job_ = true; |
| 265 | |
| 266 | // Register the application's AbortProc function with GDI. |
| 267 | if (SP_ERROR == SetAbortProc(hdc_, &AbortProc)) |
[email protected] | c8ad40c | 2009-06-08 17:05:21 | [diff] [blame] | 268 | return OnError(); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 269 | |
| 270 | DOCINFO di = { sizeof(DOCINFO) }; |
| 271 | di.lpszDocName = document_name.c_str(); |
| 272 | |
| 273 | // Is there a debug dump directory specified? If so, force to print to a file. |
[email protected] | e1504d8 | 2009-07-03 15:27:15 | [diff] [blame] | 274 | std::wstring debug_dump_path = PrintedDocument::debug_dump_path(); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 275 | if (!debug_dump_path.empty()) { |
| 276 | // Create a filename. |
| 277 | std::wstring filename; |
| 278 | Time now(Time::Now()); |
[email protected] | 5cca3a5 | 2008-08-19 22:35:29 | [diff] [blame] | 279 | filename = base::TimeFormatShortDateNumeric(now); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 280 | filename += L"_"; |
[email protected] | 5cca3a5 | 2008-08-19 22:35:29 | [diff] [blame] | 281 | filename += base::TimeFormatTimeOfDay(now); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 282 | filename += L"_"; |
| 283 | filename += document_name; |
| 284 | filename += L"_"; |
| 285 | filename += L"buffer.prn"; |
| 286 | file_util::ReplaceIllegalCharacters(&filename, '_'); |
| 287 | file_util::AppendToPath(&debug_dump_path, filename); |
| 288 | di.lpszOutput = debug_dump_path.c_str(); |
| 289 | } |
| 290 | |
[email protected] | daee497 | 2009-07-09 14:28:24 | [diff] [blame^] | 291 | // No message loop running in unit tests. |
| 292 | DCHECK(!MessageLoop::current() ? true : |
| 293 | !MessageLoop::current()->NestableTasksAllowed()); |
| 294 | |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 295 | // Begin a print job by calling the StartDoc function. |
| 296 | // NOTE: StartDoc() starts a message loop. That causes a lot of problems with |
| 297 | // IPC. Make sure recursive task processing is disabled. |
| 298 | if (StartDoc(hdc_, &di) <= 0) |
[email protected] | c8ad40c | 2009-06-08 17:05:21 | [diff] [blame] | 299 | return OnError(); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 300 | |
[email protected] | 0ae80b89 | 2008-10-15 17:56:40 | [diff] [blame] | 301 | #ifndef NDEBUG |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 302 | page_number_ = 0; |
| 303 | #endif |
| 304 | return OK; |
| 305 | } |
| 306 | |
| 307 | PrintingContext::Result PrintingContext::NewPage() { |
| 308 | if (abort_printing_) |
| 309 | return CANCEL; |
| 310 | DCHECK(in_print_job_); |
| 311 | |
| 312 | // Inform the driver that the application is about to begin sending data. |
| 313 | if (StartPage(hdc_) <= 0) |
[email protected] | c8ad40c | 2009-06-08 17:05:21 | [diff] [blame] | 314 | return OnError(); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 315 | |
[email protected] | 0ae80b89 | 2008-10-15 17:56:40 | [diff] [blame] | 316 | #ifndef NDEBUG |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 317 | ++page_number_; |
| 318 | #endif |
| 319 | |
| 320 | return OK; |
| 321 | } |
| 322 | |
| 323 | PrintingContext::Result PrintingContext::PageDone() { |
| 324 | if (abort_printing_) |
| 325 | return CANCEL; |
| 326 | DCHECK(in_print_job_); |
| 327 | |
| 328 | if (EndPage(hdc_) <= 0) |
[email protected] | c8ad40c | 2009-06-08 17:05:21 | [diff] [blame] | 329 | return OnError(); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 330 | return OK; |
| 331 | } |
| 332 | |
| 333 | PrintingContext::Result PrintingContext::DocumentDone() { |
| 334 | if (abort_printing_) |
| 335 | return CANCEL; |
| 336 | DCHECK(in_print_job_); |
| 337 | |
| 338 | // Inform the driver that document has ended. |
| 339 | if (EndDoc(hdc_) <= 0) |
[email protected] | c8ad40c | 2009-06-08 17:05:21 | [diff] [blame] | 340 | return OnError(); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 341 | |
| 342 | ResetSettings(); |
| 343 | return OK; |
| 344 | } |
| 345 | |
| 346 | void PrintingContext::Cancel() { |
| 347 | abort_printing_ = true; |
| 348 | in_print_job_ = false; |
| 349 | if (hdc_) |
| 350 | CancelDC(hdc_); |
| 351 | DismissDialog(); |
| 352 | } |
| 353 | |
| 354 | void PrintingContext::DismissDialog() { |
| 355 | if (dialog_box_) { |
| 356 | DestroyWindow(dialog_box_); |
| 357 | dialog_box_dismissed_ = true; |
| 358 | } |
| 359 | } |
| 360 | |
[email protected] | c8ad40c | 2009-06-08 17:05:21 | [diff] [blame] | 361 | PrintingContext::Result PrintingContext::OnError() { |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 362 | // This will close hdc_ and clear settings_. |
| 363 | ResetSettings(); |
| 364 | return abort_printing_ ? CANCEL : FAILED; |
| 365 | } |
| 366 | |
| 367 | // static |
| 368 | BOOL PrintingContext::AbortProc(HDC hdc, int nCode) { |
| 369 | if (nCode) { |
| 370 | // TODO(maruel): Need a way to find the right instance to set. Should |
| 371 | // leverage PrintJobManager here? |
| 372 | // abort_printing_ = true; |
| 373 | } |
| 374 | return true; |
| 375 | } |
| 376 | |
| 377 | bool PrintingContext::InitializeSettings(const DEVMODE& dev_mode, |
| 378 | const std::wstring& new_device_name, |
| 379 | const PRINTPAGERANGE* ranges, |
[email protected] | c8ad40c | 2009-06-08 17:05:21 | [diff] [blame] | 380 | int number_ranges, |
| 381 | bool selection_only) { |
[email protected] | bd63dc9 | 2009-06-14 15:14:53 | [diff] [blame] | 382 | skia::PlatformDevice::InitializeDC(hdc_); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 383 | DCHECK(GetDeviceCaps(hdc_, CLIPCAPS)); |
| 384 | DCHECK(GetDeviceCaps(hdc_, RASTERCAPS) & RC_STRETCHDIB); |
| 385 | DCHECK(GetDeviceCaps(hdc_, RASTERCAPS) & RC_BITMAP64); |
| 386 | // Some printers don't advertise these. |
| 387 | // DCHECK(GetDeviceCaps(hdc_, RASTERCAPS) & RC_SCALING); |
| 388 | // DCHECK(GetDeviceCaps(hdc_, SHADEBLENDCAPS) & SB_CONST_ALPHA); |
| 389 | // DCHECK(GetDeviceCaps(hdc_, SHADEBLENDCAPS) & SB_PIXEL_ALPHA); |
| 390 | |
| 391 | // StretchDIBits() support is needed for printing. |
| 392 | if (!(GetDeviceCaps(hdc_, RASTERCAPS) & RC_STRETCHDIB) || |
| 393 | !(GetDeviceCaps(hdc_, RASTERCAPS) & RC_BITMAP64)) { |
| 394 | NOTREACHED(); |
| 395 | ResetSettings(); |
| 396 | return false; |
| 397 | } |
| 398 | |
| 399 | DCHECK(!in_print_job_); |
| 400 | DCHECK(hdc_); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 401 | PageRanges ranges_vector; |
[email protected] | 8227045 | 2009-06-19 15:58:01 | [diff] [blame] | 402 | if (!selection_only) { |
| 403 | // Convert the PRINTPAGERANGE array to a PrintSettings::PageRanges vector. |
| 404 | ranges_vector.reserve(number_ranges); |
| 405 | for (int i = 0; i < number_ranges; ++i) { |
| 406 | PageRange range; |
| 407 | // Transfer from 1-based to 0-based. |
| 408 | range.from = ranges[i].nFromPage - 1; |
| 409 | range.to = ranges[i].nToPage - 1; |
| 410 | ranges_vector.push_back(range); |
| 411 | } |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 412 | } |
[email protected] | c8ad40c | 2009-06-08 17:05:21 | [diff] [blame] | 413 | settings_.Init(hdc_, |
| 414 | dev_mode, |
| 415 | ranges_vector, |
| 416 | new_device_name, |
| 417 | selection_only); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 418 | return true; |
| 419 | } |
| 420 | |
| 421 | bool PrintingContext::GetPrinterSettings(HANDLE printer, |
| 422 | const std::wstring& device_name) { |
| 423 | DCHECK(!in_print_job_); |
| 424 | scoped_array<uint8> buffer; |
| 425 | |
| 426 | // A PRINTER_INFO_9 structure specifying the per-user default printer |
| 427 | // settings. |
| 428 | GetPrinterHelper(printer, 9, &buffer); |
| 429 | if (buffer.get()) { |
| 430 | PRINTER_INFO_9* info_9 = reinterpret_cast<PRINTER_INFO_9*>(buffer.get()); |
| 431 | if (info_9->pDevMode != NULL) { |
| 432 | if (!AllocateContext(device_name, info_9->pDevMode)) { |
| 433 | ResetSettings(); |
| 434 | return false; |
| 435 | } |
[email protected] | c8ad40c | 2009-06-08 17:05:21 | [diff] [blame] | 436 | return InitializeSettings(*info_9->pDevMode, device_name, NULL, 0, false); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 437 | } |
| 438 | buffer.reset(); |
| 439 | } |
| 440 | |
| 441 | // A PRINTER_INFO_8 structure specifying the global default printer settings. |
| 442 | GetPrinterHelper(printer, 8, &buffer); |
| 443 | if (buffer.get()) { |
| 444 | PRINTER_INFO_8* info_8 = reinterpret_cast<PRINTER_INFO_8*>(buffer.get()); |
| 445 | if (info_8->pDevMode != NULL) { |
| 446 | if (!AllocateContext(device_name, info_8->pDevMode)) { |
| 447 | ResetSettings(); |
| 448 | return false; |
| 449 | } |
[email protected] | c8ad40c | 2009-06-08 17:05:21 | [diff] [blame] | 450 | return InitializeSettings(*info_8->pDevMode, device_name, NULL, 0, false); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 451 | } |
| 452 | buffer.reset(); |
| 453 | } |
| 454 | |
| 455 | // A PRINTER_INFO_2 structure specifying the driver's default printer |
| 456 | // settings. |
| 457 | GetPrinterHelper(printer, 2, &buffer); |
| 458 | if (buffer.get()) { |
| 459 | PRINTER_INFO_2* info_2 = reinterpret_cast<PRINTER_INFO_2*>(buffer.get()); |
| 460 | if (info_2->pDevMode != NULL) { |
| 461 | if (!AllocateContext(device_name, info_2->pDevMode)) { |
| 462 | ResetSettings(); |
| 463 | return false; |
| 464 | } |
[email protected] | c8ad40c | 2009-06-08 17:05:21 | [diff] [blame] | 465 | return InitializeSettings(*info_2->pDevMode, device_name, NULL, 0, false); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 466 | } |
| 467 | buffer.reset(); |
| 468 | } |
| 469 | // Failed to retrieve the printer settings. |
| 470 | ResetSettings(); |
| 471 | return false; |
| 472 | } |
| 473 | |
| 474 | bool PrintingContext::AllocateContext(const std::wstring& printer_name, |
| 475 | const DEVMODE* dev_mode) { |
| 476 | hdc_ = CreateDC(L"WINSPOOL", printer_name.c_str(), NULL, dev_mode); |
| 477 | DCHECK(hdc_); |
| 478 | return hdc_ != NULL; |
| 479 | } |
| 480 | |
| 481 | PrintingContext::Result PrintingContext::ParseDialogResultEx( |
| 482 | const PRINTDLGEX& dialog_options) { |
| 483 | // If the user clicked OK or Apply then Cancel, but not only Cancel. |
| 484 | if (dialog_options.dwResultAction != PD_RESULT_CANCEL) { |
| 485 | // Start fresh. |
| 486 | ResetSettings(); |
| 487 | |
| 488 | DEVMODE* dev_mode = NULL; |
| 489 | if (dialog_options.hDevMode) { |
| 490 | dev_mode = |
| 491 | reinterpret_cast<DEVMODE*>(GlobalLock(dialog_options.hDevMode)); |
| 492 | DCHECK(dev_mode); |
| 493 | } |
| 494 | |
| 495 | std::wstring device_name; |
| 496 | if (dialog_options.hDevNames) { |
| 497 | DEVNAMES* dev_names = |
| 498 | reinterpret_cast<DEVNAMES*>(GlobalLock(dialog_options.hDevNames)); |
| 499 | DCHECK(dev_names); |
| 500 | if (dev_names) { |
| 501 | device_name = |
| 502 | reinterpret_cast<const wchar_t*>( |
| 503 | reinterpret_cast<const wchar_t*>(dev_names) + |
| 504 | dev_names->wDeviceOffset); |
| 505 | GlobalUnlock(dialog_options.hDevNames); |
| 506 | } |
| 507 | } |
| 508 | |
| 509 | bool success = false; |
| 510 | if (dev_mode && !device_name.empty()) { |
| 511 | hdc_ = dialog_options.hDC; |
[email protected] | c8ad40c | 2009-06-08 17:05:21 | [diff] [blame] | 512 | PRINTPAGERANGE* page_ranges = NULL; |
| 513 | DWORD num_page_ranges = 0; |
| 514 | bool print_selection_only = false; |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 515 | if (dialog_options.Flags & PD_PAGENUMS) { |
[email protected] | c8ad40c | 2009-06-08 17:05:21 | [diff] [blame] | 516 | page_ranges = dialog_options.lpPageRanges; |
| 517 | num_page_ranges = dialog_options.nPageRanges; |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 518 | } |
[email protected] | c8ad40c | 2009-06-08 17:05:21 | [diff] [blame] | 519 | if (dialog_options.Flags & PD_SELECTION) { |
| 520 | print_selection_only = true; |
| 521 | } |
| 522 | success = InitializeSettings(*dev_mode, |
| 523 | device_name, |
| 524 | dialog_options.lpPageRanges, |
| 525 | dialog_options.nPageRanges, |
| 526 | print_selection_only); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 527 | } |
| 528 | |
| 529 | if (!success && dialog_options.hDC) { |
| 530 | DeleteDC(dialog_options.hDC); |
| 531 | hdc_ = NULL; |
| 532 | } |
| 533 | |
| 534 | if (dev_mode) { |
| 535 | GlobalUnlock(dialog_options.hDevMode); |
| 536 | } |
| 537 | } else { |
| 538 | if (dialog_options.hDC) { |
| 539 | DeleteDC(dialog_options.hDC); |
| 540 | } |
| 541 | } |
| 542 | |
| 543 | if (dialog_options.hDevMode != NULL) |
| 544 | GlobalFree(dialog_options.hDevMode); |
| 545 | if (dialog_options.hDevNames != NULL) |
| 546 | GlobalFree(dialog_options.hDevNames); |
| 547 | |
| 548 | switch (dialog_options.dwResultAction) { |
| 549 | case PD_RESULT_PRINT: |
| 550 | return hdc_ ? OK : FAILED; |
| 551 | case PD_RESULT_APPLY: |
| 552 | return hdc_ ? CANCEL : FAILED; |
| 553 | case PD_RESULT_CANCEL: |
| 554 | return CANCEL; |
| 555 | default: |
| 556 | return FAILED; |
| 557 | } |
| 558 | } |
| 559 | |
| 560 | PrintingContext::Result PrintingContext::ParseDialogResult( |
| 561 | const PRINTDLG& dialog_options) { |
| 562 | // If the user clicked OK or Apply then Cancel, but not only Cancel. |
| 563 | // Start fresh. |
| 564 | ResetSettings(); |
| 565 | |
| 566 | DEVMODE* dev_mode = NULL; |
| 567 | if (dialog_options.hDevMode) { |
| 568 | dev_mode = |
| 569 | reinterpret_cast<DEVMODE*>(GlobalLock(dialog_options.hDevMode)); |
| 570 | DCHECK(dev_mode); |
| 571 | } |
| 572 | |
| 573 | std::wstring device_name; |
| 574 | if (dialog_options.hDevNames) { |
| 575 | DEVNAMES* dev_names = |
| 576 | reinterpret_cast<DEVNAMES*>(GlobalLock(dialog_options.hDevNames)); |
| 577 | DCHECK(dev_names); |
| 578 | if (dev_names) { |
| 579 | device_name = |
| 580 | reinterpret_cast<const wchar_t*>( |
| 581 | reinterpret_cast<const wchar_t*>(dev_names) + |
| 582 | dev_names->wDeviceOffset); |
| 583 | GlobalUnlock(dialog_options.hDevNames); |
| 584 | } |
| 585 | } |
| 586 | |
| 587 | bool success = false; |
| 588 | if (dev_mode && !device_name.empty()) { |
| 589 | hdc_ = dialog_options.hDC; |
[email protected] | c8ad40c | 2009-06-08 17:05:21 | [diff] [blame] | 590 | success = InitializeSettings(*dev_mode, device_name, NULL, 0, false); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 591 | } |
| 592 | |
| 593 | if (!success && dialog_options.hDC) { |
| 594 | DeleteDC(dialog_options.hDC); |
| 595 | hdc_ = NULL; |
| 596 | } |
| 597 | |
| 598 | if (dev_mode) { |
| 599 | GlobalUnlock(dialog_options.hDevMode); |
| 600 | } |
| 601 | |
| 602 | if (dialog_options.hDevMode != NULL) |
| 603 | GlobalFree(dialog_options.hDevMode); |
| 604 | if (dialog_options.hDevNames != NULL) |
| 605 | GlobalFree(dialog_options.hDevNames); |
| 606 | |
| 607 | return hdc_ ? OK : FAILED; |
| 608 | } |
| 609 | |
| 610 | } // namespace printing |