mirror of
https://github.com/greenshot/greenshot
synced 2025-08-19 21:13:23 -07:00
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:
parent
2797c076b4
commit
fc0791bdb6
6 changed files with 242 additions and 194 deletions
|
@ -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);
|
||||||
|
|
44
GreenshotPlugin/Core/CaptureHandler.cs
Normal file
44
GreenshotPlugin/Core/CaptureHandler.cs
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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" />
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue