OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/service/cloud_print/print_system.h" | 5 #include "chrome/service/cloud_print/print_system.h" |
6 | 6 |
7 #include <windows.h> | 7 #include <windows.h> |
8 #include <objidl.h> | 8 #include <objidl.h> |
9 #include <ocidl.h> | 9 #include <ocidl.h> |
10 #include <olectl.h> | 10 #include <olectl.h> |
11 #include <prntvpt.h> | 11 #include <prntvpt.h> |
12 #include <winspool.h> | 12 #include <winspool.h> |
13 | 13 |
14 #include "base/lock.h" | 14 #include "base/lock.h" |
| 15 #include "base/file_util.h" |
15 #include "base/object_watcher.h" | 16 #include "base/object_watcher.h" |
16 #include "base/scoped_bstr_win.h" | 17 #include "base/scoped_bstr_win.h" |
17 #include "base/scoped_comptr_win.h" | 18 #include "base/scoped_comptr_win.h" |
18 #include "base/scoped_handle_win.h" | 19 #include "base/scoped_handle_win.h" |
19 #include "base/scoped_ptr.h" | 20 #include "base/scoped_ptr.h" |
20 #include "base/utf_string_conversions.h" | 21 #include "base/utf_string_conversions.h" |
| 22 #include "chrome/service/service_process.h" |
| 23 #include "chrome/service/service_utility_process_host.h" |
| 24 #include "gfx/rect.h" |
| 25 #include "printing/native_metafile.h" |
| 26 #include "printing/page_range.h" |
21 | 27 |
22 #pragma comment(lib, "prntvpt.lib") | 28 #pragma comment(lib, "prntvpt.lib") |
23 #pragma comment(lib, "rpcrt4.lib") | 29 #pragma comment(lib, "rpcrt4.lib") |
24 | 30 |
25 namespace { | 31 namespace { |
26 | 32 |
27 class DevMode { | 33 class DevMode { |
28 public: | 34 public: |
29 DevMode() : dm_(NULL) {} | 35 DevMode() : dm_(NULL) {} |
30 ~DevMode() { Free(); } | 36 ~DevMode() { Free(); } |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
110 if (SUCCEEDED(hr)) { | 116 if (SUCCEEDED(hr)) { |
111 dev_mode->Allocate(size); | 117 dev_mode->Allocate(size); |
112 memcpy(dev_mode->dm_, dm, size); | 118 memcpy(dev_mode->dm_, dm, size); |
113 PTReleaseMemory(dm); | 119 PTReleaseMemory(dm); |
114 } | 120 } |
115 PTCloseProvider(provider); | 121 PTCloseProvider(provider); |
116 } | 122 } |
117 return hr; | 123 return hr; |
118 } | 124 } |
119 | 125 |
120 HRESULT PrintPdf2DC(HDC dc, const FilePath& pdf_filename) { | |
121 HRESULT hr = E_NOTIMPL; | |
122 // TODO(sanjeevr): Implement this. | |
123 NOTIMPLEMENTED(); | |
124 return hr; | |
125 } | |
126 | |
127 } // namespace | 126 } // namespace |
128 | 127 |
129 namespace cloud_print { | 128 namespace cloud_print { |
130 | 129 |
131 class PrintSystemWatcherWin | 130 class PrintSystemWatcherWin |
132 : public base::ObjectWatcher::Delegate { | 131 : public base::ObjectWatcher::Delegate { |
133 public: | 132 public: |
134 PrintSystemWatcherWin() | 133 PrintSystemWatcherWin() |
135 : printer_(NULL), printer_change_(NULL), delegate_(NULL) { | 134 : printer_(NULL), printer_change_(NULL), delegate_(NULL) { |
136 } | 135 } |
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
248 class PrintSystemWin : public PrintSystem { | 247 class PrintSystemWin : public PrintSystem { |
249 public: | 248 public: |
250 virtual void EnumeratePrinters(PrinterList* printer_list); | 249 virtual void EnumeratePrinters(PrinterList* printer_list); |
251 | 250 |
252 virtual bool GetPrinterCapsAndDefaults(const std::string& printer_name, | 251 virtual bool GetPrinterCapsAndDefaults(const std::string& printer_name, |
253 PrinterCapsAndDefaults* printer_info); | 252 PrinterCapsAndDefaults* printer_info); |
254 | 253 |
255 virtual bool ValidatePrintTicket(const std::string& printer_name, | 254 virtual bool ValidatePrintTicket(const std::string& printer_name, |
256 const std::string& print_ticket_data); | 255 const std::string& print_ticket_data); |
257 | 256 |
258 virtual bool SpoolPrintJob(const std::string& print_ticket, | |
259 const FilePath& print_data_file_path, | |
260 const std::string& print_data_mime_type, | |
261 const std::string& printer_name, | |
262 const std::string& job_title, | |
263 PlatformJobId* job_id_ret); | |
264 | |
265 virtual bool GetJobDetails(const std::string& printer_name, | 257 virtual bool GetJobDetails(const std::string& printer_name, |
266 PlatformJobId job_id, | 258 PlatformJobId job_id, |
267 PrintJobDetails *job_details); | 259 PrintJobDetails *job_details); |
268 | 260 |
269 virtual bool IsValidPrinter(const std::string& printer_name); | 261 virtual bool IsValidPrinter(const std::string& printer_name); |
270 | 262 |
271 class PrintServerWatcherWin | 263 class PrintServerWatcherWin |
272 : public PrintSystem::PrintServerWatcher, | 264 : public PrintSystem::PrintServerWatcher, |
273 public PrintSystemWatcherWinDelegate { | 265 public PrintSystemWatcherWinDelegate { |
274 public: | 266 public: |
275 PrintServerWatcherWin() {} | 267 PrintServerWatcherWin() {} |
276 | 268 |
277 // PrintSystem::PrintServerWatcher interface | 269 // PrintSystem::PrintServerWatcher interface |
278 virtual bool StartWatching( | 270 virtual bool StartWatching( |
279 PrintSystem::PrintServerWatcher::Delegate* delegate) { | 271 PrintSystem::PrintServerWatcher::Delegate* delegate) { |
280 delegate_ = delegate; | 272 delegate_ = delegate; |
281 return watcher_.Start(std::string(), this); | 273 return watcher_.Start(std::string(), this); |
282 } | 274 } |
283 virtual bool StopWatching() { | 275 virtual bool StopWatching() { |
284 bool ret = watcher_.Stop(); | 276 bool ret = watcher_.Stop(); |
285 delegate_ = NULL; | 277 delegate_ = NULL; |
286 return ret; | 278 return ret; |
287 } | 279 } |
288 | 280 |
289 // PrintSystemWatcherWin::Delegate interface | 281 // PrintSystemWatcherWin::Delegate interface |
290 virtual void OnPrinterAdded() { | 282 virtual void OnPrinterAdded() { |
291 delegate_->OnPrinterAdded(); | 283 delegate_->OnPrinterAdded(); |
292 } | 284 } |
293 virtual void OnPrinterDeleted() { | 285 virtual void OnPrinterDeleted() { |
294 NOTREACHED(); | |
295 } | 286 } |
296 virtual void OnPrinterChanged() { | 287 virtual void OnPrinterChanged() { |
297 NOTREACHED(); | |
298 } | 288 } |
299 virtual void OnJobChanged() { | 289 virtual void OnJobChanged() { |
300 NOTREACHED(); | |
301 } | 290 } |
302 | 291 |
303 private: | 292 private: |
304 PrintSystem::PrintServerWatcher::Delegate* delegate_; | 293 PrintSystem::PrintServerWatcher::Delegate* delegate_; |
305 PrintSystemWatcherWin watcher_; | 294 PrintSystemWatcherWin watcher_; |
306 DISALLOW_COPY_AND_ASSIGN(PrintServerWatcherWin); | 295 DISALLOW_COPY_AND_ASSIGN(PrintServerWatcherWin); |
307 }; | 296 }; |
308 | 297 |
309 class PrinterWatcherWin | 298 class PrinterWatcherWin |
310 : public PrintSystem::PrinterWatcher, | 299 : public PrintSystem::PrinterWatcher, |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
342 delegate_->OnJobChanged(); | 331 delegate_->OnJobChanged(); |
343 } | 332 } |
344 | 333 |
345 private: | 334 private: |
346 std::string printer_name_; | 335 std::string printer_name_; |
347 PrintSystem::PrinterWatcher::Delegate* delegate_; | 336 PrintSystem::PrinterWatcher::Delegate* delegate_; |
348 PrintSystemWatcherWin watcher_; | 337 PrintSystemWatcherWin watcher_; |
349 DISALLOW_COPY_AND_ASSIGN(PrinterWatcherWin); | 338 DISALLOW_COPY_AND_ASSIGN(PrinterWatcherWin); |
350 }; | 339 }; |
351 | 340 |
| 341 class JobSpoolerWin : public PrintSystem::JobSpooler { |
| 342 public: |
| 343 JobSpoolerWin() : core_(new Core) {} |
| 344 // PrintSystem::JobSpooler implementation. |
| 345 virtual bool Spool(const std::string& print_ticket, |
| 346 const FilePath& print_data_file_path, |
| 347 const std::string& print_data_mime_type, |
| 348 const std::string& printer_name, |
| 349 const std::string& job_title, |
| 350 JobSpooler::Delegate* delegate) { |
| 351 return core_->Spool(print_ticket, print_data_file_path, |
| 352 print_data_mime_type, printer_name, job_title, |
| 353 delegate); |
| 354 } |
| 355 private: |
| 356 // We use a Core class because we want a separate RefCountedThreadSafe |
| 357 // implementation for ServiceUtilityProcessHost::Client. |
| 358 class Core : public ServiceUtilityProcessHost::Client { |
| 359 public: |
| 360 Core() |
| 361 : last_page_printed_(-1), job_id_(-1), delegate_(NULL), saved_dc_(0) { |
| 362 } |
| 363 ~Core() { |
| 364 } |
| 365 bool Spool(const std::string& print_ticket, |
| 366 const FilePath& print_data_file_path, |
| 367 const std::string& print_data_mime_type, |
| 368 const std::string& printer_name, |
| 369 const std::string& job_title, |
| 370 JobSpooler::Delegate* delegate) { |
| 371 if (delegate_) { |
| 372 // We are already in the process of printing. |
| 373 NOTREACHED(); |
| 374 return false; |
| 375 } |
| 376 last_page_printed_ = -1; |
| 377 // We only support PDFs for now. |
| 378 if (print_data_mime_type != "application/pdf") { |
| 379 NOTREACHED(); |
| 380 return false; |
| 381 } |
| 382 |
| 383 if (!InitXPSModule()) { |
| 384 // TODO(sanjeevr): Handle legacy proxy case (with no prntvpt.dll) |
| 385 return false; |
| 386 } |
| 387 DevMode pt_dev_mode; |
| 388 HRESULT hr = PrintTicketToDevMode(printer_name, print_ticket, |
| 389 &pt_dev_mode); |
| 390 if (FAILED(hr)) { |
| 391 NOTREACHED(); |
| 392 return false; |
| 393 } |
| 394 HDC dc = CreateDC(L"WINSPOOL", UTF8ToWide(printer_name).c_str(), |
| 395 NULL, pt_dev_mode.dm_); |
| 396 if (!dc) { |
| 397 NOTREACHED(); |
| 398 return false; |
| 399 } |
| 400 hr = E_FAIL; |
| 401 DOCINFO di = {0}; |
| 402 di.cbSize = sizeof(DOCINFO); |
| 403 std::wstring doc_name = UTF8ToWide(job_title); |
| 404 di.lpszDocName = doc_name.c_str(); |
| 405 job_id_ = StartDoc(dc, &di); |
| 406 if (SP_ERROR == job_id_) |
| 407 return false; |
| 408 |
| 409 printer_dc_.Set(dc); |
| 410 |
| 411 int printer_dpi = ::GetDeviceCaps(printer_dc_.Get(), LOGPIXELSX); |
| 412 saved_dc_ = SaveDC(printer_dc_.Get()); |
| 413 SetGraphicsMode(printer_dc_.Get(), GM_ADVANCED); |
| 414 XFORM xform = {0}; |
| 415 xform.eM11 = xform.eM22 = static_cast<float>(printer_dpi) / |
| 416 static_cast<float>(GetDeviceCaps(GetDC(NULL), LOGPIXELSX)); |
| 417 ModifyWorldTransform(printer_dc_.Get(), &xform, MWT_LEFTMULTIPLY); |
| 418 print_data_file_path_ = print_data_file_path; |
| 419 delegate_ = delegate; |
| 420 RenderNextPDFPages(); |
| 421 return true; |
| 422 } |
| 423 |
| 424 // ServiceUtilityProcessHost::Client implementation. |
| 425 virtual void OnRenderPDFPagesToMetafileSucceeded( |
| 426 const printing::NativeMetafile& metafile, |
| 427 int highest_rendered_page_number) { |
| 428 metafile.SafePlayback(printer_dc_.Get()); |
| 429 bool done_printing = (highest_rendered_page_number != |
| 430 last_page_printed_ + kPageCountPerBatch); |
| 431 last_page_printed_ = highest_rendered_page_number; |
| 432 if (done_printing) |
| 433 PrintJobDone(); |
| 434 else |
| 435 RenderNextPDFPages(); |
| 436 } |
| 437 virtual void OnRenderPDFPagesToMetafileFailed() { |
| 438 PrintJobDone(); |
| 439 } |
| 440 virtual void OnChildDied() { |
| 441 PrintJobDone(); |
| 442 } |
| 443 private: |
| 444 void PrintJobDone() { |
| 445 // If there is no delegate, then there is nothing pending to process. |
| 446 if (!delegate_) |
| 447 return; |
| 448 RestoreDC(printer_dc_.Get(), saved_dc_); |
| 449 EndDoc(printer_dc_.Get()); |
| 450 if (-1 == last_page_printed_) { |
| 451 delegate_->OnJobSpoolFailed(); |
| 452 } else { |
| 453 delegate_->OnJobSpoolSucceeded(job_id_); |
| 454 } |
| 455 delegate_ = NULL; |
| 456 } |
| 457 void RenderNextPDFPages() { |
| 458 printing::PageRange range; |
| 459 // Render 10 pages at a time. |
| 460 range.from = last_page_printed_ + 1; |
| 461 range.to = last_page_printed_ + kPageCountPerBatch; |
| 462 std::vector<printing::PageRange> page_ranges; |
| 463 page_ranges.push_back(range); |
| 464 |
| 465 int printer_dpi = ::GetDeviceCaps(printer_dc_.Get(), LOGPIXELSX); |
| 466 int dc_width = GetDeviceCaps(printer_dc_.Get(), PHYSICALWIDTH); |
| 467 int dc_height = GetDeviceCaps(printer_dc_.Get(), PHYSICALHEIGHT); |
| 468 gfx::Rect render_area(0, 0, dc_width, dc_height); |
| 469 g_service_process->io_thread()->message_loop_proxy()->PostTask( |
| 470 FROM_HERE, |
| 471 NewRunnableMethod( |
| 472 this, |
| 473 &JobSpoolerWin::Core::RenderPDFPagesInSandbox, |
| 474 print_data_file_path_, |
| 475 render_area, |
| 476 printer_dpi, |
| 477 page_ranges, |
| 478 base::MessageLoopProxy::CreateForCurrentThread())); |
| 479 } |
| 480 // Called on the service process IO thread. |
| 481 void RenderPDFPagesInSandbox( |
| 482 const FilePath& pdf_path, const gfx::Rect& render_area, |
| 483 int render_dpi, const std::vector<printing::PageRange>& page_ranges, |
| 484 const scoped_refptr<base::MessageLoopProxy>& |
| 485 client_message_loop_proxy) { |
| 486 DCHECK(g_service_process->io_thread()->message_loop_proxy()-> |
| 487 BelongsToCurrentThread()); |
| 488 scoped_ptr<ServiceUtilityProcessHost> utility_host( |
| 489 new ServiceUtilityProcessHost(this, client_message_loop_proxy)); |
| 490 if (utility_host->StartRenderPDFPagesToMetafile(pdf_path, |
| 491 render_area, |
| 492 render_dpi, |
| 493 page_ranges)) { |
| 494 // The object will self-destruct when the child process dies. |
| 495 utility_host.release(); |
| 496 } |
| 497 } |
| 498 static const int kPageCountPerBatch = 10; |
| 499 int last_page_printed_; |
| 500 PlatformJobId job_id_; |
| 501 PrintSystem::JobSpooler::Delegate* delegate_; |
| 502 int saved_dc_; |
| 503 ScopedHDC printer_dc_; |
| 504 FilePath print_data_file_path_; |
| 505 DISALLOW_COPY_AND_ASSIGN(JobSpoolerWin::Core); |
| 506 }; |
| 507 scoped_refptr<Core> core_; |
| 508 DISALLOW_COPY_AND_ASSIGN(JobSpoolerWin); |
| 509 }; |
| 510 |
352 virtual PrintSystem::PrintServerWatcher* CreatePrintServerWatcher(); | 511 virtual PrintSystem::PrintServerWatcher* CreatePrintServerWatcher(); |
353 virtual PrintSystem::PrinterWatcher* CreatePrinterWatcher( | 512 virtual PrintSystem::PrinterWatcher* CreatePrinterWatcher( |
354 const std::string& printer_name); | 513 const std::string& printer_name); |
| 514 virtual PrintSystem::JobSpooler* CreateJobSpooler(); |
355 }; | 515 }; |
356 | 516 |
357 void PrintSystemWin::EnumeratePrinters(PrinterList* printer_list) { | 517 void PrintSystemWin::EnumeratePrinters(PrinterList* printer_list) { |
358 DCHECK(printer_list); | 518 DCHECK(printer_list); |
359 DWORD bytes_needed = 0; | 519 DWORD bytes_needed = 0; |
360 DWORD count_returned = 0; | 520 DWORD count_returned = 0; |
361 BOOL ret = EnumPrinters(PRINTER_ENUM_LOCAL|PRINTER_ENUM_CONNECTIONS, NULL, 2, | 521 BOOL ret = EnumPrinters(PRINTER_ENUM_LOCAL|PRINTER_ENUM_CONNECTIONS, NULL, 2, |
362 NULL, 0, &bytes_needed, &count_returned); | 522 NULL, 0, &bytes_needed, &count_returned); |
363 if (0 != bytes_needed) { | 523 if (0 != bytes_needed) { |
364 scoped_ptr<BYTE> printer_info_buffer(new BYTE[bytes_needed]); | 524 scoped_ptr<BYTE> printer_info_buffer(new BYTE[bytes_needed]); |
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
479 print_ticket_stream.get(), | 639 print_ticket_stream.get(), |
480 NULL, | 640 NULL, |
481 kPTJobScope, | 641 kPTJobScope, |
482 result_ticket_stream.get(), | 642 result_ticket_stream.get(), |
483 error.Receive())); | 643 error.Receive())); |
484 PTCloseProvider(provider); | 644 PTCloseProvider(provider); |
485 } | 645 } |
486 return ret; | 646 return ret; |
487 } | 647 } |
488 | 648 |
489 bool PrintSystemWin::SpoolPrintJob(const std::string& print_ticket, | |
490 const FilePath& print_data_file_path, | |
491 const std::string& print_data_mime_type, | |
492 const std::string& printer_name, | |
493 const std::string& job_title, | |
494 PlatformJobId* job_id_ret) { | |
495 if (!InitXPSModule()) { | |
496 // TODO(sanjeevr): Handle legacy proxy case (with no prntvpt.dll) | |
497 return false; | |
498 } | |
499 DevMode pt_dev_mode; | |
500 HRESULT hr = PrintTicketToDevMode(printer_name, print_ticket, &pt_dev_mode); | |
501 if (FAILED(hr)) { | |
502 NOTREACHED(); | |
503 return false; | |
504 } | |
505 ScopedHDC dc(CreateDC(L"WINSPOOL", UTF8ToWide(printer_name).c_str(), NULL, | |
506 pt_dev_mode.dm_)); | |
507 if (!dc.Get()) { | |
508 NOTREACHED(); | |
509 return false; | |
510 } | |
511 hr = E_FAIL; | |
512 DOCINFO di = {0}; | |
513 di.cbSize = sizeof(DOCINFO); | |
514 std::wstring doc_name = UTF8ToWide(job_title); | |
515 di.lpszDocName = doc_name.c_str(); | |
516 int job_id = StartDoc(dc.Get(), &di); | |
517 if (SP_ERROR != job_id) { | |
518 if (print_data_mime_type == "application/pdf") { | |
519 hr = PrintPdf2DC(dc.Get(), print_data_file_path); | |
520 } else { | |
521 NOTREACHED(); | |
522 } | |
523 EndDoc(dc.Get()); | |
524 if (SUCCEEDED(hr) && job_id_ret) { | |
525 *job_id_ret = job_id; | |
526 } | |
527 } | |
528 return SUCCEEDED(hr); | |
529 } | |
530 | |
531 bool PrintSystemWin::GetJobDetails(const std::string& printer_name, | 649 bool PrintSystemWin::GetJobDetails(const std::string& printer_name, |
532 PlatformJobId job_id, | 650 PlatformJobId job_id, |
533 PrintJobDetails *job_details) { | 651 PrintJobDetails *job_details) { |
534 DCHECK(job_details); | 652 DCHECK(job_details); |
535 HANDLE printer_handle = NULL; | 653 HANDLE printer_handle = NULL; |
536 std::wstring printer_name_wide = UTF8ToWide(printer_name); | 654 std::wstring printer_name_wide = UTF8ToWide(printer_name); |
537 OpenPrinter(const_cast<LPTSTR>(printer_name_wide.c_str()), &printer_handle, | 655 OpenPrinter(const_cast<LPTSTR>(printer_name_wide.c_str()), &printer_handle, |
538 NULL); | 656 NULL); |
539 DCHECK(printer_handle); | 657 DCHECK(printer_handle); |
540 bool ret = false; | 658 bool ret = false; |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
590 PrintSystemWin::CreatePrintServerWatcher() { | 708 PrintSystemWin::CreatePrintServerWatcher() { |
591 return new PrintServerWatcherWin(); | 709 return new PrintServerWatcherWin(); |
592 } | 710 } |
593 | 711 |
594 PrintSystem::PrinterWatcher* PrintSystemWin::CreatePrinterWatcher( | 712 PrintSystem::PrinterWatcher* PrintSystemWin::CreatePrinterWatcher( |
595 const std::string& printer_name) { | 713 const std::string& printer_name) { |
596 DCHECK(!printer_name.empty()); | 714 DCHECK(!printer_name.empty()); |
597 return new PrinterWatcherWin(printer_name); | 715 return new PrinterWatcherWin(printer_name); |
598 } | 716 } |
599 | 717 |
| 718 PrintSystem::JobSpooler* |
| 719 PrintSystemWin::CreateJobSpooler() { |
| 720 return new JobSpoolerWin(); |
| 721 } |
| 722 |
600 std::string PrintSystem::GenerateProxyId() { | 723 std::string PrintSystem::GenerateProxyId() { |
601 GUID proxy_id = {0}; | 724 GUID proxy_id = {0}; |
602 HRESULT hr = UuidCreate(&proxy_id); | 725 HRESULT hr = UuidCreate(&proxy_id); |
603 DCHECK(SUCCEEDED(hr)); | 726 DCHECK(SUCCEEDED(hr)); |
604 wchar_t* proxy_id_as_string = NULL; | 727 wchar_t* proxy_id_as_string = NULL; |
605 UuidToString(&proxy_id, reinterpret_cast<RPC_WSTR *>(&proxy_id_as_string)); | 728 UuidToString(&proxy_id, reinterpret_cast<RPC_WSTR *>(&proxy_id_as_string)); |
606 DCHECK(proxy_id_as_string); | 729 DCHECK(proxy_id_as_string); |
607 std::string ret; | 730 std::string ret; |
608 WideToUTF8(proxy_id_as_string, wcslen(proxy_id_as_string), &ret); | 731 WideToUTF8(proxy_id_as_string, wcslen(proxy_id_as_string), &ret); |
609 RpcStringFree(reinterpret_cast<RPC_WSTR *>(&proxy_id_as_string)); | 732 RpcStringFree(reinterpret_cast<RPC_WSTR *>(&proxy_id_as_string)); |
610 return ret; | 733 return ret; |
611 } | 734 } |
612 | 735 |
613 scoped_refptr<PrintSystem> PrintSystem::CreateInstance( | 736 scoped_refptr<PrintSystem> PrintSystem::CreateInstance( |
614 const DictionaryValue* print_system_settings) { | 737 const DictionaryValue* print_system_settings) { |
615 return new PrintSystemWin; | 738 return new PrintSystemWin; |
616 } | 739 } |
617 | 740 |
618 } // namespace cloud_print | 741 } // namespace cloud_print |
619 | 742 |
OLD | NEW |