This commit allows us to experiment with different screen capture methods via plugins. e.g. a Desktop-Duplication API implementation could be supplied for Windows 8, which might capture DirectX better.

This commit is contained in:
RKrom 2014-12-03 22:40:32 +01:00
commit fc0791bdb6
6 changed files with 242 additions and 194 deletions

View file

@ -806,7 +806,7 @@ namespace Greenshot.Helpers {
windowCaptureMode = WindowCaptureMode.Screen; windowCaptureMode = WindowCaptureMode.Screen;
// Change to GDI, if allowed // Change to GDI, if allowed
if (!windowToCapture.isMetroApp && WindowCapture.isGDIAllowed(process)) { if (!windowToCapture.isMetroApp && WindowCapture.IsGdiAllowed(process)) {
if (!dwmEnabled && isWPF(process)) { if (!dwmEnabled && isWPF(process)) {
// do not use GDI, as DWM is not enabled and the application uses PresentationFramework.dll -> isWPF // do not use GDI, as DWM is not enabled and the application uses PresentationFramework.dll -> isWPF
LOG.InfoFormat("Not using GDI for windows of process {0}, as the process uses WPF", process.ProcessName); LOG.InfoFormat("Not using GDI for windows of process {0}, as the process uses WPF", process.ProcessName);
@ -817,20 +817,20 @@ namespace Greenshot.Helpers {
// Change to DWM, if enabled and allowed // Change to DWM, if enabled and allowed
if (dwmEnabled) { if (dwmEnabled) {
if (windowToCapture.isMetroApp || WindowCapture.isDWMAllowed(process)) { if (windowToCapture.isMetroApp || WindowCapture.IsDwmAllowed(process)) {
windowCaptureMode = WindowCaptureMode.Aero; windowCaptureMode = WindowCaptureMode.Aero;
} }
} }
} else if (windowCaptureMode == WindowCaptureMode.Aero || windowCaptureMode == WindowCaptureMode.AeroTransparent) { } else if (windowCaptureMode == WindowCaptureMode.Aero || windowCaptureMode == WindowCaptureMode.AeroTransparent) {
if (!dwmEnabled || (!windowToCapture.isMetroApp && !WindowCapture.isDWMAllowed(process))) { if (!dwmEnabled || (!windowToCapture.isMetroApp && !WindowCapture.IsDwmAllowed(process))) {
// Take default screen // Take default screen
windowCaptureMode = WindowCaptureMode.Screen; windowCaptureMode = WindowCaptureMode.Screen;
// Change to GDI, if allowed // Change to GDI, if allowed
if (WindowCapture.isGDIAllowed(process)) { if (WindowCapture.IsGdiAllowed(process)) {
windowCaptureMode = WindowCaptureMode.GDI; windowCaptureMode = WindowCaptureMode.GDI;
} }
} }
} else if (windowCaptureMode == WindowCaptureMode.GDI && !WindowCapture.isGDIAllowed(process)) { } else if (windowCaptureMode == WindowCaptureMode.GDI && !WindowCapture.IsGdiAllowed(process)) {
// GDI not allowed, take screen // GDI not allowed, take screen
windowCaptureMode = WindowCaptureMode.Screen; windowCaptureMode = WindowCaptureMode.Screen;
} }
@ -843,7 +843,7 @@ namespace Greenshot.Helpers {
ICapture tmpCapture = null; ICapture tmpCapture = null;
switch (windowCaptureMode) { switch (windowCaptureMode) {
case WindowCaptureMode.GDI: case WindowCaptureMode.GDI:
if (WindowCapture.isGDIAllowed(process)) { if (WindowCapture.IsGdiAllowed(process)) {
if (windowToCapture.Iconic) { if (windowToCapture.Iconic) {
// Restore the window making sure it's visible! // Restore the window making sure it's visible!
windowToCapture.Restore(); windowToCapture.Restore();
@ -853,15 +853,15 @@ namespace Greenshot.Helpers {
tmpCapture = windowToCapture.CaptureGDIWindow(captureForWindow); tmpCapture = windowToCapture.CaptureGDIWindow(captureForWindow);
if (tmpCapture != null) { if (tmpCapture != null) {
// check if GDI capture any good, by comparing it with the screen content // check if GDI capture any good, by comparing it with the screen content
int blackCountGDI = ImageHelper.CountColor((Bitmap)tmpCapture.Image, Color.Black, false); int blackCountGDI = ImageHelper.CountColor(tmpCapture.Image, Color.Black, false);
int GDIPixels = tmpCapture.Image.Width * tmpCapture.Image.Height; int GDIPixels = tmpCapture.Image.Width * tmpCapture.Image.Height;
int blackPercentageGDI = (blackCountGDI * 100) / GDIPixels; int blackPercentageGDI = (blackCountGDI * 100) / GDIPixels;
if (blackPercentageGDI >= 1) { if (blackPercentageGDI >= 1) {
int screenPixels = windowRectangle.Width * windowRectangle.Height; int screenPixels = windowRectangle.Width * windowRectangle.Height;
using (ICapture screenCapture = new Capture()) { using (ICapture screenCapture = new Capture()) {
screenCapture.CaptureDetails = captureForWindow.CaptureDetails; screenCapture.CaptureDetails = captureForWindow.CaptureDetails;
if (WindowCapture.CaptureRectangle(screenCapture, windowRectangle) != null) { if (WindowCapture.CaptureRectangleFromDesktopScreen(screenCapture, windowRectangle) != null) {
int blackCountScreen = ImageHelper.CountColor((Bitmap)screenCapture.Image, Color.Black, false); int blackCountScreen = ImageHelper.CountColor(screenCapture.Image, Color.Black, false);
int blackPercentageScreen = (blackCountScreen * 100) / screenPixels; int blackPercentageScreen = (blackCountScreen * 100) / screenPixels;
if (screenPixels == GDIPixels) { if (screenPixels == GDIPixels) {
// "easy compare", both have the same size // "easy compare", both have the same size
@ -901,7 +901,7 @@ namespace Greenshot.Helpers {
break; break;
case WindowCaptureMode.Aero: case WindowCaptureMode.Aero:
case WindowCaptureMode.AeroTransparent: case WindowCaptureMode.AeroTransparent:
if (windowToCapture.isMetroApp || WindowCapture.isDWMAllowed(process)) { if (windowToCapture.isMetroApp || WindowCapture.IsDwmAllowed(process)) {
tmpCapture = windowToCapture.CaptureDWMWindow(captureForWindow, windowCaptureMode, isAutoMode); tmpCapture = windowToCapture.CaptureDWMWindow(captureForWindow, windowCaptureMode, isAutoMode);
} }
if (tmpCapture != null) { if (tmpCapture != null) {
@ -922,7 +922,7 @@ namespace Greenshot.Helpers {
} }
try { try {
captureForWindow = WindowCapture.CaptureRectangle(captureForWindow, windowRectangle); captureForWindow = WindowCapture.CaptureRectangleFromDesktopScreen(captureForWindow, windowRectangle);
captureTaken = true; captureTaken = true;
} catch (Exception e) { } catch (Exception e) {
LOG.Error("Problem capturing", e); LOG.Error("Problem capturing", e);

View file

@ -0,0 +1,44 @@
/*
* Greenshot - a free and open source screenshot tool
* Copyright (C) 2007-2014 Thomas Braun, Jens Klingen, Robin Krom
*
* For more information see: http://getgreenshot.org/
* The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using System.Drawing;
namespace GreenshotPlugin.Core {
/// <summary>
/// This is the method signature which is used to capture a rectangle from the screen.
/// </summary>
/// <param name="captureBounds"></param>
/// <returns>Captured Bitmap</returns>
public delegate Bitmap CaptureScreenRectangleHandler(Rectangle captureBounds);
/// <summary>
/// This is a hack to experiment with different screen capture routines
/// </summary>
public static class CaptureHandler {
/// <summary>
/// By changing this value, null is default
/// </summary>
public static CaptureScreenRectangleHandler CaptureScreenRectangle {
get;
set;
}
}
}

View file

@ -18,6 +18,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;

View file

@ -37,43 +37,31 @@ namespace GreenshotPlugin.Core {
/// The time the Capture was taken and the Title of the window (or a region of) that is captured /// The time the Capture was taken and the Title of the window (or a region of) that is captured
/// </summary> /// </summary>
public class CaptureDetails : ICaptureDetails { public class CaptureDetails : ICaptureDetails {
private string title;
public string Title { public string Title {
get {return title;} get;
set {title = value;} set;
} }
private string filename;
public string Filename { public string Filename {
get {return filename;} get;
set {filename = value;} set;
} }
private DateTime dateTime;
public DateTime DateTime { public DateTime DateTime {
get {return dateTime;} get;
set {dateTime = value;} set;
} }
private float dpiX;
public float DpiX { public float DpiX {
get { get;
return dpiX; set;
}
set {
dpiX = value;
}
} }
private float dpiY;
public float DpiY { public float DpiY {
get { get;
return dpiY; set;
}
set {
dpiY = value;
}
} }
private Dictionary<string, string> metaData = new Dictionary<string, string>(); private Dictionary<string, string> metaData = new Dictionary<string, string>();
public Dictionary<string, string> MetaData { public Dictionary<string, string> MetaData {
get {return metaData;} get {return metaData;}
@ -87,36 +75,35 @@ namespace GreenshotPlugin.Core {
} }
} }
private CaptureMode captureMode;
public CaptureMode CaptureMode { public CaptureMode CaptureMode {
get {return captureMode;} get;
set {captureMode = value;} set;
} }
private List<IDestination> captureDestinations = new List<IDestination>(); private List<IDestination> _captureDestinations = new List<IDestination>();
public List<IDestination> CaptureDestinations { public List<IDestination> CaptureDestinations {
get {return captureDestinations;} get {return _captureDestinations;}
set {captureDestinations = value;} set {_captureDestinations = value;}
} }
public void ClearDestinations() { public void ClearDestinations() {
captureDestinations.Clear(); _captureDestinations.Clear();
} }
public void RemoveDestination(IDestination destination) { public void RemoveDestination(IDestination destination) {
if (captureDestinations.Contains(destination)) { if (_captureDestinations.Contains(destination)) {
captureDestinations.Remove(destination); _captureDestinations.Remove(destination);
} }
} }
public void AddDestination(IDestination captureDestination) { public void AddDestination(IDestination captureDestination) {
if (!captureDestinations.Contains(captureDestination)) { if (!_captureDestinations.Contains(captureDestination)) {
captureDestinations.Add(captureDestination); _captureDestinations.Add(captureDestination);
} }
} }
public bool HasDestination(string designation) { public bool HasDestination(string designation) {
foreach(IDestination destination in captureDestinations) { foreach(IDestination destination in _captureDestinations) {
if (designation.Equals(destination.Designation)) { if (designation.Equals(destination.Designation)) {
return true; return true;
} }
@ -125,7 +112,7 @@ namespace GreenshotPlugin.Core {
} }
public CaptureDetails() { public CaptureDetails() {
dateTime = DateTime.Now; DateTime = DateTime.Now;
} }
} }
@ -133,47 +120,47 @@ namespace GreenshotPlugin.Core {
/// This class is used to pass an instance of the "Capture" around /// This class is used to pass an instance of the "Capture" around
/// Having the Bitmap, eventually the Windows Title and cursor all together. /// Having the Bitmap, eventually the Windows Title and cursor all together.
/// </summary> /// </summary>
public class Capture : IDisposable, ICapture { public class Capture : ICapture {
private static ILog LOG = LogManager.GetLogger(typeof(Capture)); private static readonly ILog LOG = LogManager.GetLogger(typeof(Capture));
private List<ICaptureElement> elements = new List<ICaptureElement>(); private List<ICaptureElement> _elements = new List<ICaptureElement>();
private Rectangle screenBounds; private Rectangle _screenBounds = Rectangle.Empty;
/// <summary> /// <summary>
/// Get/Set the Screenbounds /// Get/Set the Screenbounds
/// </summary> /// </summary>
public Rectangle ScreenBounds { public Rectangle ScreenBounds {
get { get {
if (screenBounds == null) { if (_screenBounds == Rectangle.Empty) {
screenBounds = WindowCapture.GetScreenBounds(); _screenBounds = WindowCapture.GetScreenBounds();
} }
return screenBounds; return _screenBounds;
} }
set {screenBounds = value;} set {_screenBounds = value;}
} }
private Image image; private Image _image;
/// <summary> /// <summary>
/// Get/Set the Image /// Get/Set the Image
/// </summary> /// </summary>
public Image Image { public Image Image {
get {return image;} get {return _image;}
set { set {
if (image != null) { if (_image != null) {
image.Dispose(); _image.Dispose();
} }
image = value; _image = value;
if (value != null) { if (value != null) {
if (value.PixelFormat.Equals(PixelFormat.Format8bppIndexed) || value.PixelFormat.Equals(PixelFormat.Format1bppIndexed) || value.PixelFormat.Equals(PixelFormat.Format4bppIndexed)) { if (value.PixelFormat.Equals(PixelFormat.Format8bppIndexed) || value.PixelFormat.Equals(PixelFormat.Format1bppIndexed) || value.PixelFormat.Equals(PixelFormat.Format4bppIndexed)) {
LOG.Debug("Converting Bitmap to PixelFormat.Format32bppArgb as we don't support: " + value.PixelFormat); LOG.Debug("Converting Bitmap to PixelFormat.Format32bppArgb as we don't support: " + value.PixelFormat);
try { try {
// Default Bitmap PixelFormat is Format32bppArgb // Default Bitmap PixelFormat is Format32bppArgb
image = new Bitmap(value); _image = new Bitmap(value);
} finally { } finally {
// Always dispose, even when a exception occured // Always dispose, even when a exception occured
value.Dispose(); value.Dispose();
} }
} }
LOG.DebugFormat("Image is set with the following specifications: {0} - {1}", image.Size, image.PixelFormat); LOG.DebugFormat("Image is set with the following specifications: {0} - {1}", _image.Size, _image.PixelFormat);
} else { } else {
LOG.Debug("Image is removed."); LOG.Debug("Image is removed.");
} }
@ -181,65 +168,65 @@ namespace GreenshotPlugin.Core {
} }
public void NullImage() { public void NullImage() {
image = null; _image = null;
} }
private Icon cursor; private Icon _cursor;
/// <summary> /// <summary>
/// Get/Set the image for the Cursor /// Get/Set the image for the Cursor
/// </summary> /// </summary>
public Icon Cursor { public Icon Cursor {
get {return cursor;} get {return _cursor;}
set { set {
if (cursor != null) { if (_cursor != null) {
cursor.Dispose(); _cursor.Dispose();
} }
cursor = (Icon)value.Clone(); _cursor = (Icon)value.Clone();
} }
} }
private bool cursorVisible = false; private bool _cursorVisible;
/// <summary> /// <summary>
/// Set if the cursor is visible /// Set if the cursor is visible
/// </summary> /// </summary>
public bool CursorVisible { public bool CursorVisible {
get {return cursorVisible;} get {return _cursorVisible;}
set {cursorVisible = value;} set {_cursorVisible = value;}
} }
private Point cursorLocation = Point.Empty; private Point _cursorLocation = Point.Empty;
/// <summary> /// <summary>
/// Get/Set the CursorLocation /// Get/Set the CursorLocation
/// </summary> /// </summary>
public Point CursorLocation { public Point CursorLocation {
get {return cursorLocation;} get {return _cursorLocation;}
set {cursorLocation = value;} set {_cursorLocation = value;}
} }
private Point location = Point.Empty; private Point _location = Point.Empty;
/// <summary> /// <summary>
/// Get/set the Location /// Get/set the Location
/// </summary> /// </summary>
public Point Location { public Point Location {
get {return location;} get {return _location;}
set {location = value;} set {_location = value;}
} }
private CaptureDetails captureDetails; private CaptureDetails _captureDetails;
/// <summary> /// <summary>
/// Get/set the CaptureDetails /// Get/set the CaptureDetails
/// </summary> /// </summary>
public ICaptureDetails CaptureDetails { public ICaptureDetails CaptureDetails {
get {return captureDetails;} get {return _captureDetails;}
set {captureDetails = (CaptureDetails)value;} set {_captureDetails = (CaptureDetails)value;}
} }
/// <summary> /// <summary>
/// Default Constructor /// Default Constructor
/// </summary> /// </summary>
public Capture() { public Capture() {
screenBounds = WindowCapture.GetScreenBounds(); _screenBounds = WindowCapture.GetScreenBounds();
captureDetails = new CaptureDetails(); _captureDetails = new CaptureDetails();
} }
/// <summary> /// <summary>
@ -274,15 +261,15 @@ namespace GreenshotPlugin.Core {
/// <param name="disposing"></param> /// <param name="disposing"></param>
protected virtual void Dispose(bool disposing) { protected virtual void Dispose(bool disposing) {
if (disposing) { if (disposing) {
if (image != null) { if (_image != null) {
image.Dispose(); _image.Dispose();
} }
if (cursor != null) { if (_cursor != null) {
cursor.Dispose(); _cursor.Dispose();
} }
} }
image = null; _image = null;
cursor = null; _cursor = null;
} }
/// <summary> /// <summary>
@ -291,8 +278,8 @@ namespace GreenshotPlugin.Core {
/// <param name="cropRectangle">Rectangle with bitmap coordinates</param> /// <param name="cropRectangle">Rectangle with bitmap coordinates</param>
public bool Crop(Rectangle cropRectangle) { public bool Crop(Rectangle cropRectangle) {
LOG.Debug("Cropping to: " + cropRectangle.ToString()); LOG.Debug("Cropping to: " + cropRectangle.ToString());
if (ImageHelper.Crop(ref image, ref cropRectangle)) { if (ImageHelper.Crop(ref _image, ref cropRectangle)) {
location = cropRectangle.Location; _location = cropRectangle.Location;
// Change mouse location according to the cropRegtangle (including screenbounds) offset // Change mouse location according to the cropRegtangle (including screenbounds) offset
MoveMouseLocation(-cropRectangle.Location.X, -cropRectangle.Location.Y); MoveMouseLocation(-cropRectangle.Location.X, -cropRectangle.Location.Y);
// Move all the elements // Move all the elements
@ -301,12 +288,12 @@ namespace GreenshotPlugin.Core {
// Remove invisible elements // Remove invisible elements
List <ICaptureElement> newElements = new List<ICaptureElement>(); List <ICaptureElement> newElements = new List<ICaptureElement>();
foreach(ICaptureElement captureElement in elements) { foreach(ICaptureElement captureElement in _elements) {
if (captureElement.Bounds.IntersectsWith(cropRectangle)) { if (captureElement.Bounds.IntersectsWith(cropRectangle)) {
newElements.Add(captureElement); newElements.Add(captureElement);
} }
} }
elements = newElements; _elements = newElements;
return true; return true;
} }
@ -320,7 +307,7 @@ namespace GreenshotPlugin.Core {
/// <param name="x">x coordinates to move the mouse</param> /// <param name="x">x coordinates to move the mouse</param>
/// <param name="y">y coordinates to move the mouse</param> /// <param name="y">y coordinates to move the mouse</param>
public void MoveMouseLocation(int x, int y) { public void MoveMouseLocation(int x, int y) {
cursorLocation.Offset(x, y); _cursorLocation.Offset(x, y);
} }
// TODO: Enable when the elements are usable again. // TODO: Enable when the elements are usable again.
@ -388,13 +375,13 @@ namespace GreenshotPlugin.Core {
Bounds = bounds; Bounds = bounds;
} }
private List<ICaptureElement> children = new List<ICaptureElement>(); private List<ICaptureElement> _children = new List<ICaptureElement>();
public List<ICaptureElement> Children { public List<ICaptureElement> Children {
get { get {
return children; return _children;
} }
set { set {
children = value; _children = value;
} }
} }
@ -410,9 +397,9 @@ namespace GreenshotPlugin.Core {
// CaptureElements are regarded equal if their bounds are equal. this should be sufficient. // CaptureElements are regarded equal if their bounds are equal. this should be sufficient.
public override bool Equals(object obj) { public override bool Equals(object obj) {
bool ret = false; bool ret = false;
if (obj != null && GetType().Equals(obj.GetType())) { if (obj != null && GetType() == obj.GetType()) {
CaptureElement other = obj as CaptureElement; CaptureElement other = obj as CaptureElement;
if (Bounds.Equals(other.Bounds)) { if (other != null && Bounds.Equals(other.Bounds)) {
ret = true; ret = true;
} }
} }
@ -428,7 +415,7 @@ namespace GreenshotPlugin.Core {
/// </summary> /// </summary>
public class WindowCapture { public class WindowCapture {
private static readonly ILog LOG = LogManager.GetLogger(typeof(WindowCapture)); private static readonly ILog LOG = LogManager.GetLogger(typeof(WindowCapture));
private static CoreConfiguration conf = IniConfig.GetIniSection<CoreConfiguration>(); private static readonly CoreConfiguration Configuration = IniConfig.GetIniSection<CoreConfiguration>();
/// <summary> /// <summary>
/// Used to cleanup the unmanged resource in the iconInfo for the CaptureCursor method /// Used to cleanup the unmanged resource in the iconInfo for the CaptureCursor method
@ -461,8 +448,10 @@ namespace GreenshotPlugin.Core {
/// <summary> /// <summary>
/// Retrieves the cursor location safely, accounting for DPI settings in Vista/Windows 7. This implementation /// Retrieves the cursor location safely, accounting for DPI settings in Vista/Windows 7. This implementation
/// can conveniently be used when the cursor location is needed to deal with a fullscreen bitmap. /// can conveniently be used when the cursor location is needed to deal with a fullscreen bitmap.
/// <returns>Point with cursor location, relative to the top left corner of the monitor setup (which itself might /// </summary>
/// actually not be on any screen)</returns> /// <returns>
/// Point with cursor location, relative to the top left corner of the monitor setup (which itself might actually not be on any screen)
/// </returns>
public static Point GetCursorLocationRelativeToScreenBounds() { public static Point GetCursorLocationRelativeToScreenBounds() {
return GetLocationRelativeToScreenBounds(User32.GetCursorLocation()); return GetLocationRelativeToScreenBounds(User32.GetCursorLocation());
} }
@ -537,7 +526,6 @@ namespace GreenshotPlugin.Core {
/// Helper method to create an exception that might explain what is wrong while capturing /// Helper method to create an exception that might explain what is wrong while capturing
/// </summary> /// </summary>
/// <param name="method">string with current method</param> /// <param name="method">string with current method</param>
/// <param name="capture">ICapture</param>
/// <param name="captureBounds">Rectangle of what we want to capture</param> /// <param name="captureBounds">Rectangle of what we want to capture</param>
/// <returns></returns> /// <returns></returns>
private static Exception CreateCaptureException(string method, Rectangle captureBounds) { private static Exception CreateCaptureException(string method, Rectangle captureBounds) {
@ -554,12 +542,12 @@ namespace GreenshotPlugin.Core {
/// </summary> /// </summary>
/// <param name="process">Process owning the window</param> /// <param name="process">Process owning the window</param>
/// <returns>true if it's allowed</returns> /// <returns>true if it's allowed</returns>
public static bool isDWMAllowed(Process process) { public static bool IsDwmAllowed(Process process) {
if (process != null) { if (process != null) {
if (conf.NoDWMCaptureForProduct != null && conf.NoDWMCaptureForProduct.Count > 0) { if (Configuration.NoDWMCaptureForProduct != null && Configuration.NoDWMCaptureForProduct.Count > 0) {
try { try {
string productName = process.MainModule.FileVersionInfo.ProductName; string productName = process.MainModule.FileVersionInfo.ProductName;
if (productName != null && conf.NoDWMCaptureForProduct.Contains(productName.ToLower())) { if (productName != null && Configuration.NoDWMCaptureForProduct.Contains(productName.ToLower())) {
return false; return false;
} }
} catch (Exception ex) { } catch (Exception ex) {
@ -573,14 +561,14 @@ namespace GreenshotPlugin.Core {
/// <summary> /// <summary>
/// Helper method to check if it is allowed to capture the process using GDI /// Helper method to check if it is allowed to capture the process using GDI
/// </summary> /// </summary>
/// <param name="processName">Process owning the window</param> /// <param name="process">Process owning the window</param>
/// <returns>true if it's allowed</returns> /// <returns>true if it's allowed</returns>
public static bool isGDIAllowed(Process process) { public static bool IsGdiAllowed(Process process) {
if (process != null) { if (process != null) {
if (conf.NoGDICaptureForProduct != null && conf.NoGDICaptureForProduct.Count > 0) { if (Configuration.NoGDICaptureForProduct != null && Configuration.NoGDICaptureForProduct.Count > 0) {
try { try {
string productName = process.MainModule.FileVersionInfo.ProductName; string productName = process.MainModule.FileVersionInfo.ProductName;
if (productName != null && conf.NoGDICaptureForProduct.Contains(productName.ToLower())) { if (productName != null && Configuration.NoGDICaptureForProduct.Contains(productName.ToLower())) {
return false; return false;
} }
} catch (Exception ex) { } catch (Exception ex) {
@ -598,6 +586,25 @@ namespace GreenshotPlugin.Core {
/// <param name="captureBounds">Rectangle with the bounds to capture</param> /// <param name="captureBounds">Rectangle with the bounds to capture</param>
/// <returns>A Capture Object with a part of the Screen as an Image</returns> /// <returns>A Capture Object with a part of the Screen as an Image</returns>
public static ICapture CaptureRectangle(ICapture capture, Rectangle captureBounds) { public static ICapture CaptureRectangle(ICapture capture, Rectangle captureBounds) {
if (capture == null) {
capture = new Capture();
}
// If the CaptureHandler has a handle use this, otherwise use the CaptureRectangle here
capture.Image = CaptureHandler.CaptureScreenRectangle != null ? CaptureHandler.CaptureScreenRectangle(captureBounds) : CaptureRectangle(captureBounds);
capture.Location = captureBounds.Location;
if (capture.CaptureDetails != null) {
((Bitmap)capture.Image).SetResolution(capture.CaptureDetails.DpiX, capture.CaptureDetails.DpiY);
}
return capture.Image == null ? null : capture;
}
/// <summary>
/// This method will use User32 code to capture the specified captureBounds from the screen
/// </summary>
/// <param name="capture">ICapture where the captured Bitmap will be stored</param>
/// <param name="captureBounds">Rectangle with the bounds to capture</param>
/// <returns>A Capture Object with a part of the Screen as an Image</returns>
public static ICapture CaptureRectangleFromDesktopScreen(ICapture capture, Rectangle captureBounds) {
if (capture == null) { if (capture == null) {
capture = new Capture(); capture = new Capture();
} }
@ -606,10 +613,7 @@ namespace GreenshotPlugin.Core {
if (capture.CaptureDetails != null) { if (capture.CaptureDetails != null) {
((Bitmap)capture.Image).SetResolution(capture.CaptureDetails.DpiX, capture.CaptureDetails.DpiY); ((Bitmap)capture.Image).SetResolution(capture.CaptureDetails.DpiX, capture.CaptureDetails.DpiY);
} }
if (capture.Image == null) { return capture.Image == null ? null : capture;
return null;
}
return capture;
} }
/// <summary> /// <summary>
@ -622,9 +626,9 @@ namespace GreenshotPlugin.Core {
if (captureBounds.Height <= 0 || captureBounds.Width <= 0) { if (captureBounds.Height <= 0 || captureBounds.Width <= 0) {
LOG.Warn("Nothing to capture, ignoring!"); LOG.Warn("Nothing to capture, ignoring!");
return null; return null;
} else {
LOG.Debug("CaptureRectangle Called!");
} }
LOG.Debug("CaptureRectangle Called!");
// .NET GDI+ Solution, according to some post this has a GDI+ leak... // .NET GDI+ Solution, according to some post this has a GDI+ leak...
// See http://connect.microsoft.com/VisualStudio/feedback/details/344752/gdi-object-leak-when-calling-graphics-copyfromscreen // See http://connect.microsoft.com/VisualStudio/feedback/details/344752/gdi-object-leak-when-calling-graphics-copyfromscreen
// Bitmap capturedBitmap = new Bitmap(captureBounds.Width, captureBounds.Height); // Bitmap capturedBitmap = new Bitmap(captureBounds.Width, captureBounds.Height);
@ -668,9 +672,9 @@ namespace GreenshotPlugin.Core {
// Throw so people can report the problem // Throw so people can report the problem
throw exceptionToThrow; throw exceptionToThrow;
} else { }
// select the bitmap object and store the old handle // select the bitmap object and store the old handle
using (SafeSelectObjectHandle selectObject = safeCompatibleDCHandle.SelectObject(safeDibSectionHandle)) { using (safeCompatibleDCHandle.SelectObject(safeDibSectionHandle)) {
// bitblt over (make copy) // bitblt over (make copy)
GDI32.BitBlt(safeCompatibleDCHandle, 0, 0, captureBounds.Width, captureBounds.Height, desktopDCHandle, captureBounds.X, captureBounds.Y, CopyPixelOperation.SourceCopy | CopyPixelOperation.CaptureBlt); GDI32.BitBlt(safeCompatibleDCHandle, 0, 0, captureBounds.Width, captureBounds.Height, desktopDCHandle, captureBounds.X, captureBounds.Y, CopyPixelOperation.SourceCopy | CopyPixelOperation.CaptureBlt);
} }
@ -689,7 +693,7 @@ namespace GreenshotPlugin.Core {
} }
} }
// Check all all screens are of an equal size // Check all all screens are of an equal size
bool offscreenContent = false; bool offscreenContent;
using (Region captureRegion = new Region(captureBounds)) { using (Region captureRegion = new Region(captureBounds)) {
// Exclude every visible part // Exclude every visible part
foreach (Screen screen in screensInsideCapture) { foreach (Screen screen in screensInsideCapture) {
@ -702,7 +706,7 @@ namespace GreenshotPlugin.Core {
} }
// Check if we need to have a transparent background, needed for offscreen content // Check if we need to have a transparent background, needed for offscreen content
if (offscreenContent) { if (offscreenContent) {
using (Bitmap tmpBitmap = Bitmap.FromHbitmap(safeDibSectionHandle.DangerousGetHandle())) { using (Bitmap tmpBitmap = Image.FromHbitmap(safeDibSectionHandle.DangerousGetHandle())) {
// Create a new bitmap which has a transparent background // Create a new bitmap which has a transparent background
returnBitmap = ImageHelper.CreateEmpty(tmpBitmap.Width, tmpBitmap.Height, PixelFormat.Format32bppArgb, Color.Transparent, tmpBitmap.HorizontalResolution, tmpBitmap.VerticalResolution); returnBitmap = ImageHelper.CreateEmpty(tmpBitmap.Width, tmpBitmap.Height, PixelFormat.Format32bppArgb, Color.Transparent, tmpBitmap.HorizontalResolution, tmpBitmap.VerticalResolution);
// Content will be copied here // Content will be copied here
@ -719,7 +723,7 @@ namespace GreenshotPlugin.Core {
} else { } else {
// All screens, which are inside the capture, are of equal size // All screens, which are inside the capture, are of equal size
// assign image to Capture, the image will be disposed there.. // assign image to Capture, the image will be disposed there..
returnBitmap = Bitmap.FromHbitmap(safeDibSectionHandle.DangerousGetHandle()); returnBitmap = Image.FromHbitmap(safeDibSectionHandle.DangerousGetHandle());
} }
// We got through the capture without exception // We got through the capture without exception
success = true; success = true;
@ -731,6 +735,7 @@ namespace GreenshotPlugin.Core {
} }
if (!success) { if (!success) {
LOG.Error("Still couldn't create Bitmap!"); LOG.Error("Still couldn't create Bitmap!");
if (exception != null) {
throw exception; throw exception;
} }
} }

View file

@ -18,30 +18,28 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Windows.Forms;
using Greenshot.IniFile; using Greenshot.IniFile;
using Greenshot.Interop; using Greenshot.Interop;
using Greenshot.Plugin; using Greenshot.Plugin;
using GreenshotPlugin.UnmanagedHelpers; using GreenshotPlugin.UnmanagedHelpers;
using log4net;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows.Forms;
/// <summary> /// <summary>
/// Code for handling with "windows" /// Code for handling with "windows"
/// Main code is taken from vbAccelerator, location: /// Main code is taken from vbAccelerator, location:
/// http://www.vbaccelerator.com/home/NET/Code/Libraries/Windows/Enumerating_Windows/article.asp /// http://www.vbaccelerator.com/home/NET/Code/Libraries/Windows/Enumerating_Windows/article.asp
/// but a LOT of changes/enhancements were made to adapt it for Greenshot. /// but a LOT of changes/enhancements were made to adapt it for Greenshot.
/// </summary> /// </summary>
using log4net;
namespace GreenshotPlugin.Core { namespace GreenshotPlugin.Core {
#region EnumWindows #region EnumWindows
/// <summary> /// <summary>
@ -73,7 +71,7 @@ namespace GreenshotPlugin.Core {
/// <summary> /// <summary>
/// Gets all child windows of the specified window /// Gets all child windows of the specified window
/// </summary> /// </summary>
/// <param name="hWndParent">Window Handle to get children for</param> /// <param name="parent">Window Handle to get children for</param>
public WindowsEnumerator GetWindows(WindowDetails parent) { public WindowsEnumerator GetWindows(WindowDetails parent) {
if (parent != null) { if (parent != null) {
GetWindows(parent.Handle, null); GetWindows(parent.Handle, null);
@ -167,7 +165,6 @@ namespace GreenshotPlugin.Core {
private const string METRO_GUTTER_CLASS = "ImmersiveGutter"; private const string METRO_GUTTER_CLASS = "ImmersiveGutter";
private static ILog LOG = LogManager.GetLogger(typeof(WindowDetails)); private static ILog LOG = LogManager.GetLogger(typeof(WindowDetails));
private static Dictionary<string, List<string>> classnameTree = new Dictionary<string, List<string>>();
private static CoreConfiguration conf = IniConfig.GetIniSection<CoreConfiguration>(); private static CoreConfiguration conf = IniConfig.GetIniSection<CoreConfiguration>();
private static List<IntPtr> ignoreHandles = new List<IntPtr>(); private static List<IntPtr> ignoreHandles = new List<IntPtr>();
private static List<string> excludeProcessesFromFreeze = new List<string>(); private static List<string> excludeProcessesFromFreeze = new List<string>();
@ -988,7 +985,7 @@ namespace GreenshotPlugin.Core {
if (!doesCaptureFit) { if (!doesCaptureFit) {
// if GDI is allowed.. (a screenshot won't be better than we comes if we continue) // if GDI is allowed.. (a screenshot won't be better than we comes if we continue)
using (Process thisWindowProcess = Process) { using (Process thisWindowProcess = Process) {
if (!isMetroApp && WindowCapture.isGDIAllowed(thisWindowProcess)) { if (!isMetroApp && WindowCapture.IsGdiAllowed(thisWindowProcess)) {
// we return null which causes the capturing code to try another method. // we return null which causes the capturing code to try another method.
return null; return null;
} }

View file

@ -34,6 +34,7 @@
<Compile Include="Controls\GreenshotRadioButton.cs"> <Compile Include="Controls\GreenshotRadioButton.cs">
<SubType>Component</SubType> <SubType>Component</SubType>
</Compile> </Compile>
<Compile Include="Core\CaptureHandler.cs" />
<Compile Include="Core\EventDelay.cs" /> <Compile Include="Core\EventDelay.cs" />
<Compile Include="Core\FastBitmap.cs" /> <Compile Include="Core\FastBitmap.cs" />
<Compile Include="GlobalSuppressions.cs" /> <Compile Include="GlobalSuppressions.cs" />