| Index: printing/backend/win_helper.cc
|
| ===================================================================
|
| --- printing/backend/win_helper.cc (revision 70422)
|
| +++ printing/backend/win_helper.cc (working copy)
|
| @@ -175,4 +175,36 @@
|
| 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
|
|
|