From be36a3f42b0bc761864e2f2bc24484405e7fb48a Mon Sep 17 00:00:00 2001 From: RKrom Date: Mon, 16 Jun 2014 11:25:04 +0200 Subject: [PATCH] Fixed some errors, removed obsolete code, removed some anonymous delegates and added some additional disposing code in the CaptureHelper.cs --- Greenshot/Forms/AboutForm.cs | 10 +- Greenshot/Forms/CaptureForm.cs | 37 +- Greenshot/Forms/MainForm.cs | 27 +- Greenshot/Forms/SettingsForm.cs | 24 +- Greenshot/Greenshot.csproj | 3 - Greenshot/Helpers/AviHelper.cs | 1119 --------------------- Greenshot/Helpers/CaptureHelper.cs | 329 +++--- Greenshot/Helpers/HookHelper.cs | 94 -- Greenshot/Helpers/ScreenCaptureHelper.cs | 326 ------ GreenshotPlugin/Core/WindowCapture.cs | 9 +- GreenshotPlugin/UnmanagedHelpers/GDI32.cs | 24 + 11 files changed, 211 insertions(+), 1791 deletions(-) delete mode 100644 Greenshot/Helpers/AviHelper.cs delete mode 100644 Greenshot/Helpers/HookHelper.cs delete mode 100644 Greenshot/Helpers/ScreenCaptureHelper.cs 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) {