summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/service/cloud_print/print_system_win.cc13
-rw-r--r--printing/backend/print_backend_win.cc3
-rw-r--r--printing/backend/win_helper.cc32
-rw-r--r--printing/backend/win_helper.h12
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_