diff --git a/embedding/components/printingui/win/nsPrintDialogUtil.cpp b/embedding/components/printingui/win/nsPrintDialogUtil.cpp index 6931f183e23de..4857f7a5a7e20 100644 --- a/embedding/components/printingui/win/nsPrintDialogUtil.cpp +++ b/embedding/components/printingui/win/nsPrintDialogUtil.cpp @@ -55,6 +55,8 @@ WIN_LIBS= \ // This is for extending the dialog #include +#include "nsWindowsHelpers.h" + // Default labels for the radio buttons static const char* kAsLaidOutOnScreenStr = "As &laid out on the screen"; static const char* kTheSelectedFrameStr = "The selected &frame"; @@ -462,79 +464,71 @@ static UINT CALLBACK PrintHookProc(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM // This function assumes that aPrintName has already been converted from // unicode // -HGLOBAL CreateGlobalDevModeAndInit(const nsXPIDLString& aPrintName, nsIPrintSettings* aPS) +static nsReturnRef +CreateGlobalDevModeAndInit(const nsXPIDLString& aPrintName, + nsIPrintSettings* aPS) { - HGLOBAL hGlobalDevMode = nullptr; - - HANDLE hPrinter = nullptr; + nsHPRINTER hPrinter = nullptr; // const cast kludge for silly Win32 api's LPWSTR printName = const_cast(static_cast(aPrintName.get())); BOOL status = ::OpenPrinterW(printName, &hPrinter, nullptr); - if (status) { - - LPDEVMODEW pNewDevMode; - DWORD dwNeeded, dwRet; - - // Get the buffer size - dwNeeded = ::DocumentPropertiesW(gParentWnd, hPrinter, printName, nullptr, nullptr, 0); - if (dwNeeded == 0) { - return nullptr; - } - - // Allocate a buffer of the correct size. - pNewDevMode = (LPDEVMODEW)::HeapAlloc (::GetProcessHeap(), HEAP_ZERO_MEMORY, dwNeeded); - if (!pNewDevMode) return nullptr; - - hGlobalDevMode = (HGLOBAL)::GlobalAlloc(GHND, dwNeeded); - if (!hGlobalDevMode) { - ::HeapFree(::GetProcessHeap(), 0, pNewDevMode); - return nullptr; - } + if (!status) { + return nsReturnRef(); + } - dwRet = ::DocumentPropertiesW(gParentWnd, hPrinter, printName, pNewDevMode, nullptr, DM_OUT_BUFFER); + // Make sure hPrinter is closed on all paths + nsAutoPrinter autoPrinter(hPrinter); - if (dwRet != IDOK) { - ::HeapFree(::GetProcessHeap(), 0, pNewDevMode); - ::GlobalFree(hGlobalDevMode); - ::ClosePrinter(hPrinter); - return nullptr; - } + // Get the buffer size + DWORD dwNeeded = ::DocumentPropertiesW(gParentWnd, hPrinter, printName, nullptr, + nullptr, 0); + if (dwNeeded == 0) { + return nsReturnRef(); + } - // Lock memory and copy contents from DEVMODE (current printer) - // to Global Memory DEVMODE - LPDEVMODEW devMode = (DEVMODEW *)::GlobalLock(hGlobalDevMode); - if (devMode) { - memcpy(devMode, pNewDevMode, dwNeeded); - // Initialize values from the PrintSettings - nsCOMPtr psWin = do_QueryInterface(aPS); - MOZ_ASSERT(psWin); - psWin->CopyToNative(devMode); - - // Sets back the changes we made to the DevMode into the Printer Driver - dwRet = ::DocumentPropertiesW(gParentWnd, hPrinter, printName, devMode, devMode, DM_IN_BUFFER | DM_OUT_BUFFER); - if (dwRet != IDOK) { - ::GlobalUnlock(hGlobalDevMode); - ::GlobalFree(hGlobalDevMode); - ::HeapFree(::GetProcessHeap(), 0, pNewDevMode); - ::ClosePrinter(hPrinter); - return nullptr; - } + // Allocate a buffer of the correct size. + nsAutoDevMode newDevMode((LPDEVMODEW)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, + dwNeeded)); + if (!newDevMode) { + return nsReturnRef(); + } - ::GlobalUnlock(hGlobalDevMode); - } else { - ::GlobalFree(hGlobalDevMode); - hGlobalDevMode = nullptr; - } + nsHGLOBAL hDevMode = ::GlobalAlloc(GHND, dwNeeded); + nsAutoGlobalMem globalDevMode(hDevMode); + if (!hDevMode) { + return nsReturnRef(); + } - ::HeapFree(::GetProcessHeap(), 0, pNewDevMode); + DWORD dwRet = ::DocumentPropertiesW(gParentWnd, hPrinter, printName, newDevMode, + nullptr, DM_OUT_BUFFER); + if (dwRet != IDOK) { + return nsReturnRef(); + } - ::ClosePrinter(hPrinter); + // Lock memory and copy contents from DEVMODE (current printer) + // to Global Memory DEVMODE + LPDEVMODEW devMode = (DEVMODEW *)::GlobalLock(hDevMode); + if (!devMode) { + return nsReturnRef(); + } - } else { - return nullptr; + memcpy(devMode, newDevMode.get(), dwNeeded); + // Initialize values from the PrintSettings + nsCOMPtr psWin = do_QueryInterface(aPS); + MOZ_ASSERT(psWin); + psWin->CopyToNative(devMode); + + // Sets back the changes we made to the DevMode into the Printer Driver + dwRet = ::DocumentPropertiesW(gParentWnd, hPrinter, printName, devMode, devMode, + DM_IN_BUFFER | DM_OUT_BUFFER); + if (dwRet != IDOK) { + ::GlobalUnlock(hDevMode); + return nsReturnRef(); } - return hGlobalDevMode; + ::GlobalUnlock(hDevMode); + + return globalDevMode.out(); } //------------------------------------------------------------------ @@ -576,9 +570,6 @@ ShowNativePrintDialog(HWND aHWnd, gDialogWasExtended = false; - HGLOBAL hGlobalDevMode = nullptr; - HGLOBAL hDevNames = nullptr; - // Get the Print Name to be used nsXPIDLString printerName; aPrintSettings->GetPrinterName(getter_Copies(printerName)); @@ -588,7 +579,8 @@ ShowNativePrintDialog(HWND aHWnd, GetDefaultPrinterNameFromGlobalPrinters(printerName); } else { HANDLE hPrinter = nullptr; - if(!::OpenPrinterW(const_cast(static_cast(printerName.get())), &hPrinter, nullptr)) { + if(!::OpenPrinterW(const_cast(static_cast(printerName.get())), + &hPrinter, nullptr)) { // If the last used printer is not found, we should use default printer. GetDefaultPrinterNameFromGlobalPrinters(printerName); } else { @@ -599,15 +591,15 @@ ShowNativePrintDialog(HWND aHWnd, // Now create a DEVNAMES struct so the the dialog is initialized correctly. uint32_t len = printerName.Length(); - hDevNames = (HGLOBAL)::GlobalAlloc(GHND, sizeof(wchar_t) * (len + 1) + - sizeof(DEVNAMES)); + nsHGLOBAL hDevNames = ::GlobalAlloc(GHND, sizeof(wchar_t) * (len + 1) + + sizeof(DEVNAMES)); + nsAutoGlobalMem autoDevNames(hDevNames); if (!hDevNames) { return NS_ERROR_OUT_OF_MEMORY; } DEVNAMES* pDevNames = (DEVNAMES*)::GlobalLock(hDevNames); if (!pDevNames) { - ::GlobalFree(hDevNames); return NS_ERROR_FAILURE; } pDevNames->wDriverOffset = sizeof(DEVNAMES)/sizeof(wchar_t); @@ -621,10 +613,8 @@ ShowNativePrintDialog(HWND aHWnd, // Create a Moveable Memory Object that holds a new DevMode // from the Printer Name // The PRINTDLG.hDevMode requires that it be a moveable memory object - // NOTE: We only need to free hGlobalDevMode when the dialog is cancelled - // When the user prints, it comes back in the printdlg struct and - // is used and cleaned up later - hGlobalDevMode = CreateGlobalDevModeAndInit(printerName, aPrintSettings); + // NOTE: autoDevMode is automatically freed when any error occurred + nsAutoGlobalMem autoDevMode(CreateGlobalDevModeAndInit(printerName, aPrintSettings)); // Prepare to Display the Print Dialog PRINTDLGW prntdlg; @@ -632,7 +622,7 @@ ShowNativePrintDialog(HWND aHWnd, prntdlg.lStructSize = sizeof(prntdlg); prntdlg.hwndOwner = aHWnd; - prntdlg.hDevMode = hGlobalDevMode; + prntdlg.hDevMode = autoDevMode.get(); prntdlg.hDevNames = hDevNames; prntdlg.hDC = nullptr; prntdlg.Flags = PD_ALLPAGES | PD_RETURNIC | @@ -682,13 +672,11 @@ ShowNativePrintDialog(HWND aHWnd, NS_ENSURE_TRUE(aPrintSettings && prntdlg.hDevMode, NS_ERROR_FAILURE); if (prntdlg.hDevNames == nullptr) { - ::GlobalFree(hGlobalDevMode); return NS_ERROR_FAILURE; } // Lock the deviceNames and check for nullptr DEVNAMES *devnames = (DEVNAMES *)::GlobalLock(prntdlg.hDevNames); if (devnames == nullptr) { - ::GlobalFree(hGlobalDevMode); return NS_ERROR_FAILURE; } @@ -716,7 +704,6 @@ ShowNativePrintDialog(HWND aHWnd, nsCOMPtr psWin(do_QueryInterface(aPrintSettings)); if (!psWin) { - ::GlobalFree(hGlobalDevMode); return NS_ERROR_FAILURE; } @@ -772,7 +759,6 @@ ShowNativePrintDialog(HWND aHWnd, // Transfer the settings from the native data to the PrintSettings LPDEVMODEW devMode = (LPDEVMODEW)::GlobalLock(prntdlg.hDevMode); if (!devMode || !prntdlg.hDC) { - ::GlobalFree(hGlobalDevMode); return NS_ERROR_FAILURE; } psWin->SetDevMode(devMode); // copies DevMode @@ -805,7 +791,6 @@ ShowNativePrintDialog(HWND aHWnd, } else { ::SetFocus(aHWnd); aPrintSettings->SetIsCancelled(true); - if (hGlobalDevMode) ::GlobalFree(hGlobalDevMode); return NS_ERROR_ABORT; } diff --git a/embedding/components/printingui/win/nsPrintDialogUtil.h b/embedding/components/printingui/win/nsPrintDialogUtil.h index 83173cc342374..ada3da239b82d 100644 --- a/embedding/components/printingui/win/nsPrintDialogUtil.h +++ b/embedding/components/printingui/win/nsPrintDialogUtil.h @@ -9,6 +9,4 @@ nsresult NativeShowPrintDialog(HWND aHWnd, nsIWebBrowserPrint* aWebBrowserPrint, nsIPrintSettings* aPrintSettings); -HGLOBAL CreateGlobalDevModeAndInit(const nsXPIDLString& aPrintName, nsIPrintSettings* aPS); - #endif /* nsFlyOwnDialog_h___ */ diff --git a/xpcom/base/nsWindowsHelpers.h b/xpcom/base/nsWindowsHelpers.h index 2cbb9cf24a5dc..66505b3458af0 100644 --- a/xpcom/base/nsWindowsHelpers.h +++ b/xpcom/base/nsWindowsHelpers.h @@ -212,6 +212,91 @@ class nsAutoRefTraits } }; + +// HGLOBAL is just a typedef of HANDLE which nsSimpleRef has a specialization of, +// that means having a nsAutoRefTraits specialization for HGLOBAL is useless. +// Therefore we create a wrapper class for HGLOBAL to make nsAutoRefTraits and +// nsAutoRef work as intention. +class nsHGLOBAL { +public: + nsHGLOBAL(HGLOBAL hGlobal) : m_hGlobal(hGlobal) + { + } + + operator HGLOBAL() const + { + return m_hGlobal; + } + +private: + HGLOBAL m_hGlobal; +}; + + +template<> +class nsAutoRefTraits +{ +public: + typedef nsHGLOBAL RawRef; + static RawRef Void() + { + return nullptr; + } + + static void Release(RawRef hGlobal) + { + ::GlobalFree(hGlobal); + } +}; + + +// Because Printer's HANDLE uses ClosePrinter and we already have nsAutoRef +// which uses CloseHandle so we need to create a wrapper class for HANDLE to have +// another specialization for nsAutoRefTraits. +class nsHPRINTER { +public: + nsHPRINTER(HANDLE hPrinter) : m_hPrinter(hPrinter) + { + } + + operator HANDLE() const + { + return m_hPrinter; + } + + HANDLE* operator&() + { + return &m_hPrinter; + } + +private: + HANDLE m_hPrinter; +}; + + +// winspool.h header has AddMonitor macro, it conflicts with AddMonitor member +// function in TaskbarPreview.cpp and TaskbarTabPreview.cpp. Beside, we only +// need ClosePrinter here for Release function, so having its prototype is enough. +extern "C" BOOL WINAPI ClosePrinter(HANDLE hPrinter); + + +template<> +class nsAutoRefTraits +{ +public: + typedef nsHPRINTER RawRef; + static RawRef Void() + { + return nullptr; + } + + static void Release(RawRef hPrinter) + { + ::ClosePrinter(hPrinter); + } +}; + + typedef nsAutoRef nsAutoRegKey; typedef nsAutoRef nsAutoHDC; typedef nsAutoRef nsAutoBrush; @@ -221,6 +306,8 @@ typedef nsAutoRef nsAutoServiceHandle; typedef nsAutoRef nsAutoHandle; typedef nsAutoRef nsModuleHandle; typedef nsAutoRef nsAutoDevMode; +typedef nsAutoRef nsAutoGlobalMem; +typedef nsAutoRef nsAutoPrinter; namespace {