From 502abed36aee53144dce187b29c0413f46fb8548 Mon Sep 17 00:00:00 2001 From: RKrom Date: Sun, 13 Jan 2013 15:53:35 +0000 Subject: [PATCH] Added SafeHandles, see here: http://blogs.msdn.com/b/bclteam/archive/2005/03/15/396335.aspx to some of the Greenshot code. Not all possible handles have been converted, this should be done to prevent more possible memory/resource leaks. git-svn-id: http://svn.code.sf.net/p/greenshot/code/trunk@2427 7dccd23d-a4a3-4e1f-8c07-b4c1b4018ab4 --- Greenshot/Controls/Pipette.cs | 22 ++++++------ GreenshotPlugin/Core/WindowCapture.cs | 39 +++++++++++----------- GreenshotPlugin/Core/WindowsHelper.cs | 9 +++-- GreenshotPlugin/UnmanagedHelpers/GDI32.cs | 37 ++++++++++++++++---- GreenshotPlugin/UnmanagedHelpers/User32.cs | 22 ++++++++++-- 5 files changed, 87 insertions(+), 42 deletions(-) diff --git a/Greenshot/Controls/Pipette.cs b/Greenshot/Controls/Pipette.cs index dbcffaaa8..74a8ea6b8 100644 --- a/Greenshot/Controls/Pipette.cs +++ b/Greenshot/Controls/Pipette.cs @@ -56,18 +56,16 @@ namespace Greenshot.Controls { /// Hotspot Y coordinate /// Cursor private static Cursor CreateCursor(Bitmap bitmap, int hotspotX, int hotspotY) { - IntPtr iconHandle = bitmap.GetHicon(); - IntPtr icon; - IconInfo iconInfo = new IconInfo(); - User32.GetIconInfo(iconHandle, out iconInfo); - iconInfo.xHotspot = hotspotX; - iconInfo.yHotspot = hotspotY; - iconInfo.fIcon = false; - icon = User32.CreateIconIndirect(ref iconInfo); - Cursor returnCursor = new Cursor(icon); - //User32.DestroyIcon(icon); - User32.DestroyIcon(iconHandle); - return returnCursor; + using (SafeIconHandle iconHandle = new SafeIconHandle( bitmap.GetHicon())) { + IntPtr icon; + IconInfo iconInfo = new IconInfo(); + User32.GetIconInfo(iconHandle, out iconInfo); + iconInfo.xHotspot = hotspotX; + iconInfo.yHotspot = hotspotY; + iconInfo.fIcon = false; + icon = User32.CreateIconIndirect(ref iconInfo); + return new Cursor(icon); + } } /// diff --git a/GreenshotPlugin/Core/WindowCapture.cs b/GreenshotPlugin/Core/WindowCapture.cs index e94adad8b..861e335e5 100644 --- a/GreenshotPlugin/Core/WindowCapture.cs +++ b/GreenshotPlugin/Core/WindowCapture.cs @@ -498,33 +498,32 @@ namespace GreenshotPlugin.Core { capture = new Capture(); } int x,y; - IntPtr hicon; CursorInfo cursorInfo = new CursorInfo(); IconInfo iconInfo; cursorInfo.cbSize = Marshal.SizeOf(cursorInfo); if (User32.GetCursorInfo(out cursorInfo)) { if (cursorInfo.flags == User32.CURSOR_SHOWING) { - hicon = User32.CopyIcon(cursorInfo.hCursor); - if (User32.GetIconInfo(hicon, out iconInfo)) { - Point cursorLocation = GetCursorLocation(); - // Allign cursor location to Bitmap coordinates (instead of Screen coordinates) - x = cursorLocation.X - iconInfo.xHotspot - capture.ScreenBounds.X; - y = cursorLocation.Y - iconInfo.yHotspot - capture.ScreenBounds.Y; - // Set the location - capture.CursorLocation = new Point(x, y); - - using (Icon icon = Icon.FromHandle(hicon)) { - capture.Cursor = icon; - } - - if (iconInfo.hbmMask != IntPtr.Zero) { - GDI32.DeleteObject(iconInfo.hbmMask); - } - if (iconInfo.hbmColor != IntPtr.Zero) { - GDI32.DeleteObject(iconInfo.hbmColor); + using (SafeIconHandle safeIcon = User32.CopyIcon(cursorInfo.hCursor)) { + if (User32.GetIconInfo(safeIcon, out iconInfo)) { + Point cursorLocation = GetCursorLocation(); + // Allign cursor location to Bitmap coordinates (instead of Screen coordinates) + x = cursorLocation.X - iconInfo.xHotspot - capture.ScreenBounds.X; + y = cursorLocation.Y - iconInfo.yHotspot - capture.ScreenBounds.Y; + // Set the location + capture.CursorLocation = new Point(x, y); + + using (Icon icon = Icon.FromHandle(safeIcon.DangerousGetHandle())) { + capture.Cursor = icon; + } + + if (iconInfo.hbmMask != IntPtr.Zero) { + GDI32.DeleteObject(iconInfo.hbmMask); + } + if (iconInfo.hbmColor != IntPtr.Zero) { + GDI32.DeleteObject(iconInfo.hbmColor); + } } } - User32.DestroyIcon(hicon); } } return capture; diff --git a/GreenshotPlugin/Core/WindowsHelper.cs b/GreenshotPlugin/Core/WindowsHelper.cs index 9de12b729..bd9c79562 100644 --- a/GreenshotPlugin/Core/WindowsHelper.cs +++ b/GreenshotPlugin/Core/WindowsHelper.cs @@ -627,7 +627,11 @@ namespace GreenshotPlugin.Core { return User32.IsIconic(this.hWnd) || Location.X <= -32000; } set { - User32.SendMessage(this.hWnd, (int)WindowsMessages.WM_SYSCOMMAND, (IntPtr)User32.SC_MINIMIZE, IntPtr.Zero); + if (value) { + User32.SendMessage(this.hWnd, (int)WindowsMessages.WM_SYSCOMMAND, (IntPtr)User32.SC_MINIMIZE, IntPtr.Zero); + } else { + User32.SendMessage(this.hWnd, (int)WindowsMessages.WM_SYSCOMMAND, (IntPtr)User32.SC_RESTORE, IntPtr.Zero); + } } } @@ -660,7 +664,7 @@ namespace GreenshotPlugin.Core { if (monitor != IntPtr.Zero) { if (appVisibility != null) { MONITOR_APP_VISIBILITY monitorAppVisibility = appVisibility.GetAppVisibilityOnMonitor(monitor); - LOG.DebugFormat("App visible: {0}", monitorAppVisibility); + LOG.DebugFormat("App {0} visible: {1} on {2}", Text, monitorAppVisibility, screen.Bounds); if (monitorAppVisibility == MONITOR_APP_VISIBILITY.MAV_APP_VISIBLE) { return true; } @@ -1097,6 +1101,7 @@ namespace GreenshotPlugin.Core { /// Bitmap with transparency private Bitmap ApplyTransparency(Bitmap blackBitmap, Bitmap whiteBitmap) { Bitmap returnBitmap = new Bitmap(blackBitmap.Width, blackBitmap.Height, PixelFormat.Format32bppArgb); + returnBitmap.SetResolution(blackBitmap.HorizontalResolution, blackBitmap.VerticalResolution); using (BitmapBuffer blackBuffer = new BitmapBuffer(blackBitmap, false)) { blackBuffer.Lock(); using (BitmapBuffer whiteBuffer = new BitmapBuffer(whiteBitmap, false)) { diff --git a/GreenshotPlugin/UnmanagedHelpers/GDI32.cs b/GreenshotPlugin/UnmanagedHelpers/GDI32.cs index 56c8d4205..583ea4ff3 100644 --- a/GreenshotPlugin/UnmanagedHelpers/GDI32.cs +++ b/GreenshotPlugin/UnmanagedHelpers/GDI32.cs @@ -21,6 +21,8 @@ using System; using System.Drawing; using System.Runtime.InteropServices; +using System.Security; +using Microsoft.Win32.SafeHandles; namespace GreenshotPlugin.UnmanagedHelpers { public static class GDIExtensions { @@ -37,6 +39,25 @@ namespace GreenshotPlugin.UnmanagedHelpers { return topLeftVisible && topRightVisible && bottomLeftVisible && bottomRightVisible; } } + + /// + /// A hbitmap SafeHandle implementation + /// + public class SafeHBitmapHandle : SafeHandleZeroOrMinusOneIsInvalid { + [SecurityCritical] + private SafeHBitmapHandle(): base(true) { + } + + [SecurityCritical] + public SafeHBitmapHandle(IntPtr preexistingHandle) : base(true) { + SetHandle(preexistingHandle); + } + + protected override bool ReleaseHandle() { + return GDI32.DeleteObject(handle); + } + } + /// /// GDI32 Helpers /// @@ -77,9 +98,11 @@ namespace GreenshotPlugin.UnmanagedHelpers { try { hDCDest = target.GetHdc(); hDCSrc = CreateCompatibleDC(hDCDest); - IntPtr pOrig = SelectObject(hDCSrc, sourceBitmap.GetHbitmap()); - StretchBlt(hDCDest, destination.X, destination.Y, destination.Width, destination.Height, hDCSrc, source.Left, source.Top, source.Width, source.Height, CopyPixelOperation.SourceCopy); - IntPtr pNew = SelectObject(hDCDest, pOrig); + using (SafeHBitmapHandle hBitmapHandle = new SafeHBitmapHandle(sourceBitmap.GetHbitmap())) { + IntPtr pOrig = SelectObject(hDCSrc, hBitmapHandle.DangerousGetHandle()); + StretchBlt(hDCDest, destination.X, destination.Y, destination.Width, destination.Height, hDCSrc, source.Left, source.Top, source.Width, source.Height, CopyPixelOperation.SourceCopy); + IntPtr pNew = SelectObject(hDCDest, pOrig); + } } finally { if (hDCSrc != IntPtr.Zero) { DeleteDC(hDCSrc); @@ -101,9 +124,11 @@ namespace GreenshotPlugin.UnmanagedHelpers { try { hDCDest = target.GetHdc(); hDCSrc = CreateCompatibleDC(hDCDest); - IntPtr pOrig = SelectObject(hDCSrc, sourceBitmap.GetHbitmap()); - BitBlt(hDCDest, destination.X, destination.Y, source.Width, source.Height, hDCSrc, source.Left, source.Top, CopyPixelOperation.SourceCopy); - IntPtr pNew = SelectObject(hDCDest, pOrig); + using (SafeHBitmapHandle hBitmapHandle = new SafeHBitmapHandle(sourceBitmap.GetHbitmap())) { + IntPtr pOrig = SelectObject(hDCSrc, hBitmapHandle.DangerousGetHandle()); + BitBlt(hDCDest, destination.X, destination.Y, source.Width, source.Height, hDCSrc, source.Left, source.Top, CopyPixelOperation.SourceCopy); + IntPtr pNew = SelectObject(hDCDest, pOrig); + } } finally { if (hDCSrc != IntPtr.Zero) { DeleteDC(hDCSrc); diff --git a/GreenshotPlugin/UnmanagedHelpers/User32.cs b/GreenshotPlugin/UnmanagedHelpers/User32.cs index 9279abff1..729aff5fe 100644 --- a/GreenshotPlugin/UnmanagedHelpers/User32.cs +++ b/GreenshotPlugin/UnmanagedHelpers/User32.cs @@ -25,6 +25,8 @@ using System.Drawing; using System.Runtime.InteropServices; using System.Text; +using Microsoft.Win32.SafeHandles; + namespace GreenshotPlugin.UnmanagedHelpers { /// /// Used with EnumWindows or EnumChildWindows @@ -45,6 +47,22 @@ namespace GreenshotPlugin.UnmanagedHelpers { /// /// public delegate void WinEventDelegate(IntPtr hWinEventHook, WinEvent eventType, IntPtr hwnd, EventObjects idObject, int idChild, uint dwEventThread, uint dwmsEventTime); + + /// + /// A SafeHandle class implementation for the hIcon + /// + public class SafeIconHandle : SafeHandleZeroOrMinusOneIsInvalid { + private SafeIconHandle(): base(true) { + } + + public SafeIconHandle(IntPtr hIcon) : base(true) { + this.SetHandle(hIcon); + } + + protected override bool ReleaseHandle() { + return User32.DestroyIcon(this.handle); + } + } /// /// User32 Wrappers @@ -210,13 +228,13 @@ namespace GreenshotPlugin.UnmanagedHelpers { /// /// [DllImport("user32", SetLastError = true)] - public static extern IntPtr CopyIcon(IntPtr hIcon); + public static extern SafeIconHandle CopyIcon(IntPtr hIcon); [DllImport("user32", SetLastError = true)] public static extern bool DestroyIcon(IntPtr hIcon); [DllImport("user32", SetLastError = true)] public static extern bool GetCursorInfo(out CursorInfo cursorInfo); [DllImport("user32", SetLastError = true)] - public static extern bool GetIconInfo(IntPtr hIcon, out IconInfo iconInfo); + public static extern bool GetIconInfo(SafeIconHandle iconHandle, out IconInfo iconInfo); [DllImport("user32", SetLastError = true)] public static extern bool DrawIcon(IntPtr hDC, int X, int Y, IntPtr hIcon); [DllImport("user32", SetLastError = true)]