diff --git a/Greenshot/Forms/AboutForm.cs b/Greenshot/Forms/AboutForm.cs
index dd594183b..df07d5242 100644
--- a/Greenshot/Forms/AboutForm.cs
+++ b/Greenshot/Forms/AboutForm.cs
@@ -121,7 +121,7 @@ namespace Greenshot {
///
/// Cleanup all the allocated resources
///
- private void Cleanup() {
+ private void Cleanup(object sender, EventArgs e) {
if (gBitmap != null) {
gBitmap.Dispose();
gBitmap = null;
@@ -133,12 +133,8 @@ namespace Greenshot {
///
public AboutForm() {
// Make sure our resources are removed again.
- Disposed += delegate {
- Cleanup();
- };
- FormClosing += delegate {
- Cleanup();
- };
+ Disposed += Cleanup;
+ FormClosing += Cleanup;
// Enable animation for this form, when we don't set this the timer doesn't start as soon as the form is loaded.
EnableAnimation = true;
diff --git a/Greenshot/Forms/CaptureForm.cs b/Greenshot/Forms/CaptureForm.cs
index 41a784cb1..003b52977 100644
--- a/Greenshot/Forms/CaptureForm.cs
+++ b/Greenshot/Forms/CaptureForm.cs
@@ -67,7 +67,6 @@ namespace Greenshot.Forms {
private bool _mouseDown;
private Rectangle _captureRect = Rectangle.Empty;
private readonly ICapture _capture;
- private readonly Image _capturedImage;
private Point _previousMousePos = Point.Empty;
private FixMode _fixMode = FixMode.None;
private RectangleAnimator _windowAnimator;
@@ -112,6 +111,15 @@ namespace Greenshot.Forms {
}
}
+ private void ClosedHandler(object sender, EventArgs e) {
+ _currentForm = null;
+ LOG.Debug("Remove CaptureForm from currentForm");
+ }
+
+ private void ClosingHandler(object sender, EventArgs e) {
+ LOG.Debug("Closing captureform");
+ WindowDetails.UnregisterIgnoreHandle(Handle);
+ }
///
/// This creates the capture form
///
@@ -129,16 +137,8 @@ namespace Greenshot.Forms {
// Enable the AnimatingForm
EnableAnimation = true;
- // Using 32bppPArgb speeds up the drawing.
- //capturedImage = ImageHelper.Clone(capture.Image, PixelFormat.Format32bppPArgb);
- // comment the clone, uncomment the assignment and the original bitmap is used.
- _capturedImage = capture.Image;
-
// clean up
- FormClosed += delegate {
- _currentForm = null;
- LOG.Debug("Remove CaptureForm from currentForm");
- };
+ FormClosed += ClosedHandler;
_capture = capture;
_windows = windows;
@@ -155,14 +155,7 @@ namespace Greenshot.Forms {
// Make sure we never capture the captureform
WindowDetails.RegisterIgnoreHandle(Handle);
// Unregister at close
- FormClosing += delegate {
- // remove the buffer if it was created inside this form
- if (_capturedImage != capture.Image) {
- _capturedImage.Dispose();
- }
- LOG.Debug("Closing captureform");
- WindowDetails.UnregisterIgnoreHandle(Handle);
- };
+ FormClosing += ClosingHandler;
// set cursor location
_cursorPos = WindowCapture.GetCursorLocationRelativeToScreenBounds();
@@ -586,7 +579,7 @@ namespace Greenshot.Forms {
///
///
private void DrawZoom(Graphics graphics, Rectangle sourceRectangle, Rectangle destinationRectangle) {
- if (_capturedImage == null) {
+ if (_capture.Image == null) {
return;
}
ImageAttributes attributes;
@@ -611,9 +604,9 @@ namespace Greenshot.Forms {
graphics.SetClip(path);
if (!_isZoomerTransparent) {
graphics.FillRectangle(BackgroundBrush, destinationRectangle);
- graphics.DrawImage(_capturedImage, destinationRectangle, sourceRectangle, GraphicsUnit.Pixel);
+ graphics.DrawImage(_capture.Image, destinationRectangle, sourceRectangle, GraphicsUnit.Pixel);
} else {
- graphics.DrawImage(_capturedImage, destinationRectangle, sourceRectangle.X, sourceRectangle.Y, sourceRectangle.Width, sourceRectangle.Height, GraphicsUnit.Pixel, attributes);
+ graphics.DrawImage(_capture.Image, destinationRectangle, sourceRectangle.X, sourceRectangle.Y, sourceRectangle.Width, sourceRectangle.Height, GraphicsUnit.Pixel, attributes);
}
}
int alpha = (int)(255 * Conf.ZoomerOpacity);
@@ -680,7 +673,7 @@ namespace Greenshot.Forms {
Graphics graphics = e.Graphics;
Rectangle clipRectangle = e.ClipRectangle;
//graphics.BitBlt((Bitmap)buffer, Point.Empty);
- graphics.DrawImageUnscaled(_capturedImage, Point.Empty);
+ graphics.DrawImageUnscaled(_capture.Image, Point.Empty);
// Only draw Cursor if it's (partly) visible
if (_capture.Cursor != null && _capture.CursorVisible && clipRectangle.IntersectsWith(new Rectangle(_capture.CursorLocation, _capture.Cursor.Size))) {
graphics.DrawIcon(_capture.Cursor, _capture.CursorLocation.X, _capture.CursorLocation.Y);
diff --git a/Greenshot/Forms/MainForm.cs b/Greenshot/Forms/MainForm.cs
index 5118b3fa0..7c6a6dd3e 100644
--- a/Greenshot/Forms/MainForm.cs
+++ b/Greenshot/Forms/MainForm.cs
@@ -419,7 +419,17 @@ namespace Greenshot {
var dataTransport = (CopyDataTransport)copyDataReceivedEventArgs.Data;
HandleDataTransport(dataTransport);
}
+
+ private void BalloonTipClicked(object sender, EventArgs e) {
+ BalloonTipClosed(sender, e);
+ ShowSetting();
+ }
+ private void BalloonTipClosed(object sender, EventArgs e) {
+ notifyIcon.BalloonTipClicked -= BalloonTipClicked;
+ notifyIcon.BalloonTipClosed -= BalloonTipClosed;
+ }
+
private void HandleDataTransport(CopyDataTransport dataTransport) {
foreach(KeyValuePair command in dataTransport.Commands) {
LOG.Debug("Data received, Command = " + command.Key + ", Data: " + command.Value);
@@ -430,22 +440,9 @@ namespace Greenshot {
break;
case CommandEnum.FirstLaunch:
LOG.Info("FirstLaunch: Created new configuration, showing balloon.");
-
try {
- EventHandler balloonTipClickedHandler = null;
- EventHandler balloonTipClosedHandler = null;
- balloonTipClosedHandler = delegate {
- notifyIcon.BalloonTipClicked -= balloonTipClickedHandler;
- notifyIcon.BalloonTipClosed -= balloonTipClosedHandler;
- };
-
- balloonTipClickedHandler = delegate {
- ShowSetting();
- notifyIcon.BalloonTipClicked -= balloonTipClickedHandler;
- notifyIcon.BalloonTipClosed -= balloonTipClosedHandler;
- };
- notifyIcon.BalloonTipClicked += balloonTipClickedHandler;
- notifyIcon.BalloonTipClosed += balloonTipClosedHandler;
+ notifyIcon.BalloonTipClicked += BalloonTipClicked;
+ notifyIcon.BalloonTipClosed += BalloonTipClosed;
notifyIcon.ShowBalloonTip(2000, "Greenshot", Language.GetFormattedString(LangKey.tooltip_firststart, HotkeyControl.GetLocalizedHotkeyStringFromString(_conf.RegionHotkey)), ToolTipIcon.Info);
} catch (Exception ex) {
LOG.Warn("Exception while showing first launch: ", ex);
diff --git a/Greenshot/Forms/SettingsForm.cs b/Greenshot/Forms/SettingsForm.cs
index c32e730e6..a23290ae3 100644
--- a/Greenshot/Forms/SettingsForm.cs
+++ b/Greenshot/Forms/SettingsForm.cs
@@ -65,16 +65,16 @@ namespace Greenshot {
}
// This makes it possible to still capture the settings screen
- fullscreen_hotkeyControl.Enter += delegate { EnterHotkeyControl(); };
- fullscreen_hotkeyControl.Leave += delegate { LeaveHotkeyControl(); };
- window_hotkeyControl.Enter += delegate { EnterHotkeyControl(); };
- window_hotkeyControl.Leave += delegate { LeaveHotkeyControl(); };
- region_hotkeyControl.Enter += delegate { EnterHotkeyControl(); };
- region_hotkeyControl.Leave += delegate { LeaveHotkeyControl(); };
- ie_hotkeyControl.Enter += delegate { EnterHotkeyControl(); };
- ie_hotkeyControl.Leave += delegate { LeaveHotkeyControl(); };
- lastregion_hotkeyControl.Enter += delegate { EnterHotkeyControl(); };
- lastregion_hotkeyControl.Leave += delegate { LeaveHotkeyControl(); };
+ fullscreen_hotkeyControl.Enter += EnterHotkeyControl;
+ fullscreen_hotkeyControl.Leave += LeaveHotkeyControl;
+ window_hotkeyControl.Enter += EnterHotkeyControl;
+ window_hotkeyControl.Leave += LeaveHotkeyControl;
+ region_hotkeyControl.Enter += EnterHotkeyControl;
+ region_hotkeyControl.Leave += LeaveHotkeyControl;
+ ie_hotkeyControl.Enter += EnterHotkeyControl;
+ ie_hotkeyControl.Leave += LeaveHotkeyControl;
+ lastregion_hotkeyControl.Enter += EnterHotkeyControl;
+ lastregion_hotkeyControl.Leave += LeaveHotkeyControl;
DisplayPluginTab();
UpdateUI();
@@ -83,12 +83,12 @@ namespace Greenshot {
CheckSettings();
}
- private void EnterHotkeyControl() {
+ private void EnterHotkeyControl(object sender, EventArgs e) {
HotkeyControl.UnregisterHotkeys();
_inHotkey = true;
}
- private void LeaveHotkeyControl() {
+ private void LeaveHotkeyControl(object sender, EventArgs e) {
MainForm.RegisterHotkeys();
_inHotkey = false;
}
diff --git a/Greenshot/Greenshot.csproj b/Greenshot/Greenshot.csproj
index 61f4cb890..31fe29a9e 100644
--- a/Greenshot/Greenshot.csproj
+++ b/Greenshot/Greenshot.csproj
@@ -202,14 +202,12 @@
MovableShowColorForm.cs
-
-
@@ -223,7 +221,6 @@
-
diff --git a/Greenshot/Helpers/AviHelper.cs b/Greenshot/Helpers/AviHelper.cs
deleted file mode 100644
index 9884b49c9..000000000
--- a/Greenshot/Helpers/AviHelper.cs
+++ /dev/null
@@ -1,1119 +0,0 @@
-// AForge Video for Windows Library
-// AForge.NET framework
-// http://www.aforgenet.com/framework/
-//
-// Copyright © Andrew Kirillov, 2007-2009
-// andrew.kirillov@aforgenet.com
-//
-//
-using System;
-using System.Runtime.InteropServices;
-
-using GreenshotPlugin.UnmanagedHelpers;
-using System.Collections.Generic;
-using System.IO;
-
-namespace Greenshot.Helpers {
-
- ///
- /// AVI files writing using Video for Windows interface.
- ///
- ///
- /// The class allows to write AVI files using Video for Windows API.
- ///
- /// Sample usage:
- /// /// // instantiate AVI writer, use WMV3 codec
- /// AVIWriter writer = new AVIWriter( "wmv3" );
- /// // create new AVI file and open it
- /// writer.Open( "test.avi", 320, 240 );
- /// // create frame image
- /// Bitmap image = new Bitmap( 320, 240 );
- ///
- /// for ( int i = 0; i < 240; i++ )
- /// {
- /// // update image
- /// image.SetPixel( i, i, Color.Red );
- /// // add the image as a new frame of video file
- /// writer.AddFrame( image );
- /// }
- /// writer.Close( );
- ///
- ///
- ///
- public class AVIWriter : IDisposable {
- private static log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(AVIWriter));
- // AVI file
- private IntPtr file;
- // video stream
- private IntPtr stream;
- // compressed stream
- private IntPtr streamCompressed;
- // width of video frames
- private int width;
- // height of vide frames
- private int height;
- // length of one line
- private int stride;
- // quality
- private int quality = -1;
- // frame rate
- private int rate = 25;
- // current position
- private int position;
- // codec used for video compression
- private string codec = null; //"DIB ";
-
- ///
- /// Width of video frames.
- ///
- ///
- /// The property specifies the width of video frames, which are acceptable
- /// by method for saving, which is set in
- /// method.
- ///
- public int Width {
- get {
- return width;
- }
- }
-
- ///
- /// Height of video frames.
- ///
- ///
- /// The property specifies the height of video frames, which are acceptable
- /// by method for saving, which is set in
- /// method.
- ///
- public int Height {
- get {
- return height;
- }
- }
-
- ///
- /// Current position in video stream.
- ///
- ///
- /// The property tell current position in video stream, which actually equals
- /// to the amount of frames added using method.
- ///
- public int Position {
- get {
- return position;
- }
- }
-
- ///
- /// Desired playing frame rate.
- ///
- ///
- /// The property sets the video frame rate, which should be use during playing
- /// of the video to be saved.
- ///
- /// The property should be set befor opening new file to take effect.
- ///
- /// Default frame rate is set to 25.
- ///
- public int FrameRate {
- get {
- return rate;
- }
- set {
- rate = value;
- }
- }
-
- ///
- /// Codec used for video compression.
- ///
- ///
- /// The property sets the FOURCC code of video compression codec, which needs to
- /// be used for video encoding.
- ///
- /// The property should be set befor opening new file to take effect.
- ///
- /// Default video codec is set "DIB ", which means no compression.
- ///
- public string Codec {
- get {
- return codec;
- }
- set {
- codec = value;
- }
- }
-
- ///
- /// Compression video quality.
- ///
- ///
- /// The property sets video quality used by codec in order to balance compression rate
- /// and image quality. The quality is measured usually in the [0, 100] range.
- ///
- /// The property should be set befor opening new file to take effect.
- ///
- /// Default value is set to -1 - default compression quality of the codec.
- ///
- public int Quality {
- get {
- return quality;
- }
- set {
- quality = value;
- }
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- ///
- /// Initializes Video for Windows library.
- ///
- public AVIWriter() {
- Avi32.AVIFileInit();
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- ///
- /// Codec to use for compression. eg [CVID],[IV50]
- ///
- /// Initializes Video for Windows library.
- ///
- public AVIWriter(string codec)
- : this() {
- this.codec = codec;
- }
-
- ///
- /// Destroys the instance of the class.
- ///
- ///
- ~AVIWriter() {
- Dispose(false);
- }
-
- ///
- /// Dispose the object.
- ///
- ///
- /// Frees unmanaged resources used by the object. The object becomes unusable
- /// after that.
- ///
- public void Dispose() {
- Dispose(true);
- // remove me from the Finalization queue
- GC.SuppressFinalize(this);
- }
-
- ///
- /// Dispose the object.
- ///
- ///
- /// Indicates if disposing was initiated manually.
- ///
- protected virtual void Dispose(bool disposing) {
- if (disposing) {
- // dispose managed resources
- }
- // close current AVI file if any opened and uninitialize AVI library
- Close();
- Avi32.AVIFileExit();
- }
-
- ///
- /// Create new AVI file and open it for writing.
- ///
- ///
- /// AVI file name to create.
- /// Video width.
- /// Video height.
- ///
- /// The method opens (creates) a video files, configure video codec and prepares
- /// the stream for saving video frames with a help of method.
- ///
- /// Failure of opening video files (the exception message
- /// specifies the issues).
- ///
- public bool Open(string fileName, int width, int height) {
- lock (this) {
- // calculate stride
- stride = width * 4;
- if ((stride % 4) != 0) {
- stride += (4 - stride % 4);
- }
-
- this.width = width;
- this.height = height;
-
- // describe new stream
- Avi32.AVISTREAMINFO info = new Avi32.AVISTREAMINFO();
-
- LOG.InfoFormat("Available codecs: {0}", String.Join(", ", Avi32.AvailableCodecs.ToArray()));
-
- info.type = Avi32.mmioFOURCC("vids");
- if (codec != null) {
- info.handler = Avi32.mmioFOURCC(codec);
- } else {
- info.handler = Avi32.mmioFOURCC("DIB ");
- }
- info.scale = 1;
- info.rate = rate;
- info.suggestedBufferSize = stride * height;
-
- try {
- // create new file
- if (Avi32.AVIFileOpen(out file, fileName, Avi32.OpenFileMode.Create | Avi32.OpenFileMode.Write, IntPtr.Zero) != 0) {
- throw new ApplicationException("Failed opening file");
- }
-
- // create stream
- if (Avi32.AVIFileCreateStream(file, out stream, ref info) != 0) {
- throw new ApplicationException("Failed creating stream");
- }
-
- // describe compression options
- Avi32.AVICOMPRESSOPTIONS options = new Avi32.AVICOMPRESSOPTIONS();
- // uncomment if video settings dialog is required to show
- int retCode = 0;
- if (codec == null) {
- retCode = Avi32.AVISaveOptions(stream, ref options);
- if (retCode == 0) {
- LOG.Debug("Cancel clicked!");
- return false;
- }
- codec = Avi32.decode_mmioFOURCC(options.handler);
- quality = options.quality;
- } else {
- options.handler = Avi32.mmioFOURCC(codec);
- options.quality = quality;
- }
- LOG.DebugFormat("Codec {0} selected with quality {1}.", codec, quality);
-
- AviError retval;
- // create compressed stream
- try {
- retval = Avi32.AVIMakeCompressedStream(out streamCompressed, stream, ref options, IntPtr.Zero);
- } catch (Exception exCompress) {
- LOG.Warn("Couldn't use compressed stream.", exCompress);
- retval = AviError.AVIERR_OK;
- }
- if (retval != AviError.AVIERR_OK) {
- throw new ApplicationException(string.Format("Failed creating compressed stream: {0}", retval));
- }
-
-
- // describe frame format
- BitmapInfoHeader bitmapInfoHeader = new BitmapInfoHeader(width, height, 32);
-
- // set frame format
- if (streamCompressed != IntPtr.Zero) {
- retval = Avi32.AVIStreamSetFormat(streamCompressed, 0, ref bitmapInfoHeader, Marshal.SizeOf(bitmapInfoHeader.GetType()));
- } else {
- retval = Avi32.AVIStreamSetFormat(stream, 0, ref bitmapInfoHeader, Marshal.SizeOf(bitmapInfoHeader.GetType()));
- }
- if (retval != 0) {
- throw new ApplicationException(string.Format("Failed creating stream: {0}", retval));
- }
- position = 0;
- return true;
- } catch (Exception ex) {
- Close();
- Avi32.AVIFileExit();
- if (File.Exists(fileName)) {
- File.Delete(fileName);
- }
- throw ex;
- }
- }
- }
-
- ///
- /// Close video file.
- ///
- ///
- public void Close() {
- LOG.Debug("Close called");
- lock (this) {
- // release compressed stream
- if (streamCompressed != IntPtr.Zero) {
- LOG.Debug("AVIStreamRelease streamCompressed");
- Avi32.AVIStreamRelease(streamCompressed);
- streamCompressed = IntPtr.Zero;
- }
-
- // release stream
- if (stream != IntPtr.Zero) {
- LOG.Debug("AVIStreamRelease stream");
- Avi32.AVIStreamRelease(stream);
- stream = IntPtr.Zero;
- }
-
- // release file
- if (file != IntPtr.Zero) {
- LOG.Debug("AVIFileRelease file");
- Avi32.AVIFileRelease(file);
- file = IntPtr.Zero;
- }
- }
- }
-
- public void AddEmptyFrames(int frames) {
- lock (this) {
- position += frames;
- }
- }
-
- ///
- /// Add new frame to the AVI file.
- ///
- /// New frame data.
- public void AddLowLevelFrame(IntPtr frameData) {
- lock (this) {
- // write to stream
- if (Avi32.AVIStreamWrite(streamCompressed, position, 1, frameData, stride * height, 0, IntPtr.Zero, IntPtr.Zero) != 0) {
- throw new ApplicationException("Failed adding frame");
- }
-
- position++;
- }
- }
- }
-
- ///
- /// Windows API functions and structures.
- ///
- ///
- /// The class provides Video for Windows and some other Avi32 functions and structurs.
- ///
- internal static class Avi32 {
- private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(Avi32));
-
- [DllImport("MSVFW32", CharSet = CharSet.Ansi)]
- static extern bool ICInfo(int fccType, int fccHandler, ref ICINFO lpicinfo);
-
- [DllImport("MSVFW32"), PreserveSig]
- static extern IntPtr ICOpen(int fccType, int fccHandler, ICMODE wMode);
-
- [DllImport("MSVFW32")]
- static extern int ICClose(IntPtr hic);
-
- [DllImport("MSVFW32", CharSet = CharSet.Ansi)]
- static extern int ICGetInfo(IntPtr hic, ref ICINFO lpicinfo, int cb);
-
- // --- Video for Windows Functions
-
- ///
- /// Initialize the AVIFile library.
- ///
- ///
- [DllImport("avifil32")]
- public static extern void AVIFileInit();
-
- ///
- /// Exit the AVIFile library.
- ///
- [DllImport("avifil32")]
- public static extern void AVIFileExit();
-
- ///
- /// Open an AVI file.
- ///
- ///
- /// Opened AVI file interface.
- /// AVI file name.
- /// Opening mode (see ).
- /// Handler to use (null to use default).
- ///
- /// Returns zero on success or error code otherwise.
- ///
- [DllImport("avifil32", CharSet = CharSet.Unicode)]
- public static extern AviError AVIFileOpen(out IntPtr aviHandler, String fileName, OpenFileMode mode, IntPtr handler);
-
- ///
- /// Release an open AVI stream.
- ///
- ///
- /// Open AVI file interface.
- ///
- /// Returns the reference count of the file.
- ///
- [DllImport("avifil32")]
- public static extern int AVIFileRelease(IntPtr aviHandler);
-
- ///
- /// Get stream interface that is associated with a specified AVI file
- ///
- ///
- /// Handler to an open AVI file.
- /// Stream interface.
- /// Stream type to open.
- /// Count of the stream type. Identifies which occurrence of the specified stream type to access.
- ///
- ///
- ///
- [DllImport("avifil32")]
- public static extern int AVIFileGetStream(IntPtr aviHandler, out IntPtr streamHandler, int streamType, int streamNumner);
-
- ///
- /// Create a new stream in an existing file and creates an interface to the new stream.
- ///
- ///
- /// Handler to an open AVI file.
- /// Stream interface.
- /// Pointer to a structure containing information about the new stream.
- ///
- /// Returns zero if successful or an error otherwise.
- ///
- [DllImport("avifil32")]
- public static extern int AVIFileCreateStream(IntPtr aviHandler, out IntPtr streamHandler, ref AVISTREAMINFO streamInfo);
-
- ///
- /// Release an open AVI stream.
- ///
- ///
- /// Handle to an open stream.
- ///
- /// Returns the current reference count of the stream.
- ///
- [DllImport("avifil32")]
- public static extern int AVIStreamRelease(IntPtr streamHandler);
-
- ///
- /// Set the format of a stream at the specified position.
- ///
- ///
- /// Handle to an open stream.
- /// Position in the stream to receive the format.
- /// Pointer to a structure containing the new format.
- /// Size, in bytes, of the block of memory referenced by format.
- ///
- /// Returns zero if successful or an error otherwise.
- ///
- [DllImport("avifil32")]
- public static extern AviError AVIStreamSetFormat(IntPtr streamHandler, int position, ref BitmapInfoHeader format, int formatSize);
-
- ///
- /// Get the starting sample number for the stream.
- ///
- ///
- /// Handle to an open stream.
- ///
- /// Returns the number if successful or – 1 otherwise.
- ///
- [DllImport("avifil32")]
- public static extern int AVIStreamStart(IntPtr streamHandler);
-
- ///
- /// Get the length of the stream.
- ///
- /// Handle to an open stream.
- /// Returns the stream's length, in samples, if successful or -1 otherwise.
- [DllImport("avifil32")]
- public static extern int AVIStreamLength(IntPtr streamHandler);
-
- ///
- /// Obtain stream header information.
- ///
- ///
- /// Handle to an open stream.
- /// Pointer to a structure to contain the stream information.
- /// Size, in bytes, of the structure used for streamInfo.
- ///
- /// Returns zero if successful or an error otherwise.
- ///
- [DllImport("avifil32", CharSet = CharSet.Unicode)]
- public static extern int AVIStreamInfo(IntPtr streamHandler, ref AVISTREAMINFO streamInfo, int infoSize);
-
- ///
- /// Prepare to decompress video frames from the specified video stream
- ///
- /// Pointer to the video stream used as the video source.
- /// Pointer to a structure that defines the desired video format. Specify NULL to use a default format.
- /// Returns an object that can be used with the function.
- [DllImport("avifil32")]
- public static extern IntPtr AVIStreamGetFrameOpen(IntPtr streamHandler, ref BitmapInfoHeader wantedFormat);
-
- ///
- /// Prepare to decompress video frames from the specified video stream.
- ///
- /// Pointer to the video stream used as the video source.
- /// Pointer to a structure that defines the desired video format. Specify NULL to use a default format.
- /// Returns a GetFrame object that can be used with the function.
- [DllImport("avifil32")]
- public static extern IntPtr AVIStreamGetFrameOpen(IntPtr streamHandler, int wantedFormat);
-
- ///
- /// Releases resources used to decompress video frames.
- ///
- /// Handle returned from the function.
- /// Returns zero if successful or an error otherwise.
- [DllImport("avifil32")]
- public static extern int AVIStreamGetFrameClose(IntPtr getFrameObject);
-
- ///
- /// Return the address of a decompressed video frame.
- ///
- /// Pointer to a GetFrame object.
- /// Position, in samples, within the stream of the desired frame.
- /// Returns a pointer to the frame data if successful or NULL otherwise.
- [DllImport("avifil32")]
- public static extern IntPtr AVIStreamGetFrame(IntPtr getFrameObject, int position);
-
- ///
- /// Write data to a stream.
- ///
- /// Handle to an open stream.
- /// First sample to write.
- /// Number of samples to write.
- /// Pointer to a buffer containing the data to write.
- /// Size of the buffer referenced by buffer.
- /// Flag associated with this data.
- /// Pointer to a buffer that receives the number of samples written. This can be set to NULL.
- /// Pointer to a buffer that receives the number of bytes written. This can be set to NULL.
- ///
- /// Returns zero if successful or an error otherwise.
- ///
- [DllImport("avifil32")]
- public static extern AviError AVIStreamWrite(IntPtr streamHandler, int start, int samples, IntPtr buffer, int bufferSize, int flags, IntPtr samplesWritten, IntPtr bytesWritten);
-
- ///
- /// Retrieve the save options for a file and returns them in a buffer.
- ///
- /// Handle to the parent window for the Compression Options dialog box.
- /// Flags for displaying the Compression Options dialog box.
- /// Number of streams that have their options set by the dialog box.
- /// Pointer to an array of stream interface pointers.
- /// Pointer to an array of pointers to AVICOMPRESSOPTIONS structures.
- /// Returns TRUE if the user pressed OK, FALSE for CANCEL, or an error otherwise.
- [DllImport("avifil32")]
- public static extern int AVISaveOptions(IntPtr window, int flags, int streams, [In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] IntPtr[] streamInterfaces, [In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] IntPtr[] options);
-
- ///
- /// Free the resources allocated by the AVISaveOptions function.
- ///
- /// Count of the AVICOMPRESSOPTIONS structures referenced in options.
- /// Pointer to an array of pointers to AVICOMPRESSOPTIONS structures.
- /// Returns 0.
- [DllImport("avifil32")]
- public static extern AviError AVISaveOptionsFree(int streams, [In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] IntPtr[] options);
-
- ///
- /// Create a compressed stream from an uncompressed stream and a
- /// compression filter, and returns the address of a pointer to
- /// the compressed stream.
- ///
- /// Pointer to a buffer that receives the compressed stream pointer.
- /// Pointer to the stream to be compressed.
- /// Pointer to a structure that identifies the type of compression to use and the options to apply.
- /// Pointer to a class identifier used to create the stream.
- /// Returns 0 if successful or an error otherwise.
- [DllImport("avifil32")]
- public static extern AviError AVIMakeCompressedStream(out IntPtr compressedStream, IntPtr sourceStream, ref AVICOMPRESSOPTIONS options, IntPtr clsidHandler);
-
- ///
- /// Code type
- ///
- public enum ICMODE {
- ICMODE_COMPRESS = 1,
- ICMODE_DECOMPRESS = 2,
- ICMODE_FASTDECOMPRESS = 3,
- ICMODE_QUERY = 4,
- ICMODE_FASTCOMPRESS = 5,
- ICMODE_DRAW = 8
- }
-
- // --- structures
-
- ///
- /// Structor for the codec info
- /// See: http://msdn.microsoft.com/en-us/library/windows/desktop/dd743162%28v=vs.85%29.aspx
- ///
- [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
- public struct ICINFO {
- public int dwSize;
- public int fccType;
- public int fccHandler;
- public int dwFlags;
- public int dwVersion;
- public int dwVersionICM;
- [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]
- public string szName;
- [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
- public string szDescription;
- [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
- public string szDriver;
-
- public ICINFO(int type) {
- dwSize = Marshal.SizeOf(typeof(ICINFO));
- fccType = type;
- fccHandler = 0;
- dwFlags = 0;
- dwVersion = 0;
- dwVersionICM = 0;
- szName = null;
- szDescription = null;
- szDriver = null;
- }
- }
-
- ///
- /// Structure, which contains information for a single stream .
- ///
- ///
- [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 1)]
- public struct AVISTREAMINFO {
- ///
- /// Four-character code indicating the stream type.
- ///
- ///
- [MarshalAs(UnmanagedType.I4)]
- public int type;
-
- ///
- /// Four-character code of the compressor handler that will compress this video stream when it is saved.
- ///
- ///
- [MarshalAs(UnmanagedType.I4)]
- public int handler;
-
- ///
- /// Applicable flags for the stream.
- ///
- ///
- [MarshalAs(UnmanagedType.I4)]
- public int flags;
-
- ///
- /// Capability flags; currently unused.
- ///
- ///
- [MarshalAs(UnmanagedType.I4)]
- public int ñapabilities;
-
- ///
- /// Priority of the stream.
- ///
- ///
- [MarshalAs(UnmanagedType.I2)]
- public short priority;
-
- ///
- /// Language of the stream.
- ///
- ///
- [MarshalAs(UnmanagedType.I2)]
- public short language;
-
- ///
- /// Time scale applicable for the stream.
- ///
- ///
- /// Dividing rate by scale gives the playback rate in number of samples per second.
- ///
- [MarshalAs(UnmanagedType.I4)]
- public int scale;
-
- ///
- /// Rate in an integer format.
- ///
- ///
- [MarshalAs(UnmanagedType.I4)]
- public int rate;
-
- ///
- /// Sample number of the first frame of the AVI file.
- ///
- ///
- [MarshalAs(UnmanagedType.I4)]
- public int start;
-
- ///
- /// Length of this stream.
- ///
- ///
- /// The units are defined by rate and scale.
- ///
- [MarshalAs(UnmanagedType.I4)]
- public int length;
-
- ///
- /// Audio skew. This member specifies how much to skew the audio data ahead of the video frames in interleaved files.
- ///
- ///
- [MarshalAs(UnmanagedType.I4)]
- public int initialFrames;
-
- ///
- /// Recommended buffer size, in bytes, for the stream.
- ///
- ///
- [MarshalAs(UnmanagedType.I4)]
- public int suggestedBufferSize;
-
- ///
- /// Quality indicator of the video data in the stream.
- ///
- ///
- /// Quality is represented as a number between 0 and 10,000.
- ///
- [MarshalAs(UnmanagedType.I4)]
- public int quality;
-
- ///
- /// Size, in bytes, of a single data sample.
- ///
- ///
- [MarshalAs(UnmanagedType.I4)]
- public int sampleSize;
-
- ///
- /// Dimensions of the video destination rectangle.
- ///
- ///
- [MarshalAs(UnmanagedType.Struct, SizeConst = 16)]
- public RECT rectFrame;
-
- ///
- /// Number of times the stream has been edited.
- ///
- ///
- [MarshalAs(UnmanagedType.I4)]
- public int editCount;
-
- ///
- /// Number of times the stream format has changed.
- ///
- ///
- [MarshalAs(UnmanagedType.I4)]
- public int formatChangeCount;
-
- ///
- /// Description of the stream.
- ///
- ///
- [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]
- public string name;
- }
-
- ///
- /// Structure, which contains information about a stream and how it is compressed and saved.
- ///
- ///
- [StructLayout(LayoutKind.Sequential, Pack = 1)]
- public struct AVICOMPRESSOPTIONS {
- ///
- /// Four-character code indicating the stream type.
- ///
- ///
- [MarshalAs(UnmanagedType.I4)]
- public int type;
-
- ///
- /// Four-character code for the compressor handler that will compress this video stream when it is saved.
- ///
- ///
- [MarshalAs(UnmanagedType.I4)]
- public int handler;
-
- ///
- /// Maximum period between video key frames.
- ///
- ///
- [MarshalAs(UnmanagedType.I4)]
- public int keyFrameEvery;
-
- ///
- /// Quality value passed to a video compressor.
- ///
- ///
- [MarshalAs(UnmanagedType.I4)]
- public int quality;
-
- ///
- /// Video compressor data rate.
- ///
- ///
- [MarshalAs(UnmanagedType.I4)]
- public int bytesPerSecond;
-
- ///
- /// Flags used for compression.
- ///
- ///
- [MarshalAs(UnmanagedType.I4)]
- public int flags;
-
- ///
- /// Pointer to a structure defining the data format.
- ///
- ///
- [MarshalAs(UnmanagedType.I4)]
- public int format;
-
- ///
- /// Size, in bytes, of the data referenced by format.
- ///
- ///
- [MarshalAs(UnmanagedType.I4)]
- public int formatSize;
-
- ///
- /// Video-compressor-specific data; used internally.
- ///
- ///
- [MarshalAs(UnmanagedType.I4)]
- public int parameters;
-
- ///
- /// Size, in bytes, of the data referenced by parameters.
- ///
- [MarshalAs(UnmanagedType.I4)]
- public int parametersSize;
-
- ///
- /// Interleave factor for interspersing stream data with data from the first stream.
- ///
- ///
- [MarshalAs(UnmanagedType.I4)]
- public int interleaveEvery;
- }
-
- // --- enumerations
-
- ///
- /// File access modes.
- ///
- ///
- [Flags]
- public enum OpenFileMode {
- Read = 0x00000000,
- Write = 0x00000001,
- ReadWrite = 0x00000002,
- ShareCompat = 0x00000000,
- ShareExclusive = 0x00000010,
- ShareDenyWrite = 0x00000020,
- ShareDenyRead = 0x00000030,
- ShareDenyNone = 0x00000040,
- Parse = 0x00000100,
- Delete = 0x00000200,
- Verify = 0x00000400,
- Cancel = 0x00000800,
- Create = 0x00001000,
- Prompt = 0x00002000,
- Exist = 0x00004000,
- Reopen = 0x00008000
- }
-
- ///
- /// .NET replacement of mmioFOURCC macros. Converts four characters to code.
- ///
- ///
- /// Four characters string.
- ///
- /// Returns the code created from provided characters.
- ///
- public static int mmioFOURCC(string str) {
- return (((int)(byte)(str[0])) |
- ((int)(byte)(str[1]) << 8) |
- ((int)(byte)(str[2]) << 16) |
- ((int)(byte)(str[3]) << 24));
- }
-
- ///
- /// Inverse to . Converts code to fout characters string.
- ///
- ///
- /// Code to convert.
- ///
- /// Returns four characters string.
- ///
- public static string decode_mmioFOURCC(int code) {
- char[] chs = new char[4];
-
- for (int i = 0; i < 4; i++) {
- chs[i] = (char)(byte)((code >> (i << 3)) & 0xFF);
- if (!char.IsLetterOrDigit(chs[i])) {
- chs[i] = ' ';
- }
- }
- return new string(chs);
- }
-
- ///
- /// Get a list of available codecs.
- ///
- /// List
- public static List AvailableCodecs {
- get {
- List returnValues = new List();
- int codecNr = 0;
-
- ICINFO codecInfo = new ICINFO(mmioFOURCC("VIDC"));
-
- bool success = true;
- do {
- success = ICInfo(codecInfo.fccType, codecNr++, ref codecInfo);
- if (success) {
- IntPtr hic = ICOpen(codecInfo.fccType, codecInfo.fccHandler, ICMODE.ICMODE_QUERY);
- if (hic != IntPtr.Zero) {
- ICGetInfo(hic, ref codecInfo, Marshal.SizeOf(codecInfo));
- string codecName = decode_mmioFOURCC(codecInfo.fccHandler);
- returnValues.Add(codecName);
- LOG.DebugFormat("Found codec {0} {4}, with name {1} and description {2}, driver {3}", codecName, codecInfo.szName, codecInfo.szDescription, codecInfo.szDriver, codecInfo.dwVersion);
- ICClose(hic);
- }
- }
- } while (success);
- return returnValues;
- }
- }
-
- ///
- /// Version of for one stream only.
- ///
- ///
- /// Stream to configure.
- /// Stream options.
- ///
- /// Returns TRUE if the user pressed OK, FALSE for CANCEL, or an error otherwise.
- ///
- public static int AVISaveOptions(IntPtr stream, ref AVICOMPRESSOPTIONS options) {
- IntPtr[] streams = new IntPtr[1];
- IntPtr[] infPtrs = new IntPtr[1];
- IntPtr mem;
- int ret;
-
- // alloc unmanaged memory
- mem = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(AVICOMPRESSOPTIONS)));
-
- // copy from managed structure to unmanaged memory
- Marshal.StructureToPtr(options, mem, false);
-
- streams[0] = stream;
- infPtrs[0] = mem;
-
- // show dialog with a list of available compresors and configuration
- ret = AVISaveOptions(IntPtr.Zero, 0, 1, streams, infPtrs);
-
- // copy from unmanaged memory to managed structure
- options = (AVICOMPRESSOPTIONS)Marshal.PtrToStructure(mem, typeof(AVICOMPRESSOPTIONS));
-
- // free AVI compression options
- AVISaveOptionsFree(1, infPtrs);
-
- // clear it, because the information already freed by AVISaveOptionsFree
- options.format = 0;
- options.parameters = 0;
-
- // free unmanaged memory
- Marshal.FreeHGlobal(mem);
-
- return ret;
- }
- }
-
- ///
- /// AVI Error Codes
- ///
- [Flags]
- public enum AviError : uint {
- ///
- /// Compression is not supported for this type of data.
- /// This error might be returned if you try to compress
- /// data that is not audio or video.
- ///
- AVIERR_UNSUPPORTED = 0x80044065,
- ///
- /// The file couldn't be read, indicating a corrupt file or an unrecognized format
- ///
- AVIERR_BADFORMAT = 0x80044066,
- ///
- /// There is not enough memory to complete the operation.
- ///
- AVIERR_MEMORY = 0x80044067,
- ///
- ///
- ///
- // TODO : Put documentation
- AVIERR_INTERNAL = 0x80044068,
- ///
- ///
- ///
- // TODO : Put documentation
- AVIERR_BADFLAGS = 0x80044069,
- ///
- ///
- ///
- // TODO : Put documentation
- AVIERR_BADPARAM = 0x8004406A,
- ///
- ///
- ///
- // TODO : Put documentation
- AVIERR_BADSIZE = 0x8004406B,
- ///
- ///
- ///
- // TODO : Put documentation
- AVIERR_BADHANDLE = 0x8004406C,
- ///
- /// A disk error occurred while reading the file
- ///
- AVIERR_FILEREAD = 0x8004406D,
- ///
- ///
- ///
- // TODO : Put documentation
- AVIERR_FILEWRITE = 0x8004406E,
- ///
- /// A disk error occurred while opening the file
- ///
- AVIERR_FILEOPEN = 0x8004406F,
- ///
- ///
- ///
- // TODO : Put documentation
- AVIERR_COMPRESSOR = 0x80044070,
- ///
- /// A suitable compressor cannot be found.
- ///
- AVIERR_NOCOMPRESSOR = 0x80044071,
- ///
- ///
- ///
- // TODO : Put documentation
- AVIERR_READONLY = 0x80044072,
- ///
- ///
- ///
- // TODO : Put documentation
- AVIERR_NODATA = 0x80044073,
- ///
- ///
- ///
- // TODO : Put documentation
- AVIERR_BUFFERTOOSMALL = 0x80044074,
- ///
- ///
- ///
- // TODO : Put documentation
- AVIERR_CANTCOMPRESS = 0x80044075,
- ///
- ///
- ///
- // TODO : Put documentation
- AVIERR_USERABORT = 0x800440C6,
- ///
- ///
- ///
- // TODO : Put documentation
- AVIERR_ERROR = 0x800440C7,
- ///
- /// Operation successful
- ///
- AVIERR_OK = 0x0
- }
-}
diff --git a/Greenshot/Helpers/CaptureHelper.cs b/Greenshot/Helpers/CaptureHelper.cs
index 2e9be5c8b..72f2e86c7 100644
--- a/Greenshot/Helpers/CaptureHelper.cs
+++ b/Greenshot/Helpers/CaptureHelper.cs
@@ -27,6 +27,7 @@ using Greenshot.IniFile;
using Greenshot.Plugin;
using GreenshotPlugin.Core;
using GreenshotPlugin.UnmanagedHelpers;
+using log4net;
using System;
using System.Collections.Generic;
using System.Diagnostics;
@@ -34,7 +35,6 @@ using System.Drawing;
using System.IO;
using System.Threading;
using System.Windows.Forms;
-using log4net;
namespace Greenshot.Helpers {
///
@@ -118,7 +118,9 @@ namespace Greenshot.Helpers {
}
public static void CaptureWindow(bool captureMouse) {
- new CaptureHelper(CaptureMode.ActiveWindow, captureMouse).MakeCapture();
+ using (CaptureHelper captureHelper = new CaptureHelper(CaptureMode.ActiveWindow, captureMouse)) {
+ captureHelper.MakeCapture();
+ }
}
public static void CaptureWindow(WindowDetails windowToCapture) {
@@ -214,13 +216,8 @@ namespace Greenshot.Helpers {
/// Make Capture with specified destinations
///
private void MakeCapture() {
- // Experimental code
- // TODO: when we get the screen capture code working correctly, this needs to be enabled
- //if (screenCapture != null) {
- // screenCapture.Stop();
- // screenCapture = null;
- // return;
- //}
+ Thread retrieveWindowDetailsThread = null;
+
// This fixes a problem when a balloon is still visible and a capture needs to be taken
// forcefully removes the balloon!
if (!conf.HideTrayicon) {
@@ -236,11 +233,11 @@ namespace Greenshot.Helpers {
case CaptureMode.Region:
// Check if a region is pre-supplied!
if (Rectangle.Empty.Equals(_captureRect)) {
- PrepareForCaptureWithFeedback();
+ retrieveWindowDetailsThread = PrepareForCaptureWithFeedback();
}
break;
case CaptureMode.Window:
- PrepareForCaptureWithFeedback();
+ retrieveWindowDetailsThread = PrepareForCaptureWithFeedback();
break;
}
@@ -286,12 +283,6 @@ namespace Greenshot.Helpers {
break;
case CaptureMode.ActiveWindow:
if (CaptureActiveWindow()) {
- // TODO: Reactive / check if the elements code is activated
- //if (windowDetailsThread != null) {
- // windowDetailsThread.Join();
- //}
- //capture.MoveElements(capture.ScreenBounds.Location.X-capture.Location.X, capture.ScreenBounds.Location.Y-capture.Location.Y);
-
// Capture worked, offset mouse according to screen bounds and capture location
_capture.MoveMouseLocation(_capture.ScreenBounds.Location.X-_capture.Location.X, _capture.ScreenBounds.Location.Y-_capture.Location.Y);
_capture.CaptureDetails.AddMetaData("source", "Window");
@@ -448,10 +439,10 @@ namespace Greenshot.Helpers {
LOG.Warn("Unknown capture mode: " + _captureMode);
break;
}
- // TODO: Reactive / check if the elements code is activated
- //if (windowDetailsThread != null) {
- // windowDetailsThread.Join();
- //}
+ // Wait for thread, otherwise we can't dipose the CaptureHelper
+ if (retrieveWindowDetailsThread != null) {
+ retrieveWindowDetailsThread.Join();
+ }
if (_capture != null) {
LOG.Debug("Disposing capture");
_capture.Dispose();
@@ -470,82 +461,47 @@ namespace Greenshot.Helpers {
_windows.Add(appLauncherWindow);
return null;
}
-
- Thread getWindowDetailsThread = new Thread (delegate() {
- // Start Enumeration of "active" windows
- List allWindows = WindowDetails.GetMetroApps();
- allWindows.AddRange(WindowDetails.GetAllWindows());
- foreach (WindowDetails window in allWindows) {
- // Window should be visible and not ourselves
- if (!window.Visible) {
- continue;
- }
-
- // Skip empty
- Rectangle windowRectangle = window.WindowRectangle;
- Size windowSize = windowRectangle.Size;
- if (windowSize.Width == 0 || windowSize.Height == 0) {
- continue;
- }
-
- // Make sure the details are retrieved once
- window.FreezeDetails();
-
- // Force children retrieval, sometimes windows close on losing focus and this is solved by caching
- int goLevelDeep = 3;
- if (conf.WindowCaptureAllChildLocations) {
- goLevelDeep = 20;
- }
- window.GetChildren(goLevelDeep);
- lock (_windows) {
- _windows.Add(window);
- }
- // TODO: Following code should be enabled & checked if the editor can support "elements"
- //// Get window rectangle as capture Element
- //CaptureElement windowCaptureElement = new CaptureElement(windowRectangle);
- //if (capture == null) {
- // break;
- //}
- //capture.Elements.Add(windowCaptureElement);
-
- //if (!window.HasParent) {
- // // Get window client rectangle as capture Element, place all the other "children" in there
- // Rectangle clientRectangle = window.ClientRectangle;
- // CaptureElement windowClientCaptureElement = new CaptureElement(clientRectangle);
- // windowCaptureElement.Children.Add(windowClientCaptureElement);
- // AddCaptureElementsForWindow(windowClientCaptureElement, window, goLevelDeep);
- //} else {
- // AddCaptureElementsForWindow(windowCaptureElement, window, goLevelDeep);
- //}
- }
-// lock (windows) {
-// windows = WindowDetails.SortByZOrder(IntPtr.Zero, windows);
-// }
- });
+ Thread getWindowDetailsThread = new Thread(RetrieveWindowDetails);
getWindowDetailsThread.Name = "Retrieve window details";
getWindowDetailsThread.IsBackground = true;
getWindowDetailsThread.Start();
return getWindowDetailsThread;
}
-
- // Code used to get the capture elements, which is not active yet
- //private void AddCaptureElementsForWindow(ICaptureElement parentElement, WindowDetails parentWindow, int level) {
- // foreach(WindowDetails childWindow in parentWindow.Children) {
- // // Make sure the details are retrieved once
- // childWindow.FreezeDetails();
- // Rectangle childRectangle = childWindow.WindowRectangle;
- // Size s1 = childRectangle.Size;
- // childRectangle.Intersect(parentElement.Bounds);
- // if (childRectangle.Width > 0 && childRectangle.Height > 0) {
- // CaptureElement childCaptureElement = new CaptureElement(childRectangle);
- // parentElement.Children.Add(childCaptureElement);
- // if (level > 0) {
- // AddCaptureElementsForWindow(childCaptureElement, childWindow, level -1);
- // }
- // }
- // }
- //}
+
+ private void RetrieveWindowDetails() {
+ LOG.Debug("start RetrieveWindowDetails");
+ // Start Enumeration of "active" windows
+ List allWindows = WindowDetails.GetMetroApps();
+ allWindows.AddRange(WindowDetails.GetAllWindows());
+ foreach (WindowDetails window in allWindows) {
+ // Window should be visible and not ourselves
+ if (!window.Visible) {
+ continue;
+ }
+
+ // Skip empty
+ Rectangle windowRectangle = window.WindowRectangle;
+ Size windowSize = windowRectangle.Size;
+ if (windowSize.Width == 0 || windowSize.Height == 0) {
+ continue;
+ }
+
+ // Make sure the details are retrieved once
+ window.FreezeDetails();
+
+ // Force children retrieval, sometimes windows close on losing focus and this is solved by caching
+ int goLevelDeep = 3;
+ if (conf.WindowCaptureAllChildLocations) {
+ goLevelDeep = 20;
+ }
+ window.GetChildren(goLevelDeep);
+ lock (_windows) {
+ _windows.Add(window);
+ }
+ }
+ LOG.Debug("end RetrieveWindowDetails");
+ }
private void AddConfiguredDestination() {
foreach(string destinationDesignation in conf.OutputDestinations) {
@@ -556,6 +512,98 @@ namespace Greenshot.Helpers {
}
}
+ ///
+ /// If a balloon tip is show for a taken capture, this handles the click on it
+ ///
+ ///
+ ///
+ private void OpenCaptureOnClick(object sender, EventArgs e) {
+ SurfaceMessageEventArgs eventArgs = MainForm.Instance.NotifyIcon.Tag as SurfaceMessageEventArgs;
+ if (eventArgs == null) {
+ LOG.Warn("OpenCaptureOnClick called without SurfaceMessageEventArgs");
+ RemoveEventHandler(sender, e);
+ return;
+ }
+ ISurface surface = eventArgs.Surface;
+ if (surface != null && eventArgs.MessageType == SurfaceMessageTyp.FileSaved) {
+ if (!string.IsNullOrEmpty(surface.LastSaveFullPath)) {
+ string errorMessage = null;
+
+ try {
+ ProcessStartInfo psi = new ProcessStartInfo("explorer.exe");
+ psi.Arguments = Path.GetDirectoryName(surface.LastSaveFullPath);
+ psi.UseShellExecute = false;
+ using (Process p = new Process()) {
+ p.StartInfo = psi;
+ p.Start();
+ }
+ } catch (Exception ex) {
+ errorMessage = ex.Message;
+ }
+ // Added fallback for when the explorer can't be found
+ if (errorMessage != null) {
+ try {
+ string windowsPath = Environment.GetEnvironmentVariable("SYSTEMROOT");
+ string explorerPath = Path.Combine(windowsPath, "explorer.exe");
+ if (File.Exists(explorerPath)) {
+ ProcessStartInfo psi = new ProcessStartInfo(explorerPath);
+ psi.Arguments = Path.GetDirectoryName(surface.LastSaveFullPath);
+ psi.UseShellExecute = false;
+ using (Process p = new Process()) {
+ p.StartInfo = psi;
+ p.Start();
+ }
+ errorMessage = null;
+ }
+ } catch {
+ }
+ }
+ if (errorMessage != null) {
+ MessageBox.Show(string.Format("{0}\r\nexplorer.exe {1}", errorMessage, surface.LastSaveFullPath), "explorer.exe", MessageBoxButtons.OK, MessageBoxIcon.Error);
+ }
+ }
+ } else if (surface != null && !string.IsNullOrEmpty(surface.UploadURL)) {
+ Process.Start(surface.UploadURL);
+ }
+ LOG.DebugFormat("Deregistering the BalloonTipClicked");
+ RemoveEventHandler(sender, e);
+ }
+
+ private void RemoveEventHandler(object sender, EventArgs e) {
+ MainForm.Instance.NotifyIcon.BalloonTipClicked -= OpenCaptureOnClick;
+ MainForm.Instance.NotifyIcon.BalloonTipClosed -= RemoveEventHandler;
+ MainForm.Instance.NotifyIcon.Tag = null;
+ }
+
+ ///
+ /// This is the SufraceMessageEvent receiver
+ ///
+ ///
+ ///
+ private void SurfaceMessageReceived(object sender, SurfaceMessageEventArgs eventArgs) {
+ if (eventArgs == null || string.IsNullOrEmpty(eventArgs.Message)) {
+ return;
+ }
+ switch (eventArgs.MessageType) {
+ case SurfaceMessageTyp.Error:
+ MainForm.Instance.NotifyIcon.ShowBalloonTip(10000, "Greenshot", eventArgs.Message, ToolTipIcon.Error);
+ break;
+ case SurfaceMessageTyp.Info:
+ MainForm.Instance.NotifyIcon.ShowBalloonTip(10000, "Greenshot", eventArgs.Message, ToolTipIcon.Info);
+ break;
+ case SurfaceMessageTyp.FileSaved:
+ case SurfaceMessageTyp.UploadedUri:
+ // Show a balloon and register an event handler to open the "capture" for if someone clicks the balloon.
+ MainForm.Instance.NotifyIcon.BalloonTipClicked += OpenCaptureOnClick;
+ MainForm.Instance.NotifyIcon.BalloonTipClosed += RemoveEventHandler;
+ // Store for later usage
+ MainForm.Instance.NotifyIcon.Tag = eventArgs;
+ MainForm.Instance.NotifyIcon.ShowBalloonTip(10000, "Greenshot", eventArgs.Message, ToolTipIcon.Info);
+ break;
+ }
+ }
+
+
private void HandleCapture() {
// Flag to see if the image was "exported" so the FileEditor doesn't
// ask to save the file as long as nothing is done.
@@ -586,80 +634,7 @@ namespace Greenshot.Helpers {
// Register notify events if this is wanted
if (conf.ShowTrayNotification && !conf.HideTrayicon) {
- surface.SurfaceMessage += delegate(object source, SurfaceMessageEventArgs eventArgs) {
- if (eventArgs == null || string.IsNullOrEmpty(eventArgs.Message)) {
- return;
- }
- switch (eventArgs.MessageType) {
- case SurfaceMessageTyp.Error:
- MainForm.Instance.NotifyIcon.ShowBalloonTip(10000, "Greenshot", eventArgs.Message, ToolTipIcon.Error);
- break;
- case SurfaceMessageTyp.Info:
- MainForm.Instance.NotifyIcon.ShowBalloonTip(10000, "Greenshot", eventArgs.Message, ToolTipIcon.Info);
- break;
- case SurfaceMessageTyp.FileSaved:
- case SurfaceMessageTyp.UploadedUri:
- EventHandler balloonTipClickedHandler = null;
- EventHandler balloonTipClosedHandler = null;
- balloonTipClosedHandler = delegate(object sender, EventArgs e) {
- LOG.DebugFormat("Deregistering the BalloonTipClosed");
- MainForm.Instance.NotifyIcon.BalloonTipClicked -= balloonTipClickedHandler;
- MainForm.Instance.NotifyIcon.BalloonTipClosed -= balloonTipClosedHandler;
- };
-
- balloonTipClickedHandler = delegate(object sender, EventArgs e) {
- if (eventArgs.MessageType == SurfaceMessageTyp.FileSaved) {
- if (!string.IsNullOrEmpty(surface.LastSaveFullPath)) {
- string errorMessage = null;
-
- try {
- ProcessStartInfo psi = new ProcessStartInfo("explorer.exe");
- psi.Arguments = Path.GetDirectoryName(surface.LastSaveFullPath);
- psi.UseShellExecute = false;
- using (Process p = new Process()) {
- p.StartInfo = psi;
- p.Start();
- }
- } catch (Exception ex) {
- errorMessage = ex.Message;
- }
- // Added fallback for when the explorer can't be found
- if (errorMessage != null) {
- try {
- string windowsPath = Environment.GetEnvironmentVariable("SYSTEMROOT");
- string explorerPath = Path.Combine(windowsPath, "explorer.exe");
- if (File.Exists(explorerPath)) {
- ProcessStartInfo psi = new ProcessStartInfo(explorerPath);
- psi.Arguments = Path.GetDirectoryName(surface.LastSaveFullPath);
- psi.UseShellExecute = false;
- using (Process p = new Process()) {
- p.StartInfo = psi;
- p.Start();
- }
- errorMessage = null;
- }
- } catch {
- }
- }
- if (errorMessage != null) {
- MessageBox.Show(string.Format("{0}\r\nexplorer.exe {1}", errorMessage, surface.LastSaveFullPath), "explorer.exe", MessageBoxButtons.OK, MessageBoxIcon.Error);
- }
- }
- } else {
- if (!string.IsNullOrEmpty(surface.UploadURL)) {
- Process.Start(surface.UploadURL);
- }
- }
- LOG.DebugFormat("Deregistering the BalloonTipClicked");
- MainForm.Instance.NotifyIcon.BalloonTipClicked -= balloonTipClickedHandler;
- MainForm.Instance.NotifyIcon.BalloonTipClosed -= balloonTipClosedHandler;
- };
- MainForm.Instance.NotifyIcon.BalloonTipClicked += balloonTipClickedHandler;
- MainForm.Instance.NotifyIcon.BalloonTipClosed += balloonTipClosedHandler;
- MainForm.Instance.NotifyIcon.ShowBalloonTip(10000, "Greenshot", eventArgs.Message, ToolTipIcon.Info);
- break;
- }
- };
+ surface.SurfaceMessage += SurfaceMessageReceived;
}
// Let the processors do their job
@@ -984,30 +959,6 @@ namespace Greenshot.Helpers {
}
if (_captureRect.Height > 0 && _captureRect.Width > 0) {
- // TODO: Reactive / check if the elements code is activated
- //if (windowDetailsThread != null) {
- // windowDetailsThread.Join();
- //}
-
- // Experimental code for Video capture
- // TODO: when we get the screen capture code working correctly, this needs to be enabled
- //if (capture.CaptureDetails.CaptureMode == CaptureMode.Video) {
- // if (captureForm.UsedCaptureMode == CaptureMode.Window) {
- // screenCapture = new ScreenCaptureHelper(selectedCaptureWindow);
- // } else if (captureForm.UsedCaptureMode == CaptureMode.Region) {
- // screenCapture = new ScreenCaptureHelper(captureRect);
- // }
- // if (screenCapture != null) {
- // screenCapture.RecordMouse = capture.CursorVisible;
- // if (screenCapture.Start(25)) {
- // return;
- // }
- // // User clicked cancel or a problem occured
- // screenCapture.Stop();
- // screenCapture = null;
- // return;
- // }
- //}
// Take the captureRect, this already is specified as bitmap coordinates
_capture.Crop(_captureRect);
diff --git a/Greenshot/Helpers/HookHelper.cs b/Greenshot/Helpers/HookHelper.cs
deleted file mode 100644
index ca261a870..000000000
--- a/Greenshot/Helpers/HookHelper.cs
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * 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 .
- */
-using System;
-using System.Collections.Generic;
-using GreenshotPlugin.UnmanagedHelpers;
-using GreenshotPlugin.Core;
-
-namespace Greenshot.Helpers {
- public class HookHelper {
- private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(HookHelper));
- private static List hooks = new List();
- private static WinEventDelegate _winEventProc;
- private static uint oleEventThread = 0;
-
- ///
- /// Remove the made hooks
- ///
- public static void Unhook() {
- LOG.Debug("Cleaning winEvent hooks");
- foreach (IntPtr hook in hooks) {
- if (hook != IntPtr.Zero) {
- User32.UnhookWinEvent(hook);
- }
- }
- }
-
- ///
- /// Hook the WinEvents we are interested in
- ///
- public static void Hook() {
- LOG.Debug("Starting winEvent hooks");
- _winEventProc = new WinEventDelegate(WinEventProc);
- int processID = 0; //Process.GetCurrentProcess().Id;
- hooks.Add(User32.SetWinEventHook(WinEvent.EVENT_OBJECT_CREATE, WinEvent.EVENT_OBJECT_HIDE, IntPtr.Zero, _winEventProc, processID, 0, WinEventHookFlags.WINEVENT_SKIPOWNPROCESS));
- hooks.Add(User32.SetWinEventHook(WinEvent.EVENT_OBJECT_LOCATIONCHANGE, WinEvent.EVENT_OBJECT_LOCATIONCHANGE, IntPtr.Zero, _winEventProc, 0, 0, WinEventHookFlags.WINEVENT_SKIPOWNPROCESS));
- hooks.Add(User32.SetWinEventHook(WinEvent.EVENT_SYSTEM_MENUSTART, WinEvent.EVENT_SYSTEM_MENUPOPUPEND, IntPtr.Zero, _winEventProc, processID, 0, WinEventHookFlags.WINEVENT_SKIPOWNPROCESS));
- }
-
- ///
- /// Handle the WinEvent
- ///
- /// The Hook IntPtr
- /// Event Type to handle, enum WinEvent
- /// Window handle which caused the event
- /// Object ID, enum EventObjects
- /// Child ID of the window
- /// Thread which generated the ID
- ///
- private static void WinEventProc(IntPtr hWinEventHook, WinEvent eventType, IntPtr hwnd, EventObjects idObject, int idChild, uint dwEventThread, uint dwmsEventTime) {
- // Check if it's an event generated by a Window
- if (hwnd == IntPtr.Zero || idObject != EventObjects.OBJID_WINDOW) {
- // Other events do not interest us.
- return;
- }
- String classname = null;
- // Check if the event was generated by the OLE Event Thread, which causes a lot of create/destroy
- if (oleEventThread != 0 && dwEventThread == oleEventThread) {
- return;
- }
-
- // Only get the classname when it's not a destroy (classname is not available)
- if (eventType == WinEvent.EVENT_OBJECT_CREATE) {
- classname = WindowDetails.GetClassName(hwnd);
- // Make sure the OleMainThreadWndClass events are ignored.
- if (oleEventThread == 0) {
- if (classname == "OleMainThreadWndClass") {
- oleEventThread = dwEventThread;
- return;
- }
- }
- }
-
- LOG.DebugFormat("eventType={0},hwnd={1},classname={4},idObject={2},idChild={3},dwEventThread={5}", eventType, hwnd, idObject, idChild, classname, dwEventThread);
- }
- }
-}
diff --git a/Greenshot/Helpers/ScreenCaptureHelper.cs b/Greenshot/Helpers/ScreenCaptureHelper.cs
deleted file mode 100644
index 29e16ee38..000000000
--- a/Greenshot/Helpers/ScreenCaptureHelper.cs
+++ /dev/null
@@ -1,326 +0,0 @@
-/*
- * 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 .
- */
-using System;
-using System.Diagnostics;
-using System.Drawing;
-using System.Drawing.Imaging;
-using System.IO;
-using System.Runtime.InteropServices;
-using System.Text.RegularExpressions;
-using System.Threading;
-using System.Windows.Forms;
-using GreenshotPlugin.UnmanagedHelpers;
-using GreenshotPlugin.Core;
-using Greenshot.IniFile;
-
-namespace Greenshot.Helpers {
- ///
- /// Description of ScreenCaptureHelper.
- ///
- public class ScreenCaptureHelper {
- private static log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(ScreenCaptureHelper));
- private static CoreConfiguration conf = IniConfig.GetIniSection();
- private const int ALIGNMENT = 8;
- private IntPtr hWndDesktop = IntPtr.Zero;
- private IntPtr hDCDesktop = IntPtr.Zero;
- private IntPtr hDCDest = IntPtr.Zero;
- private IntPtr hDIBSection = IntPtr.Zero;
- private IntPtr hOldObject = IntPtr.Zero;
- private int framesPerSecond;
- private Thread backgroundTask;
- private bool stop = false;
- private AVIWriter aviWriter;
- private WindowDetails recordingWindow;
- private Rectangle recordingRectangle;
- public bool RecordMouse = false;
- private Size recordingSize;
- private IntPtr bits0 = IntPtr.Zero; //pointer to the raw bits that make up the bitmap.
- private Bitmap GDIBitmap;
- private string filename = null;
- private Stopwatch stopwatch = new Stopwatch();
- private bool disabledDWM = false;
-
- private ScreenCaptureHelper() {
- if (DWM.isDWMEnabled()) {
- // with DWM Composition disabled the capture goes ~2x faster
- DWM.DisableComposition();
- disabledDWM = true;
- }
- }
- public ScreenCaptureHelper(Rectangle recordingRectangle) : this() {
- this.recordingRectangle = recordingRectangle;
- }
- public ScreenCaptureHelper(WindowDetails recordingWindow) : this() {
- this.recordingWindow = recordingWindow;
- }
-
- ///
- /// Helper method to create an exception that might explain what is wrong while capturing
- ///
- /// string with current method
- /// Rectangle of what we want to capture
- ///
- private static Exception CreateCaptureException(string method, Size size) {
- Exception exceptionToThrow = User32.CreateWin32Exception(method);
- if (size != Size.Empty) {
- exceptionToThrow.Data.Add("Height", size.Height);
- exceptionToThrow.Data.Add("Width", size.Width);
- }
- return exceptionToThrow;
- }
-
- ///
- /// Start the recording
- ///
- ///
- ///
- public bool Start(int framesPerSecond) {
- if (recordingWindow != null) {
- string windowTitle = Regex.Replace(recordingWindow.Text, @"[^\x20\d\w]", "");
- if (string.IsNullOrEmpty(windowTitle)) {
- windowTitle = "greenshot-recording";
- }
- filename = Path.Combine(conf.OutputFilePath, windowTitle + ".avi");
-
- } else {
- filename = Path.Combine(conf.OutputFilePath, "greenshot-recording.avi");
- }
- if (File.Exists(filename)) {
- try {
- File.Delete(filename);
- } catch {}
- }
- LOG.InfoFormat("Capturing to {0}", filename);
-
- if (recordingWindow != null) {
- LOG.InfoFormat("Starting recording Window '{0}', {1}", recordingWindow.Text, recordingWindow.WindowRectangle);
- recordingSize = recordingWindow.WindowRectangle.Size;
- } else {
- LOG.InfoFormat("Starting recording rectangle {0}", recordingRectangle);
- recordingSize = recordingRectangle.Size;
- }
- //if (recordingSize.Width % ALIGNMENT > 0) {
- // LOG.InfoFormat("Correcting width to be factor alignment, {0} => {1}", recordingSize.Width, recordingSize.Width + (ALIGNMENT - (recordingSize.Width % ALIGNMENT)));
- // recordingSize = new Size(recordingSize.Width + (ALIGNMENT - (recordingSize.Width % ALIGNMENT)), recordingSize.Height);
- //}
- //if (recordingSize.Height % ALIGNMENT > 0) {
- // LOG.InfoFormat("Correcting Height to be factor alignment, {0} => {1}", recordingSize.Height, recordingSize.Height + (ALIGNMENT - (recordingSize.Height % ALIGNMENT)));
- // recordingSize = new Size(recordingSize.Width, recordingSize.Height + (ALIGNMENT - (recordingSize.Height % ALIGNMENT)));
- //}
- this.framesPerSecond = framesPerSecond;
- // "P/Invoke" Solution for capturing the screen
- hWndDesktop = User32.GetDesktopWindow();
- // get te hDC of the target window
- hDCDesktop = User32.GetWindowDC(hWndDesktop);
- // Make sure the last error is set to 0
- Win32.SetLastError(0);
-
- // create a device context we can copy to
- 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", recordingSize);
- // Cleanup
- User32.ReleaseDC(hWndDesktop, hDCDesktop);
- // throw exception
- throw exceptionToThrow;
- }
-
- // Create BitmapInfoHeader for CreateDIBSection
- BitmapInfoHeader bitmapInfoHeader = new BitmapInfoHeader(recordingSize.Width, recordingSize.Height, 32);
-
- // 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
- hDIBSection = GDI32.CreateDIBSection(hDCDesktop, ref bitmapInfoHeader, BitmapInfoHeader.DIB_RGB_COLORS, out bits0, IntPtr.Zero, 0);
-
- if (hDIBSection == IntPtr.Zero) {
- // Get Exception before the error is lost
- Exception exceptionToThrow = CreateCaptureException("CreateDIBSection", recordingSize);
- 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;
- }
- // Create a GDI Bitmap so we can use GDI and GDI+ operations on the same memory
- GDIBitmap = new Bitmap(recordingSize.Width, recordingSize.Height, 32, PixelFormat.Format32bppArgb, bits0);
- // select the bitmap object and store the old handle
- hOldObject = GDI32.SelectObject(hDCDest, hDIBSection);
- stop = false;
-
- aviWriter = new AVIWriter();
- // Comment the following 2 lines to make the user select it's own codec
- aviWriter.Codec = "msvc";
- aviWriter.Quality = 10000;
-
- aviWriter.FrameRate = framesPerSecond;
- if (aviWriter.Open(filename, recordingSize.Width, recordingSize.Height)) {
- // Start update check in the background
- backgroundTask = new Thread (new ThreadStart(CaptureFrame));
- backgroundTask.IsBackground = true;
- backgroundTask.Name = "Capture video";
- backgroundTask.Start();
- return true;
- } else {
- // Cancel
- aviWriter.Dispose();
- aviWriter = null;
- }
- return false;
- }
-
- ///
- /// Do the actual frame capture
- ///
- private void CaptureFrame() {
- int MSBETWEENCAPTURES = 1000/framesPerSecond;
- int msToNextCapture = MSBETWEENCAPTURES;
- stopwatch.Reset();
- while (!stop) {
- stopwatch.Start();
- Point captureLocation;
- if (recordingWindow != null) {
- recordingWindow.Reset();
- captureLocation = recordingWindow.Location;
- } else {
- captureLocation = new Point(recordingRectangle.X, recordingRectangle.Y);
- }
- // "Capture"
- GDI32.BitBlt(hDCDest, 0, 0, recordingSize.Width, recordingSize.Height, hDCDesktop, captureLocation.X, captureLocation.Y, CopyPixelOperation.SourceCopy);
- //GDI32.BitBlt(hDCDest, 0, 0, recordingSize.Width, recordingSize.Height, hDCDesktop, captureLocation.X, captureLocation.Y, CopyPixelOperation.SourceCopy | CopyPixelOperation.CaptureBlt);
-
- // Mouse
- if (RecordMouse) {
- CursorInfo cursorInfo = new CursorInfo();
- cursorInfo.cbSize = Marshal.SizeOf(cursorInfo);
- Point mouseLocation = Cursor.Position;
- mouseLocation.Offset(-captureLocation.X, -captureLocation.Y);
- if (User32.GetCursorInfo(out cursorInfo)) {
- User32.DrawIcon(hDCDest, mouseLocation.X, mouseLocation.Y, cursorInfo.hCursor);
- }
- }
- // add to avi
- try {
- aviWriter.AddLowLevelFrame(bits0);
- } catch (Exception) {
- LOG.Error("Error adding frame to avi, stopping capturing.");
- break;
- }
-
- int restTime = (int)(msToNextCapture - stopwatch.ElapsedMilliseconds);
-
- // Set time to next capture, we correct it if needed later.
- msToNextCapture = MSBETWEENCAPTURES;
- if (restTime > 0) {
- // We were fast enough, we wait for next capture
- Thread.Sleep(restTime);
- } else if (restTime < 0) {
- // Compensating, as we took to long
- int framesToSkip = ((-restTime) / MSBETWEENCAPTURES);
- int leftoverMillis = (-restTime) % MSBETWEENCAPTURES;
- //LOG.InfoFormat("Adding {0} empty frames to avi, leftover millis is {1}, sleeping {2} (of {3} total)", framesToSkip, leftover, sleepMillis, MSBETWEENCAPTURES);
- aviWriter.AddEmptyFrames(framesToSkip);
-
- // check how bad it is, if we only missed our target by a few millis we hope the next capture corrects this
- if (leftoverMillis > 0 && leftoverMillis <= 2) {
- // subtract the leftover from the millis to next capture, do nothing else
- msToNextCapture -= leftoverMillis;
- } else if (leftoverMillis > 0) {
- // it's more, we add an empty frame
- aviWriter.AddEmptyFrames(1);
- // we sleep to the next time and
- int sleepMillis = MSBETWEENCAPTURES - leftoverMillis;
- // Sleep to next capture
- Thread.Sleep(sleepMillis);
- }
- }
- stopwatch.Reset();
- }
- Cleanup();
- }
-
- ///
- /// Stop the recording, after the next frame
- ///
- public void Stop() {
- stop = true;
- if (backgroundTask != null) {
- backgroundTask.Join();
- }
- Cleanup();
- }
-
- ///
- /// Free resources
- ///
- private void Cleanup() {
- if (hOldObject != IntPtr.Zero && hDCDest != IntPtr.Zero) {
- // restore selection (old handle)
- GDI32.SelectObject(hDCDest, hOldObject);
- GDI32.DeleteDC(hDCDest);
- }
- if (hDCDesktop != IntPtr.Zero) {
- User32.ReleaseDC(hWndDesktop, hDCDesktop);
- }
- if (hDIBSection != IntPtr.Zero) {
- // free up the Bitmap object
- GDI32.DeleteObject(hDIBSection);
- }
-
- if (disabledDWM) {
- DWM.EnableComposition();
- }
- if (aviWriter != null) {
- aviWriter.Dispose();
- aviWriter = null;
-
- string ffmpegexe = PluginUtils.GetExePath("ffmpeg.exe");
- if (ffmpegexe != null) {
- try {
- string webMFile = filename.Replace(".avi", ".webm");
- string arguments = "-i \"" + filename + "\" -codec:v libvpx -quality good -cpu-used 0 -b:v 1000k -qmin 10 -qmax 42 -maxrate 1000k -bufsize 4000k -threads 4 \"" + webMFile + "\"";
- LOG.DebugFormat("Starting {0} with arguments {1}", ffmpegexe, arguments);
- ProcessStartInfo processStartInfo = new ProcessStartInfo(ffmpegexe, arguments);
- processStartInfo.CreateNoWindow = false;
- processStartInfo.RedirectStandardOutput = false;
- processStartInfo.UseShellExecute = false;
- Process process = Process.Start(processStartInfo);
- process.WaitForExit();
- if (process.ExitCode == 0) {
- MessageBox.Show("Recording written to " + webMFile);
- }
- } catch (Exception ex) {
- MessageBox.Show("Recording written to " + filename + " couldn't convert due to an error: " + ex.Message);
- }
- } else {
- MessageBox.Show("Recording written to " + filename);
- }
- }
- }
- }
-}
diff --git a/GreenshotPlugin/Core/WindowCapture.cs b/GreenshotPlugin/Core/WindowCapture.cs
index 38d1e01c9..6106ea575 100644
--- a/GreenshotPlugin/Core/WindowCapture.cs
+++ b/GreenshotPlugin/Core/WindowCapture.cs
@@ -18,6 +18,11 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
+
+using Greenshot.IniFile;
+using Greenshot.Plugin;
+using GreenshotPlugin.UnmanagedHelpers;
+using log4net;
using System;
using System.Collections.Generic;
using System.Diagnostics;
@@ -25,10 +30,6 @@ using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using System.Windows.Forms;
-using Greenshot.IniFile;
-using Greenshot.Plugin;
-using GreenshotPlugin.UnmanagedHelpers;
-using log4net;
namespace GreenshotPlugin.Core {
///
diff --git a/GreenshotPlugin/UnmanagedHelpers/GDI32.cs b/GreenshotPlugin/UnmanagedHelpers/GDI32.cs
index e6d7c9ba0..b767f33e5 100644
--- a/GreenshotPlugin/UnmanagedHelpers/GDI32.cs
+++ b/GreenshotPlugin/UnmanagedHelpers/GDI32.cs
@@ -76,6 +76,10 @@ namespace GreenshotPlugin.UnmanagedHelpers {
/// A hbitmap SafeHandle implementation
///
public class SafeHBitmapHandle : SafeObjectHandle {
+ [SecurityCritical]
+ private SafeHBitmapHandle() : base(true) {
+ }
+
[SecurityCritical]
public SafeHBitmapHandle(IntPtr preexistingHandle) : base(true) {
SetHandle(preexistingHandle);
@@ -86,6 +90,10 @@ namespace GreenshotPlugin.UnmanagedHelpers {
/// A hRegion SafeHandle implementation
///
public class SafeRegionHandle : SafeObjectHandle {
+ [SecurityCritical]
+ private SafeRegionHandle() : base(true) {
+ }
+
[SecurityCritical]
public SafeRegionHandle(IntPtr preexistingHandle) : base(true) {
SetHandle(preexistingHandle);
@@ -96,6 +104,10 @@ namespace GreenshotPlugin.UnmanagedHelpers {
/// A dibsection SafeHandle implementation
///
public class SafeDibSectionHandle : SafeObjectHandle {
+ [SecurityCritical]
+ private SafeDibSectionHandle() : base(true) {
+ }
+
[SecurityCritical]
public SafeDibSectionHandle(IntPtr preexistingHandle) : base(true) {
SetHandle(preexistingHandle);
@@ -112,6 +124,10 @@ namespace GreenshotPlugin.UnmanagedHelpers {
private SafeHandle hdc;
+ [SecurityCritical]
+ private SafeSelectObjectHandle() : base(true) {
+ }
+
[SecurityCritical]
public SafeSelectObjectHandle(SafeDCHandle hdc, SafeHandle newHandle) : base(true) {
this.hdc = hdc;
@@ -135,6 +151,10 @@ namespace GreenshotPlugin.UnmanagedHelpers {
[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);
@@ -154,6 +174,10 @@ namespace GreenshotPlugin.UnmanagedHelpers {
///
public class SafeDeviceContextHandle : SafeDCHandle {
private Graphics graphics = null;
+
+ [SecurityCritical]
+ private SafeDeviceContextHandle() : base(true) {
+ }
[SecurityCritical]
public SafeDeviceContextHandle(Graphics graphics, IntPtr preexistingHandle) : base(true) {