diff --git a/Greenshot/Forms/MovableShowColorForm.cs b/Greenshot/Forms/MovableShowColorForm.cs
index f2f788d79..edb3a66cf 100644
--- a/Greenshot/Forms/MovableShowColorForm.cs
+++ b/Greenshot/Forms/MovableShowColorForm.cs
@@ -86,16 +86,13 @@ namespace Greenshot.Forms {
/// Point with the coordinates
/// Color at the specified screenCoordinates
static private Color GetPixelColor(Point screenCoordinates) {
- IntPtr hdc = User32.GetDC(IntPtr.Zero);
- try {
- uint pixel = GDI32.GetPixel(hdc, screenCoordinates.X, screenCoordinates.Y);
- Color color = Color.FromArgb(255, (int)(pixel & 0xFF), (int)(pixel & 0xFF00) >> 8, (int)(pixel & 0xFF0000) >> 16);
- return color;
- } catch (Exception) {
- return Color.Empty;
- } finally {
- if (hdc != IntPtr.Zero) {
- User32.ReleaseDC(IntPtr.Zero, hdc);
+ using (SafeWindowDCHandle screenDC = SafeWindowDCHandle.fromDesktop()) {
+ try {
+ uint pixel = GDI32.GetPixel(screenDC, screenCoordinates.X, screenCoordinates.Y);
+ Color color = Color.FromArgb(255, (int)(pixel & 0xFF), (int)(pixel & 0xFF00) >> 8, (int)(pixel & 0xFF0000) >> 16);
+ return color;
+ } catch (Exception) {
+ return Color.Empty;
}
}
}
diff --git a/GreenshotPlugin/Controls/AnimatingForm.cs b/GreenshotPlugin/Controls/AnimatingForm.cs
index 3d5324bd3..b64302054 100644
--- a/GreenshotPlugin/Controls/AnimatingForm.cs
+++ b/GreenshotPlugin/Controls/AnimatingForm.cs
@@ -48,9 +48,9 @@ namespace GreenshotPlugin.Controls {
get {
if (vRefresh == 0) {
// get te hDC of the desktop to get the VREFRESH
- IntPtr hDCDesktop = User32.GetWindowDC(User32.GetDesktopWindow());
- vRefresh = GDI32.GetDeviceCaps(hDCDesktop, DeviceCaps.VREFRESH);
- User32.ReleaseDC(hDCDesktop);
+ using (SafeWindowDCHandle desktopHandle = SafeWindowDCHandle.fromDesktop()) {
+ vRefresh = GDI32.GetDeviceCaps(desktopHandle, DeviceCaps.VREFRESH);
+ }
}
// A vertical refresh rate value of 0 or 1 represents the display hardware's default refresh rate.
// As there is currently no know way to get the default, we guess it.
diff --git a/GreenshotPlugin/Core/ClipboardHelper.cs b/GreenshotPlugin/Core/ClipboardHelper.cs
index 44ca8b023..a4e134d2b 100644
--- a/GreenshotPlugin/Core/ClipboardHelper.cs
+++ b/GreenshotPlugin/Core/ClipboardHelper.cs
@@ -493,7 +493,7 @@ EndSelection:<<<<<<<4
///
private const int BITMAPFILEHEADER_LENGTH = 14;
public static void SetClipboardData(ISurface surface) {
- DataObject ido = new DataObject();
+ DataObject dataObject = new DataObject();
// This will work for Office and most other applications
//ido.SetData(DataFormats.Bitmap, true, image);
@@ -515,7 +515,7 @@ EndSelection:<<<<<<<4
ImageOutput.SaveToStream(imageToSave, null, pngStream, pngOutputSettings);
pngStream.Seek(0, SeekOrigin.Begin);
// Set the PNG stream
- ido.SetData(FORMAT_PNG, false, pngStream);
+ dataObject.SetData(FORMAT_PNG, false, pngStream);
}
} catch (Exception pngEX) {
LOG.Error("Error creating PNG for the Clipboard.", pngEX);
@@ -534,7 +534,7 @@ EndSelection:<<<<<<<4
}
// Set the DIB to the clipboard DataObject
- ido.SetData(DataFormats.Dib, true, dibStream);
+ dataObject.SetData(DataFormats.Dib, true, dibStream);
}
} catch (Exception dibEx) {
LOG.Error("Error creating DIB for the Clipboard.", dibEx);
@@ -544,7 +544,7 @@ EndSelection:<<<<<<<4
if (config.ClipboardFormats.Contains(ClipboardFormat.HTML)) {
string tmpFile = ImageOutput.SaveToTmpFile(surface, new SurfaceOutputSettings(OutputFormat.png, 100, false), null);
string html = getHTMLString(surface, tmpFile);
- ido.SetText(html, TextDataFormat.Html);
+ dataObject.SetText(html, TextDataFormat.Html);
} else if (config.ClipboardFormats.Contains(ClipboardFormat.HTMLDATAURL)) {
string html;
using (MemoryStream tmpPNGStream = new MemoryStream()) {
@@ -560,18 +560,18 @@ EndSelection:<<<<<<<4
}
html = getHTMLDataURLString(surface, tmpPNGStream);
}
- ido.SetText(html, TextDataFormat.Html);
+ dataObject.SetText(html, TextDataFormat.Html);
}
} finally {
// we need to use the SetDataOject before the streams are closed otherwise the buffer will be gone!
// Check if Bitmap is wanted
if (config.ClipboardFormats.Contains(ClipboardFormat.BITMAP)) {
- ido.SetImage(imageToSave);
+ dataObject.SetImage(imageToSave);
// Place the DataObject to the clipboard
- SetDataObject(ido, true);
+ SetDataObject(dataObject, true);
} else {
// Place the DataObject to the clipboard
- SetDataObject(ido, true);
+ SetDataObject(dataObject, true);
}
if (pngStream != null) {
diff --git a/GreenshotPlugin/Core/WindowCapture.cs b/GreenshotPlugin/Core/WindowCapture.cs
index 861e335e5..8a2a2c209 100644
--- a/GreenshotPlugin/Core/WindowCapture.cs
+++ b/GreenshotPlugin/Core/WindowCapture.cs
@@ -428,6 +428,14 @@ namespace GreenshotPlugin.Core {
private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(WindowCapture));
private static CoreConfiguration conf = IniConfig.GetIniSection();
+ ///
+ /// Used to cleanup the unmanged resource in the iconInfo for the CaptureCursor method
+ ///
+ ///
+ ///
+ [DllImport("gdi32", SetLastError = true)]
+ private static extern bool DeleteObject(IntPtr hObject);
+
private WindowCapture() {
}
@@ -517,10 +525,10 @@ namespace GreenshotPlugin.Core {
}
if (iconInfo.hbmMask != IntPtr.Zero) {
- GDI32.DeleteObject(iconInfo.hbmMask);
+ DeleteObject(iconInfo.hbmMask);
}
if (iconInfo.hbmColor != IntPtr.Zero) {
- GDI32.DeleteObject(iconInfo.hbmColor);
+ DeleteObject(iconInfo.hbmColor);
}
}
}
@@ -640,123 +648,109 @@ namespace GreenshotPlugin.Core {
// }
// capture.Image = capturedBitmap;
// capture.Location = captureBounds.Location;
-
- // "P/Invoke" Solution for capturing the screen
- IntPtr hWndDesktop = User32.GetDesktopWindow();
- // get te hDC of the target window
- IntPtr hDCDesktop = User32.GetWindowDC(hWndDesktop);
- // Make sure the last error is set to 0
- Win32.SetLastError(0);
+ using (SafeWindowDCHandle desktopDCHandle = SafeWindowDCHandle.fromDesktop()) {
+ if (desktopDCHandle.IsInvalid) {
+ // Get Exception before the error is lost
+ Exception exceptionToThrow = CreateCaptureException("desktopDCHandle", captureBounds);
+ // throw exception
+ throw exceptionToThrow;
+ }
- // create a device context we can copy to
- IntPtr hDCDest = GDI32.CreateCompatibleDC(hDCDesktop);
- // Check if the device context is there, if not throw an error with as much info as possible!
- if (hDCDest == IntPtr.Zero) {
- // Get Exception before the error is lost
- Exception exceptionToThrow = CreateCaptureException("CreateCompatibleDC", captureBounds);
- // Cleanup
- User32.ReleaseDC(hWndDesktop, hDCDesktop);
- // throw exception
- throw exceptionToThrow;
- }
+ // create a device context we can copy to
+ using (SafeCompatibleDCHandle safeCompatibleDCHandle = GDI32.CreateCompatibleDC(desktopDCHandle)) {
+ // Check if the device context is there, if not throw an error with as much info as possible!
+ if (safeCompatibleDCHandle.IsInvalid) {
+ // Get Exception before the error is lost
+ Exception exceptionToThrow = CreateCaptureException("CreateCompatibleDC", captureBounds);
+ // throw exception
+ throw exceptionToThrow;
+ }
+ // Create BitmapInfoHeader for CreateDIBSection
+ BitmapInfoHeader bmi = new BitmapInfoHeader(captureBounds.Width, captureBounds.Height, 24);
- // Create BitmapInfoHeader for CreateDIBSection
- BitmapInfoHeader bmi = new BitmapInfoHeader(captureBounds.Width, captureBounds.Height, 24);
+ // Make sure the last error is set to 0
+ Win32.SetLastError(0);
- // Make sure the last error is set to 0
- Win32.SetLastError(0);
+ // create a bitmap we can copy it to, using GetDeviceCaps to get the width/height
+ IntPtr bits0; // not used for our purposes. It returns a pointer to the raw bits that make up the bitmap.
+ using (SafeDibSectionHandle safeDibSectionHandle = GDI32.CreateDIBSection(desktopDCHandle, ref bmi, BitmapInfoHeader.DIB_RGB_COLORS, out bits0, IntPtr.Zero, 0)) {
+ if (safeDibSectionHandle.IsInvalid) {
+ // Get Exception before the error is lost
+ Exception exceptionToThrow = CreateCaptureException("CreateDIBSection", captureBounds);
+ exceptionToThrow.Data.Add("hdcDest", safeCompatibleDCHandle.DangerousGetHandle().ToInt32());
+ exceptionToThrow.Data.Add("hdcSrc", desktopDCHandle.DangerousGetHandle().ToInt32());
- // create a bitmap we can copy it to, using GetDeviceCaps to get the width/height
- IntPtr bits0; // not used for our purposes. It returns a pointer to the raw bits that make up the bitmap.
- IntPtr hDIBSection = GDI32.CreateDIBSection(hDCDesktop, ref bmi, BitmapInfoHeader.DIB_RGB_COLORS, out bits0, IntPtr.Zero, 0);
-
- if (hDIBSection == IntPtr.Zero) {
- // Get Exception before the error is lost
- Exception exceptionToThrow = CreateCaptureException("CreateDIBSection", captureBounds);
- exceptionToThrow.Data.Add("hdcDest", hDCDest.ToInt32());
- exceptionToThrow.Data.Add("hdcSrc", hDCDesktop.ToInt32());
-
- // clean up
- GDI32.DeleteDC(hDCDest);
- User32.ReleaseDC(hWndDesktop, hDCDesktop);
-
- // Throw so people can report the problem
- throw exceptionToThrow;
- } else {
- // select the bitmap object and store the old handle
- IntPtr hOldObject = GDI32.SelectObject(hDCDest, hDIBSection);
-
- // bitblt over (make copy)
- GDI32.BitBlt(hDCDest, 0, 0, captureBounds.Width, captureBounds.Height, hDCDesktop, captureBounds.X, captureBounds.Y, CopyPixelOperation.SourceCopy | CopyPixelOperation.CaptureBlt);
-
- // restore selection (old handle)
- GDI32.SelectObject(hDCDest, hOldObject);
- // clean up
- GDI32.DeleteDC(hDCDest);
- User32.ReleaseDC(hWndDesktop, hDCDesktop);
-
- // get a .NET image object for it
- // A suggestion for the "A generic error occurred in GDI+." E_FAIL/0×80004005 error is to re-try...
- bool success = false;
- ExternalException exception = null;
- for (int i = 0; i < 3; i++) {
- try {
- // Collect all screens inside this capture
- List screensInsideCapture = new List();
- foreach (Screen screen in Screen.AllScreens) {
- if (screen.Bounds.IntersectsWith(captureBounds)) {
- screensInsideCapture.Add(screen);
+ // Throw so people can report the problem
+ throw exceptionToThrow;
+ } else {
+ // select the bitmap object and store the old handle
+ using (SafeSelectObjectHandle selectObject = safeCompatibleDCHandle.SelectObject(safeDibSectionHandle)) {
+ // bitblt over (make copy)
+ GDI32.BitBlt(safeCompatibleDCHandle, 0, 0, captureBounds.Width, captureBounds.Height, desktopDCHandle, captureBounds.X, captureBounds.Y, CopyPixelOperation.SourceCopy | CopyPixelOperation.CaptureBlt);
}
- }
- // Check all all screens are of an equal size
- bool offscreenContent = false;
- using (Region captureRegion = new Region(captureBounds)) {
- // Exclude every visible part
- foreach (Screen screen in screensInsideCapture) {
- captureRegion.Exclude(screen.Bounds);
- }
- // If the region is not empty, we have "offscreenContent"
- using (Graphics screenGraphics = Graphics.FromHwnd(User32.GetDesktopWindow())) {
- offscreenContent = !captureRegion.IsEmpty(screenGraphics);
- }
- }
- // Check if we need to have a transparent background, needed for offscreen content
- if (offscreenContent) {
- using (Bitmap tmpBitmap = Bitmap.FromHbitmap(hDIBSection)) {
- // Create a new bitmap which has a transparent background
- returnBitmap = ImageHelper.CreateEmpty(tmpBitmap.Width, tmpBitmap.Height, PixelFormat.Format32bppArgb, Color.Transparent, tmpBitmap.HorizontalResolution, tmpBitmap.VerticalResolution);
- // Content will be copied here
- using (Graphics graphics = Graphics.FromImage(returnBitmap)) {
- // For all screens copy the content to the new bitmap
+
+ // get a .NET image object for it
+ // A suggestion for the "A generic error occurred in GDI+." E_FAIL/0×80004005 error is to re-try...
+ bool success = false;
+ ExternalException exception = null;
+ for (int i = 0; i < 3; i++) {
+ try {
+ // Collect all screens inside this capture
+ List screensInsideCapture = new List();
foreach (Screen screen in Screen.AllScreens) {
- Rectangle screenBounds = screen.Bounds;
- // Make sure the bounds are offsetted to the capture bounds
- screenBounds.Offset(-captureBounds.X, -captureBounds.Y);
- graphics.DrawImage(tmpBitmap, screenBounds, screenBounds.X, screenBounds.Y, screenBounds.Width, screenBounds.Height, GraphicsUnit.Pixel);
+ if (screen.Bounds.IntersectsWith(captureBounds)) {
+ screensInsideCapture.Add(screen);
+ }
}
+ // Check all all screens are of an equal size
+ bool offscreenContent = false;
+ using (Region captureRegion = new Region(captureBounds)) {
+ // Exclude every visible part
+ foreach (Screen screen in screensInsideCapture) {
+ captureRegion.Exclude(screen.Bounds);
+ }
+ // If the region is not empty, we have "offscreenContent"
+ using (Graphics screenGraphics = Graphics.FromHwnd(User32.GetDesktopWindow())) {
+ offscreenContent = !captureRegion.IsEmpty(screenGraphics);
+ }
+ }
+ // Check if we need to have a transparent background, needed for offscreen content
+ if (offscreenContent) {
+ using (Bitmap tmpBitmap = Bitmap.FromHbitmap(safeDibSectionHandle.DangerousGetHandle())) {
+ // Create a new bitmap which has a transparent background
+ returnBitmap = ImageHelper.CreateEmpty(tmpBitmap.Width, tmpBitmap.Height, PixelFormat.Format32bppArgb, Color.Transparent, tmpBitmap.HorizontalResolution, tmpBitmap.VerticalResolution);
+ // Content will be copied here
+ using (Graphics graphics = Graphics.FromImage(returnBitmap)) {
+ // For all screens copy the content to the new bitmap
+ foreach (Screen screen in Screen.AllScreens) {
+ Rectangle screenBounds = screen.Bounds;
+ // Make sure the bounds are offsetted to the capture bounds
+ screenBounds.Offset(-captureBounds.X, -captureBounds.Y);
+ graphics.DrawImage(tmpBitmap, screenBounds, screenBounds.X, screenBounds.Y, screenBounds.Width, screenBounds.Height, GraphicsUnit.Pixel);
+ }
+ }
+ }
+ } else {
+ // All screens, which are inside the capture, are of equal size
+ // assign image to Capture, the image will be disposed there..
+ returnBitmap = Bitmap.FromHbitmap(safeDibSectionHandle.DangerousGetHandle());
+ }
+ // We got through the capture without exception
+ success = true;
+ break;
+ } catch (ExternalException ee) {
+ LOG.Warn("Problem getting bitmap at try " + i + " : ", ee);
+ exception = ee;
}
}
- } else {
- // All screens, which are inside the capture, are of equal size
- // assign image to Capture, the image will be disposed there..
- returnBitmap = Bitmap.FromHbitmap(hDIBSection);
+ if (!success) {
+ LOG.Error("Still couldn't create Bitmap!");
+ throw exception;
+ }
}
- // We got through the capture without exception
- success = true;
- break;
- } catch (ExternalException ee) {
- LOG.Warn("Problem getting bitmap at try " + i + " : ", ee);
- exception = ee;
}
}
- if (!success) {
- LOG.Error("Still couldn't create Bitmap!");
- throw exception;
- }
- // free up the Bitmap object
- GDI32.DeleteObject(hDIBSection);
-
}
return returnBitmap;
}
diff --git a/GreenshotPlugin/Core/WindowsHelper.cs b/GreenshotPlugin/Core/WindowsHelper.cs
index bd9c79562..6f90f1a93 100644
--- a/GreenshotPlugin/Core/WindowsHelper.cs
+++ b/GreenshotPlugin/Core/WindowsHelper.cs
@@ -1224,15 +1224,15 @@ namespace GreenshotPlugin.Core {
/// Get the region for a window
///
private Region GetRegion() {
- IntPtr windowRegionPtr = GDI32.CreateRectRgn(0,0,0,0);
- RegionResult result = User32.GetWindowRgn(Handle, windowRegionPtr);
- Region returnRegion = null;
- if (result != RegionResult.REGION_ERROR && result != RegionResult.REGION_NULLREGION) {
- returnRegion = Region.FromHrgn(windowRegionPtr);
+ using (SafeRegionHandle region = GDI32.CreateRectRgn(0, 0, 0, 0)) {
+ if (!region.IsInvalid) {
+ RegionResult result = User32.GetWindowRgn(Handle, region);
+ if (result != RegionResult.REGION_ERROR && result != RegionResult.REGION_NULLREGION) {
+ return Region.FromHrgn(region.DangerousGetHandle());
+ }
+ }
}
- // Free the region object
- GDI32.DeleteObject(windowRegionPtr);
- return returnRegion;
+ return null;
}
private bool CanFreezeOrUnfreeze(string titleOrProcessname) {
diff --git a/GreenshotPlugin/UnmanagedHelpers/GDI32.cs b/GreenshotPlugin/UnmanagedHelpers/GDI32.cs
index 583ea4ff3..af334e20b 100644
--- a/GreenshotPlugin/UnmanagedHelpers/GDI32.cs
+++ b/GreenshotPlugin/UnmanagedHelpers/GDI32.cs
@@ -26,6 +26,13 @@ using Microsoft.Win32.SafeHandles;
namespace GreenshotPlugin.UnmanagedHelpers {
public static class GDIExtensions {
+ ///
+ /// Check if all the corners of the rectangle are visible in the specified region.
+ /// Not a perfect check, but this currently a workaround for checking if a window is completely visible
+ ///
+ ///
+ ///
+ ///
public static bool AreRectangleCornersVisisble(this Region region, Rectangle rectangle) {
Point topLeft = new Point(rectangle.X, rectangle.Y);
Point topRight = new Point(rectangle.X + rectangle.Width, rectangle.Y);
@@ -38,103 +45,210 @@ namespace GreenshotPlugin.UnmanagedHelpers {
return topLeftVisible && topRightVisible && bottomLeftVisible && bottomRightVisible;
}
+
+ ///
+ /// Get a SafeHandle for the GetHdc, so one can use using to automatically cleanup the devicecontext
+ ///
+ ///
+ /// SafeDeviceContextHandle
+ public static SafeDeviceContextHandle getSafeDeviceContext(this Graphics graphics) {
+ return SafeDeviceContextHandle.fromGraphics(graphics);
+ }
}
-
+
+ ///
+ /// Abstract class SafeObjectHandle which contains all handles that are cleaned with DeleteObject
+ ///
+ public abstract class SafeObjectHandle : SafeHandleZeroOrMinusOneIsInvalid {
+ [DllImport("gdi32", SetLastError = true)]
+ private static extern bool DeleteObject(IntPtr hObject);
+
+ protected SafeObjectHandle(bool ownsHandle) : base(ownsHandle) {
+ }
+
+ protected override bool ReleaseHandle() {
+ return DeleteObject(handle);
+ }
+ }
+
///
/// A hbitmap SafeHandle implementation
///
- public class SafeHBitmapHandle : SafeHandleZeroOrMinusOneIsInvalid {
- [SecurityCritical]
- private SafeHBitmapHandle(): base(true) {
- }
+ public class SafeHBitmapHandle : SafeObjectHandle {
+ [SecurityCritical]
+ private SafeHBitmapHandle() : base(true) {
+ }
- [SecurityCritical]
- public SafeHBitmapHandle(IntPtr preexistingHandle) : base(true) {
- SetHandle(preexistingHandle);
- }
-
- protected override bool ReleaseHandle() {
- return GDI32.DeleteObject(handle);
- }
+ [SecurityCritical]
+ public SafeHBitmapHandle(IntPtr preexistingHandle) : base(true) {
+ SetHandle(preexistingHandle);
+ }
}
+ ///
+ /// A hRegion SafeHandle implementation
+ ///
+ public class SafeRegionHandle : SafeObjectHandle {
+ [SecurityCritical]
+ private SafeRegionHandle() : base(true) {
+ }
+
+ [SecurityCritical]
+ public SafeRegionHandle(IntPtr preexistingHandle) : base(true) {
+ SetHandle(preexistingHandle);
+ }
+ }
+
+ ///
+ /// A dibsection SafeHandle implementation
+ ///
+ public class SafeDibSectionHandle : SafeObjectHandle {
+ [SecurityCritical]
+ private SafeDibSectionHandle() : base(true) {
+ }
+
+ [SecurityCritical]
+ public SafeDibSectionHandle(IntPtr preexistingHandle) : base(true) {
+ SetHandle(preexistingHandle);
+ }
+ }
+
+ ///
+ /// A select object safehandle implementation
+ /// This impl will select the passed SafeHandle to the HDC and replace the returned value when disposing
+ ///
+ public class SafeSelectObjectHandle : SafeHandleZeroOrMinusOneIsInvalid {
+ [DllImport("gdi32", SetLastError = true)]
+ private static extern IntPtr SelectObject(IntPtr hDC, IntPtr hObject);
+
+ private SafeHandle hdc;
+
+ [SecurityCritical]
+ private SafeSelectObjectHandle() : base(true) {
+ }
+
+ [SecurityCritical]
+ public SafeSelectObjectHandle(SafeDCHandle hdc, SafeHandle newHandle) : base(true) {
+ this.hdc = hdc;
+ SetHandle(SelectObject(hdc.DangerousGetHandle(), newHandle.DangerousGetHandle()));
+ }
+
+ protected override bool ReleaseHandle() {
+ SelectObject(hdc.DangerousGetHandle(), handle);
+ return true;
+ }
+ }
+
+ public abstract class SafeDCHandle : SafeHandleZeroOrMinusOneIsInvalid {
+ protected SafeDCHandle(bool ownsHandle) : base(ownsHandle) {
+ }
+ }
+ ///
+ /// A CompatibleDC SafeHandle implementation
+ ///
+ public class SafeCompatibleDCHandle : SafeDCHandle {
+ [DllImport("gdi32", SetLastError = true)]
+ private static extern bool DeleteDC(IntPtr hDC);
+
+ [SecurityCritical]
+ private SafeCompatibleDCHandle() : base(true) {
+ }
+
+ [SecurityCritical]
+ public SafeCompatibleDCHandle(IntPtr preexistingHandle) : base(true) {
+ SetHandle(preexistingHandle);
+ }
+
+ public SafeSelectObjectHandle SelectObject(SafeHandle newHandle) {
+ return new SafeSelectObjectHandle(this, newHandle);
+ }
+
+ protected override bool ReleaseHandle() {
+ return DeleteDC(handle);
+ }
+ }
+
+ ///
+ /// A DeviceContext SafeHandle implementation
+ ///
+ public class SafeDeviceContextHandle : SafeDCHandle {
+ private Graphics graphics = null;
+ [SecurityCritical]
+ private SafeDeviceContextHandle() : base(true) {
+ }
+
+ [SecurityCritical]
+ public SafeDeviceContextHandle(Graphics graphics, IntPtr preexistingHandle) : base(true) {
+ this.graphics = graphics;
+ SetHandle(preexistingHandle);
+ }
+
+ protected override bool ReleaseHandle() {
+ graphics.ReleaseHdc(handle);
+ return true;
+ }
+
+ public SafeSelectObjectHandle SelectObject(SafeHandle newHandle) {
+ return new SafeSelectObjectHandle(this, newHandle);
+ }
+
+ public static SafeDeviceContextHandle fromGraphics(Graphics graphics) {
+ return new SafeDeviceContextHandle(graphics, graphics.GetHdc());
+ }
+ }
+
///
/// GDI32 Helpers
///
public static class GDI32 {
[DllImport("gdi32", SetLastError=true)]
- public static extern bool BitBlt(IntPtr hObject,int nXDest,int nYDest, int nWidth,int nHeight,IntPtr hObjectSource, int nXSrc,int nYSrc, CopyPixelOperation dwRop);
+ public static extern bool BitBlt(SafeHandle hObject, int nXDest, int nYDest, int nWidth, int nHeight, SafeHandle hdcSrc, int nXSrc, int nYSrc, CopyPixelOperation dwRop);
[DllImport("gdi32", SetLastError=true)]
- public static extern bool StretchBlt(IntPtr hdcDest, int nXOriginDest, int nYOriginDest, int nWidthDest, int nHeightDest, IntPtr hdcSrc, int nXOriginSrc, int nYOriginSrc, int nWidthSrc, int nHeightSrc, CopyPixelOperation dwRop );
+ public static extern bool StretchBlt(SafeHandle hdcDest, int nXOriginDest, int nYOriginDest, int nWidthDest, int nHeightDest, SafeHandle hdcSrc, int nXOriginSrc, int nYOriginSrc, int nWidthSrc, int nHeightSrc, CopyPixelOperation dwRop);
[DllImport("gdi32", SetLastError=true)]
- public static extern IntPtr CreateCompatibleDC(IntPtr hDC);
+ public static extern SafeCompatibleDCHandle CreateCompatibleDC(SafeHandle hDC);
[DllImport("gdi32", SetLastError=true)]
- public static extern bool DeleteDC(IntPtr hDC);
+ public static extern IntPtr SelectObject(SafeHandle hDC, SafeHandle hObject);
[DllImport("gdi32", SetLastError=true)]
- public static extern bool DeleteObject(IntPtr hObject);
+ public static extern SafeDibSectionHandle CreateDIBSection(SafeHandle hdc, ref BitmapInfoHeader bmi, uint Usage, out IntPtr bits, IntPtr hSection, uint dwOffset);
[DllImport("gdi32", SetLastError=true)]
- public static extern IntPtr SelectObject(IntPtr hDC,IntPtr hObject);
+ public static extern SafeRegionHandle CreateRectRgn(int nLeftRect, int nTopRect, int nRightRect, int nBottomRect);
[DllImport("gdi32", SetLastError=true)]
- public static extern IntPtr CreateDIBSection(IntPtr hdc, ref BitmapInfoHeader bmi, uint Usage, out IntPtr bits, IntPtr hSection, uint dwOffset);
+ public static extern uint GetPixel(SafeHandle hdc, int nXPos, int nYPos);
[DllImport("gdi32", SetLastError=true)]
- public static extern IntPtr CreateRectRgn(int nLeftRect, int nTopRect, int nRightRect, int nBottomRect);
- [DllImport("gdi32", SetLastError=true)]
- public static extern int GetClipBox(IntPtr hdc, out RECT lprc);
- [DllImport("gdi32", SetLastError = true)]
- public static extern uint GetPixel(IntPtr hdc, int nXPos, int nYPos);
- [DllImport("gdi32", SetLastError = true)]
- public static extern IntPtr CreateRoundRectRgn(int x1, int y1, int x2, int y2, int cx, int cy);
- [DllImport("gdi32", SetLastError = true)]
- public static extern int GetDeviceCaps(IntPtr hdc, DeviceCaps nIndex);
+ public static extern int GetDeviceCaps(SafeHandle hdc, DeviceCaps nIndex);
///
+ /// StretchBlt extension for the graphics object
/// Doesn't work?
///
///
///
public static void StretchBlt(this Graphics target, Bitmap sourceBitmap, Rectangle source, Rectangle destination) {
- IntPtr hDCSrc = IntPtr.Zero;
- IntPtr hDCDest = IntPtr.Zero;
- try {
- hDCDest = target.GetHdc();
- hDCSrc = CreateCompatibleDC(hDCDest);
- 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);
- }
- if (hDCDest != IntPtr.Zero) {
- target.ReleaseHdc(hDCDest);
+ using (SafeDeviceContextHandle targetDC = target.getSafeDeviceContext()) {
+ using (SafeCompatibleDCHandle safeCompatibleDCHandle = CreateCompatibleDC(targetDC)) {
+ using (SafeHBitmapHandle hBitmapHandle = new SafeHBitmapHandle(sourceBitmap.GetHbitmap())) {
+ using (SafeSelectObjectHandle selectObject = safeCompatibleDCHandle.SelectObject(hBitmapHandle)) {
+ StretchBlt(targetDC, destination.X, destination.Y, destination.Width, destination.Height, safeCompatibleDCHandle, source.Left, source.Top, source.Width, source.Height, CopyPixelOperation.SourceCopy);
+ }
+ }
}
}
}
///
- ///
+ /// Bitblt extension for the graphics object
///
///
///
public static void BitBlt(this Graphics target, Bitmap sourceBitmap, Rectangle source, Point destination) {
- IntPtr hDCSrc = IntPtr.Zero;
- IntPtr hDCDest = IntPtr.Zero;
- try {
- hDCDest = target.GetHdc();
- hDCSrc = CreateCompatibleDC(hDCDest);
- 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);
- }
- if (hDCDest != IntPtr.Zero) {
- target.ReleaseHdc(hDCDest);
+ using (SafeDeviceContextHandle targetDC = target.getSafeDeviceContext()) {
+ using (SafeCompatibleDCHandle safeCompatibleDCHandle = CreateCompatibleDC(targetDC)) {
+ using (SafeHBitmapHandle hBitmapHandle = new SafeHBitmapHandle(sourceBitmap.GetHbitmap())) {
+ using (SafeSelectObjectHandle selectObject = safeCompatibleDCHandle.SelectObject(hBitmapHandle)) {
+ BitBlt(safeCompatibleDCHandle, destination.X, destination.Y, source.Width, source.Height, safeCompatibleDCHandle, source.Left, source.Top, CopyPixelOperation.SourceCopy);
+ }
+ }
}
}
}
diff --git a/GreenshotPlugin/UnmanagedHelpers/User32.cs b/GreenshotPlugin/UnmanagedHelpers/User32.cs
index 729aff5fe..3628727e3 100644
--- a/GreenshotPlugin/UnmanagedHelpers/User32.cs
+++ b/GreenshotPlugin/UnmanagedHelpers/User32.cs
@@ -26,6 +26,7 @@ using System.Runtime.InteropServices;
using System.Text;
using Microsoft.Win32.SafeHandles;
+using System.Security;
namespace GreenshotPlugin.UnmanagedHelpers {
///
@@ -36,38 +37,10 @@ namespace GreenshotPlugin.UnmanagedHelpers {
///
public delegate int EnumWindowsProc(IntPtr hwnd, int lParam);
- ///
- /// Used with SetWinEventHook
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- 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
///
- public class User32 {
+ public static class User32 {
public const int SC_RESTORE = 0xF120;
public const int SC_CLOSE = 0xF060;
public const int SC_MAXIMIZE = 0xF030;
@@ -166,11 +139,7 @@ namespace GreenshotPlugin.UnmanagedHelpers {
[DllImport("user32", SetLastError=true, EntryPoint = "PostMessageA")]
public static extern bool PostMessage(IntPtr hWnd, uint msg, int wParam, int lParam);
[DllImport("user32", SetLastError = true)]
- public static extern RegionResult GetWindowRgn(IntPtr hWnd, IntPtr hRgn);
- [DllImport("user32", SetLastError = true)]
- public static extern IntPtr GetWindowDC(IntPtr hWnd);
- [DllImport("user32", SetLastError = true)]
- public static extern IntPtr ReleaseDC(IntPtr hWnd,IntPtr hDC);
+ public static extern RegionResult GetWindowRgn(IntPtr hWnd, SafeHandle hRgn);
[DllImport("user32", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, WindowPos uFlags);
@@ -236,8 +205,6 @@ namespace GreenshotPlugin.UnmanagedHelpers {
[DllImport("user32", SetLastError = true)]
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)]
public static extern IntPtr SetCapture(IntPtr hWnd);
[DllImport("user32", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
@@ -306,4 +273,64 @@ namespace GreenshotPlugin.UnmanagedHelpers {
return exceptionToThrow;
}
}
+
+ ///
+ /// Used with SetWinEventHook
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ 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);
+ }
+ }
+
+ ///
+ /// A WindowDC SafeHandle implementation
+ ///
+ public class SafeWindowDCHandle : SafeHandleZeroOrMinusOneIsInvalid {
+ [DllImport("user32", SetLastError = true)]
+ private static extern IntPtr GetWindowDC(IntPtr hWnd);
+ [DllImport("user32", SetLastError = true)]
+ private static extern bool ReleaseDC(IntPtr hWnd, IntPtr hDC);
+
+ private IntPtr hWnd;
+ [SecurityCritical]
+ private SafeWindowDCHandle() : base(true) {
+ }
+
+ [SecurityCritical]
+ public SafeWindowDCHandle(IntPtr hWnd, IntPtr preexistingHandle) : base(true) {
+ this.hWnd = hWnd;
+ SetHandle(preexistingHandle);
+ }
+
+ protected override bool ReleaseHandle() {
+ bool returnValue = ReleaseDC(hWnd, handle);
+ return returnValue;
+ }
+
+ public static SafeWindowDCHandle fromDesktop() {
+ IntPtr hWndDesktop = User32.GetDesktopWindow();
+ IntPtr hDCDesktop = GetWindowDC(hWndDesktop);
+ return new SafeWindowDCHandle(hWndDesktop, hDCDesktop);
+ }
+ }
}