Skip to content

Commit

Permalink
Fixed a crash with some HP printer drivers (when invoking PTGetPrintC…
Browse files Browse the repository at this point in the history
…apabilities on them).

Detailed story:
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).


BUG=None
TEST=Test Cloud Print Proxy on Windows with HP Photosmart 7960 series printers.

Review URL: http://codereview.chromium.org/6037019

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@70754 0039d316-1c4b-4281-b951-d872f2087c98
  • Loading branch information
sanjeevr@chromium.org committed Jan 7, 2011
1 parent 803b99a commit 39900b4
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 6 deletions.
13 changes: 8 additions & 5 deletions chrome/service/cloud_print/print_system_win.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand Down Expand Up @@ -383,17 +388,14 @@ 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);
if (FAILED(hr)) {
NOTREACHED();
return false;
}

HDC dc = CreateDC(L"WINSPOOL", UTF8ToWide(printer_name).c_str(),
NULL, pt_dev_mode.dm_);
if (!dc) {
Expand Down Expand Up @@ -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;
}
Expand Down
3 changes: 2 additions & 1 deletion printing/backend/print_backend_win.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
32 changes: 32 additions & 0 deletions printing/backend/win_helper.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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
12 changes: 12 additions & 0 deletions printing/backend/win_helper.h
Original file line number Diff line number Diff line change
Expand Up @@ -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_

0 comments on commit 39900b4

Please sign in to comment.