Skip to content

Commit

Permalink
Bug 1242456 - Create RAIIs to manage HGLOBAL and printer HANDLE in Sh…
Browse files Browse the repository at this point in the history
…owNativePrintDialog and CreateGlobalDevModeAndInit. r=jimm, r=bobowen
  • Loading branch information
so61pi committed Apr 5, 2016
1 parent 0a327c9 commit bb8780b
Show file tree
Hide file tree
Showing 3 changed files with 149 additions and 79 deletions.
139 changes: 62 additions & 77 deletions embedding/components/printingui/win/nsPrintDialogUtil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ WIN_LIBS= \
// This is for extending the dialog
#include <dlgs.h>

#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";
Expand Down Expand Up @@ -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<nsHGLOBAL>
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<wchar_t*>(static_cast<const wchar_t*>(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<nsHGLOBAL>();
}

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<nsHGLOBAL>();
}

// 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<nsIPrintSettingsWin> 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<nsHGLOBAL>();
}

::GlobalUnlock(hGlobalDevMode);
} else {
::GlobalFree(hGlobalDevMode);
hGlobalDevMode = nullptr;
}
nsHGLOBAL hDevMode = ::GlobalAlloc(GHND, dwNeeded);
nsAutoGlobalMem globalDevMode(hDevMode);
if (!hDevMode) {
return nsReturnRef<nsHGLOBAL>();
}

::HeapFree(::GetProcessHeap(), 0, pNewDevMode);
DWORD dwRet = ::DocumentPropertiesW(gParentWnd, hPrinter, printName, newDevMode,
nullptr, DM_OUT_BUFFER);
if (dwRet != IDOK) {
return nsReturnRef<nsHGLOBAL>();
}

::ClosePrinter(hPrinter);
// Lock memory and copy contents from DEVMODE (current printer)
// to Global Memory DEVMODE
LPDEVMODEW devMode = (DEVMODEW *)::GlobalLock(hDevMode);
if (!devMode) {
return nsReturnRef<nsHGLOBAL>();
}

} else {
return nullptr;
memcpy(devMode, newDevMode.get(), dwNeeded);
// Initialize values from the PrintSettings
nsCOMPtr<nsIPrintSettingsWin> 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<nsHGLOBAL>();
}

return hGlobalDevMode;
::GlobalUnlock(hDevMode);

return globalDevMode.out();
}

//------------------------------------------------------------------
Expand Down Expand Up @@ -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));
Expand All @@ -588,7 +579,8 @@ ShowNativePrintDialog(HWND aHWnd,
GetDefaultPrinterNameFromGlobalPrinters(printerName);
} else {
HANDLE hPrinter = nullptr;
if(!::OpenPrinterW(const_cast<wchar_t*>(static_cast<const wchar_t*>(printerName.get())), &hPrinter, nullptr)) {
if(!::OpenPrinterW(const_cast<wchar_t*>(static_cast<const wchar_t*>(printerName.get())),
&hPrinter, nullptr)) {
// If the last used printer is not found, we should use default printer.
GetDefaultPrinterNameFromGlobalPrinters(printerName);
} else {
Expand All @@ -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);
Expand All @@ -621,18 +613,16 @@ 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;
memset(&prntdlg, 0, sizeof(PRINTDLGW));

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 |
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -716,7 +704,6 @@ ShowNativePrintDialog(HWND aHWnd,

nsCOMPtr<nsIPrintSettingsWin> psWin(do_QueryInterface(aPrintSettings));
if (!psWin) {
::GlobalFree(hGlobalDevMode);
return NS_ERROR_FAILURE;
}

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -805,7 +791,6 @@ ShowNativePrintDialog(HWND aHWnd,
} else {
::SetFocus(aHWnd);
aPrintSettings->SetIsCancelled(true);
if (hGlobalDevMode) ::GlobalFree(hGlobalDevMode);
return NS_ERROR_ABORT;
}

Expand Down
2 changes: 0 additions & 2 deletions embedding/components/printingui/win/nsPrintDialogUtil.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,4 @@ nsresult NativeShowPrintDialog(HWND aHWnd,
nsIWebBrowserPrint* aWebBrowserPrint,
nsIPrintSettings* aPrintSettings);

HGLOBAL CreateGlobalDevModeAndInit(const nsXPIDLString& aPrintName, nsIPrintSettings* aPS);

#endif /* nsFlyOwnDialog_h___ */
87 changes: 87 additions & 0 deletions xpcom/base/nsWindowsHelpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,91 @@ class nsAutoRefTraits<DEVMODEW*>
}
};


// 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<nsHGLOBAL>
{
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<HANDLE>
// 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<nsHPRINTER>
{
public:
typedef nsHPRINTER RawRef;
static RawRef Void()
{
return nullptr;
}

static void Release(RawRef hPrinter)
{
::ClosePrinter(hPrinter);
}
};


typedef nsAutoRef<HKEY> nsAutoRegKey;
typedef nsAutoRef<HDC> nsAutoHDC;
typedef nsAutoRef<HBRUSH> nsAutoBrush;
Expand All @@ -221,6 +306,8 @@ typedef nsAutoRef<SC_HANDLE> nsAutoServiceHandle;
typedef nsAutoRef<HANDLE> nsAutoHandle;
typedef nsAutoRef<HMODULE> nsModuleHandle;
typedef nsAutoRef<DEVMODEW*> nsAutoDevMode;
typedef nsAutoRef<nsHGLOBAL> nsAutoGlobalMem;
typedef nsAutoRef<nsHPRINTER> nsAutoPrinter;

namespace {

Expand Down

0 comments on commit bb8780b

Please sign in to comment.