diff options
-rw-r--r-- | chrome/service/cloud_print/print_system_win.cc | 13 | ||||
-rw-r--r-- | printing/backend/print_backend_win.cc | 3 | ||||
-rw-r--r-- | printing/backend/win_helper.cc | 32 | ||||
-rw-r--r-- | printing/backend/win_helper.h | 12 |
4 files changed, 54 insertions, 6 deletions
diff --git a/chrome/service/cloud_print/print_system_win.cc b/chrome/service/cloud_print/print_system_win.cc index d77217f..88c38d9 100644 --- a/chrome/service/cloud_print/print_system_win.cc +++ b/chrome/service/cloud_print/print_system_win.cc @@ -76,6 +76,11 @@ HRESULT PrintTicketToDevMode(const std::string& printer_name, const std::string& print_ticket, DevMode* dev_mode) { DCHECK(dev_mode); + printing::ScopedXPSInitializer xps_initializer; + if (!xps_initializer.initialized()) { + // TODO(sanjeevr): Handle legacy proxy case (with no prntvpt.dll) + return E_FAIL; + } ScopedComPtr<IStream> pt_stream; HRESULT hr = StreamFromPrintTicket(print_ticket, pt_stream.Receive()); @@ -383,10 +388,6 @@ class PrintSystemWin : public PrintSystem { return false; } - if (!printing::XPSModule::Init()) { - // TODO(sanjeevr): Handle legacy proxy case (with no prntvpt.dll) - return false; - } DevMode pt_dev_mode; HRESULT hr = PrintTicketToDevMode(printer_name, print_ticket, &pt_dev_mode); @@ -394,6 +395,7 @@ class PrintSystemWin : public PrintSystem { NOTREACHED(); return false; } + HDC dc = CreateDC(L"WINSPOOL", UTF8ToWide(printer_name).c_str(), NULL, pt_dev_mode.dm_); if (!dc) { @@ -618,7 +620,8 @@ bool PrintSystemWin::IsValidPrinter(const std::string& printer_name) { bool PrintSystemWin::ValidatePrintTicket( const std::string& printer_name, const std::string& print_ticket_data) { - if (!printing::XPSModule::Init()) { + printing::ScopedXPSInitializer xps_initializer; + if (!xps_initializer.initialized()) { // TODO(sanjeevr): Handle legacy proxy case (with no prntvpt.dll) return false; } diff --git a/printing/backend/print_backend_win.cc b/printing/backend/print_backend_win.cc index ba71da0..41d9ee3 100644 --- a/printing/backend/print_backend_win.cc +++ b/printing/backend/print_backend_win.cc @@ -85,7 +85,8 @@ void PrintBackendWin::EnumeratePrinters(PrinterList* printer_list) { bool PrintBackendWin::GetPrinterCapsAndDefaults( const std::string& printer_name, PrinterCapsAndDefaults* printer_info) { - if (!XPSModule::Init()) { + ScopedXPSInitializer xps_initializer; + if (!xps_initializer.initialized()) { // TODO(sanjeevr): Handle legacy proxy case (with no prntvpt.dll) return false; } diff --git a/printing/backend/win_helper.cc b/printing/backend/win_helper.cc index 72f2528..e63b45f 100644 --- a/printing/backend/win_helper.cc +++ b/printing/backend/win_helper.cc @@ -175,4 +175,36 @@ HRESULT XPSModule::CloseProvider(HPTPROVIDER provider) { return g_close_provider_proc(provider); } +ScopedXPSInitializer::ScopedXPSInitializer() : initialized_(false) { + if (XPSModule::Init()) { + // Calls to XPS APIs typically require the XPS provider to be opened with + // PTOpenProvider. PTOpenProvider calls CoInitializeEx with + // COINIT_MULTITHREADED. We have seen certain buggy HP printer driver DLLs + // that call CoInitializeEx with COINIT_APARTMENTTHREADED in the context of + // PTGetPrintCapabilities. This call fails but the printer driver calls + // CoUninitialize anyway. This results in the apartment being torn down too + // early and the msxml DLL being unloaded which in turn causes code in + // unidrvui.dll to have a dangling pointer to an XML document which causes a + // crash. To protect ourselves from such drivers we make sure we always have + // an extra CoInitialize (calls to CoInitialize/CoUninitialize are + // refcounted). + HRESULT coinit_ret = CoInitializeEx(NULL, COINIT_MULTITHREADED); + // If this succeeded we are done because the PTOpenProvider call will + // provide the extra refcount on the apartment. If it failed because someone + // already called CoInitializeEx with COINIT_APARTMENTTHREADED, we try + // the other model to provide the additional refcount (since we don't know + // which model buggy printer drivers will use). + if (coinit_ret == RPC_E_CHANGED_MODE) + coinit_ret = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); + DCHECK(SUCCEEDED(coinit_ret)); + initialized_ = true; + } +} + +ScopedXPSInitializer::~ScopedXPSInitializer() { + if (initialized_) + CoUninitialize(); + initialized_ = false; +} + } // namespace printing diff --git a/printing/backend/win_helper.h b/printing/backend/win_helper.h index 8b99a35..891f833 100644 --- a/printing/backend/win_helper.h +++ b/printing/backend/win_helper.h @@ -58,6 +58,18 @@ class XPSModule { static bool InitImpl(); }; +// See comments in cc file explaining why we need this. +class ScopedXPSInitializer { + public: + ScopedXPSInitializer(); + ~ScopedXPSInitializer(); + + bool initialized() const { return initialized_; } + + private: + bool initialized_; +}; + } // namespace printing #endif // PRINTING_BACKEND_WIN_HELPER_H_ |