Added some missing files.

git-svn-id: http://svn.code.sf.net/p/greenshot/code/trunk@1603 7dccd23d-a4a3-4e1f-8c07-b4c1b4018ab4
This commit is contained in:
RKrom 2012-01-24 19:28:12 +00:00
commit e860872ae0
7 changed files with 2231 additions and 0 deletions

View file

@ -0,0 +1,901 @@
// 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.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using GreenshotPlugin.UnmanagedHelpers;
namespace Greenshot.Helpers {
/// <summary>
/// AVI files writing using Video for Windows interface.
/// </summary>
///
/// <remarks><para>The class allows to write AVI files using Video for Windows API.</para>
///
/// <para>Sample usage:</para>
/// /// // 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 &lt; 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( );
///
/// </remarks>
///
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 ";
/// <summary>
/// Width of video frames.
/// </summary>
///
/// <remarks><para>The property specifies the width of video frames, which are acceptable
/// by <see cref="AddFrame"/> method for saving, which is set in <see cref="Open"/>
/// method.</para></remarks>
///
public int Width {
get { return width; }
}
/// <summary>
/// Height of video frames.
/// </summary>
///
/// <remarks><para>The property specifies the height of video frames, which are acceptable
/// by <see cref="AddFrame"/> method for saving, which is set in <see cref="Open"/>
/// method.</para></remarks>
///
public int Height {
get { return height; }
}
/// <summary>
/// Current position in video stream.
/// </summary>
///
/// <remarks><para>The property tell current position in video stream, which actually equals
/// to the amount of frames added using <see cref="AddFrame"/> method.</para></remarks>
///
public int Position
{
get { return position; }
}
/// <summary>
/// Desired playing frame rate.
/// </summary>
///
/// <remarks><para>The property sets the video frame rate, which should be use during playing
/// of the video to be saved.</para>
///
/// <para><note>The property should be set befor opening new file to take effect.</note></para>
///
/// <para>Default frame rate is set to <b>25</b>.</para></remarks>
///
public int FrameRate
{
get { return rate; }
set { rate = value; }
}
/// <summary>
/// Codec used for video compression.
/// </summary>
///
/// <remarks><para>The property sets the FOURCC code of video compression codec, which needs to
/// be used for video encoding.</para>
///
/// <para><note>The property should be set befor opening new file to take effect.</note></para>
///
/// <para>Default video codec is set <b>"DIB "</b>, which means no compression.</para></remarks>
///
public string Codec
{
get { return codec; }
set { codec = value; }
}
/// <summary>
/// Compression video quality.
/// </summary>
///
/// <remarks><para>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.</para>
///
/// <para><note>The property should be set befor opening new file to take effect.</note></para>
///
/// <para>Default value is set to <b>-1</b> - default compression quality of the codec.</para></remarks>
///
public int Quality
{
get { return quality; }
set { quality = value; }
}
/// <summary>
/// Initializes a new instance of the <see cref="AVIWriter"/> class.
/// </summary>
///
/// <remarks>Initializes Video for Windows library.</remarks>
///
public AVIWriter() {
Avi32.AVIFileInit();
}
/// <summary>
/// Initializes a new instance of the <see cref="AVIWriter"/> class.
/// </summary>
///
/// <param name="codec">Codec to use for compression. eg [CVID],[IV50]</param>
///
/// <remarks>Initializes Video for Windows library.</remarks>
///
public AVIWriter(string codec) : this() {
this.codec = codec;
}
/// <summary>
/// Destroys the instance of the <see cref="AVIWriter"/> class.
/// </summary>
///
~AVIWriter() {
Dispose(false);
}
/// <summary>
/// Dispose the object.
/// </summary>
///
/// <remarks>Frees unmanaged resources used by the object. The object becomes unusable
/// after that.</remarks>
///
public void Dispose() {
Dispose(true);
// remove me from the Finalization queue
GC.SuppressFinalize(this);
}
/// <summary>
/// Dispose the object.
/// </summary>
///
/// <param name="disposing">Indicates if disposing was initiated manually.</param>
///
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();
}
/// <summary>
/// Create new AVI file and open it for writing.
/// </summary>
///
/// <param name="fileName">AVI file name to create.</param>
/// <param name="width">Video width.</param>
/// <param name="height">Video height.</param>
///
/// <remarks><para>The method opens (creates) a video files, configure video codec and prepares
/// the stream for saving video frames with a help of <see cref="AddFrame"/> method.</para></remarks>
///
/// <exception cref="ApplicationException">Failure of opening video files (the exception message
/// specifies the issues).</exception>
///
public bool Open(string fileName, int width, int height) {
lock (this) {
// calculate stride
stride = width * 4;
if ((stride % 4) != 0)
stride += (4 - stride % 4);
// create new file
if (Avi32.AVIFileOpen(out file, fileName, Avi32.OpenFileMode.Create | Avi32.OpenFileMode.Write, IntPtr.Zero) != 0) {
throw new ApplicationException("Failed opening file");
}
this.width = width;
this.height = height;
// describe new stream
Avi32.AVISTREAMINFO info = new Avi32.AVISTREAMINFO();
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;
// 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
if (codec == null) {
int retCode = Avi32.AVISaveOptions( stream, ref options );
if (retCode == 0) {
LOG.Debug("Cancel clicked!");
return false;
}
} else {
options.handler = Avi32.mmioFOURCC(codec);
options.quality = quality;
}
// create compressed stream
int retval = Avi32.AVIMakeCompressedStream(out streamCompressed, stream, ref options, IntPtr.Zero);
if (retval != 0) {
throw new ApplicationException("Failed creating compressed stream: " + retval);
}
// describe frame format
BitmapInfoHeader bitmapInfoHeader = new BitmapInfoHeader(width, height, 32);
// set frame format
retval = Avi32.AVIStreamSetFormat(streamCompressed, 0, ref bitmapInfoHeader, Marshal.SizeOf(bitmapInfoHeader.GetType()));
if (retval != 0) {
throw new ApplicationException("Failed creating compressed stream: "+ retval);
}
position = 0;
return true;
}
}
/// <summary>
/// Close video file.
/// </summary>
///
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;
}
}
}
/// <summary>
/// Add new frame to the AVI file.
/// </summary>
/// <param name="frameData">New frame data.</param>
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++;
}
}
}
/// <summary>
/// Windows API functions and structures.
/// </summary>
///
/// <remarks>The class provides Video for Windows and some other Avi32 functions and structurs.</remarks>
///
internal static class Avi32 {
/// <summary>
/// Copy a block of memory.
/// </summary>
///
/// <param name="dst">Destination pointer.</param>
/// <param name="src">Source pointer.</param>
/// <param name="count">Memory block's length to copy.</param>
///
/// <returns>Return's the value of <b>dst</b> - pointer to destination.</returns>
///
[DllImport("ntdll.dll")]
public static extern int memcpy(int dst, int src, int count);
// --- Video for Windows Functions
/// <summary>
/// Initialize the AVIFile library.
/// </summary>
///
[DllImport("avifil32.dll")]
public static extern void AVIFileInit();
/// <summary>
/// Exit the AVIFile library.
/// </summary>
[DllImport("avifil32.dll")]
public static extern void AVIFileExit();
/// <summary>
/// Open an AVI file.
/// </summary>
///
/// <param name="aviHandler">Opened AVI file interface.</param>
/// <param name="fileName">AVI file name.</param>
/// <param name="mode">Opening mode (see <see cref="OpenFileMode"/>).</param>
/// <param name="handler">Handler to use (<b>null</b> to use default).</param>
///
/// <returns>Returns zero on success or error code otherwise.</returns>
///
[DllImport("avifil32.dll", CharSet = CharSet.Unicode)]
public static extern int AVIFileOpen(out IntPtr aviHandler, String fileName, OpenFileMode mode, IntPtr handler);
/// <summary>
/// Release an open AVI stream.
/// </summary>
///
/// <param name="aviHandler">Open AVI file interface.</param>
///
/// <returns>Returns the reference count of the file.</returns>
///
[DllImport("avifil32.dll")]
public static extern int AVIFileRelease(IntPtr aviHandler);
/// <summary>
/// Get stream interface that is associated with a specified AVI file
/// </summary>
///
/// <param name="aviHandler">Handler to an open AVI file.</param>
/// <param name="streamHandler">Stream interface.</param>
/// <param name="streamType">Stream type to open.</param>
/// <param name="streamNumner">Count of the stream type. Identifies which occurrence of the specified stream type to access. </param>
///
/// <returns></returns>
///
[DllImport("avifil32.dll")]
public static extern int AVIFileGetStream(IntPtr aviHandler, out IntPtr streamHandler, int streamType, int streamNumner);
/// <summary>
/// Create a new stream in an existing file and creates an interface to the new stream.
/// </summary>
///
/// <param name="aviHandler">Handler to an open AVI file.</param>
/// <param name="streamHandler">Stream interface.</param>
/// <param name="streamInfo">Pointer to a structure containing information about the new stream.</param>
///
/// <returns>Returns zero if successful or an error otherwise.</returns>
///
[DllImport("avifil32.dll")]
public static extern int AVIFileCreateStream(IntPtr aviHandler, out IntPtr streamHandler, ref AVISTREAMINFO streamInfo);
/// <summary>
/// Release an open AVI stream.
/// </summary>
///
/// <param name="streamHandler">Handle to an open stream.</param>
///
/// <returns>Returns the current reference count of the stream.</returns>
///
[DllImport("avifil32.dll")]
public static extern int AVIStreamRelease(IntPtr streamHandler);
/// <summary>
/// Set the format of a stream at the specified position.
/// </summary>
///
/// <param name="streamHandler">Handle to an open stream.</param>
/// <param name="position">Position in the stream to receive the format.</param>
/// <param name="format">Pointer to a structure containing the new format.</param>
/// <param name="formatSize">Size, in bytes, of the block of memory referenced by <b>format</b>.</param>
///
/// <returns>Returns zero if successful or an error otherwise.</returns>
///
[DllImport("avifil32.dll")]
public static extern int AVIStreamSetFormat(IntPtr streamHandler, int position, ref BitmapInfoHeader format, int formatSize);
/// <summary>
/// Get the starting sample number for the stream.
/// </summary>
///
/// <param name="streamHandler">Handle to an open stream.</param>
///
/// <returns>Returns the number if successful or 1 otherwise.</returns>
///
[DllImport("avifil32.dll")]
public static extern int AVIStreamStart(IntPtr streamHandler);
/// <summary>
/// Get the length of the stream.
/// </summary>
/// <param name="streamHandler">Handle to an open stream.</param>
/// <returns>Returns the stream's length, in samples, if successful or -1 otherwise. </returns>
[DllImport("avifil32.dll")]
public static extern int AVIStreamLength(IntPtr streamHandler);
/// <summary>
/// Obtain stream header information.
/// </summary>
///
/// <param name="streamHandler">Handle to an open stream.</param>
/// <param name="streamInfo">Pointer to a structure to contain the stream information.</param>
/// <param name="infoSize">Size, in bytes, of the structure used for <b>streamInfo</b>.</param>
///
/// <returns>Returns zero if successful or an error otherwise.</returns>
///
[DllImport("avifil32.dll", CharSet = CharSet.Unicode)]
public static extern int AVIStreamInfo(IntPtr streamHandler, ref AVISTREAMINFO streamInfo, int infoSize);
/// <summary>
/// Prepare to decompress video frames from the specified video stream
/// </summary>
/// <param name="streamHandler">Pointer to the video stream used as the video source.</param>
/// <param name="wantedFormat">Pointer to a structure that defines the desired video format. Specify NULL to use a default format.</param>
/// <returns>Returns an object that can be used with the <see cref="AVIStreamGetFrame"/> function.</returns>
[DllImport("avifil32.dll")]
public static extern IntPtr AVIStreamGetFrameOpen(IntPtr streamHandler, ref BitmapInfoHeader wantedFormat);
/// <summary>
/// Prepare to decompress video frames from the specified video stream.
/// </summary>
/// <param name="streamHandler">Pointer to the video stream used as the video source.</param>
/// <param name="wantedFormat">Pointer to a structure that defines the desired video format. Specify NULL to use a default format.</param>
/// <returns>Returns a <b>GetFrame</b> object that can be used with the <see cref="AVIStreamGetFrame"/> function.</returns>
[DllImport("avifil32.dll")]
public static extern IntPtr AVIStreamGetFrameOpen(IntPtr streamHandler, int wantedFormat);
/// <summary>
/// Releases resources used to decompress video frames.
/// </summary>
/// <param name="getFrameObject">Handle returned from the <see cref="AVIStreamGetFrameOpen(IntPtr,int)"/> function.</param>
/// <returns>Returns zero if successful or an error otherwise.</returns>
[DllImport("avifil32.dll")]
public static extern int AVIStreamGetFrameClose(IntPtr getFrameObject);
/// <summary>
/// Return the address of a decompressed video frame.
/// </summary>
/// <param name="getFrameObject">Pointer to a GetFrame object.</param>
/// <param name="position">Position, in samples, within the stream of the desired frame.</param>
/// <returns>Returns a pointer to the frame data if successful or NULL otherwise.</returns>
[DllImport("avifil32.dll")]
public static extern IntPtr AVIStreamGetFrame(IntPtr getFrameObject, int position);
/// <summary>
/// Write data to a stream.
/// </summary>
/// <param name="streamHandler">Handle to an open stream.</param>
/// <param name="start">First sample to write.</param>
/// <param name="samples">Number of samples to write.</param>
/// <param name="buffer">Pointer to a buffer containing the data to write. </param>
/// <param name="bufferSize">Size of the buffer referenced by <b>buffer</b>.</param>
/// <param name="flags">Flag associated with this data.</param>
/// <param name="samplesWritten">Pointer to a buffer that receives the number of samples written. This can be set to NULL.</param>
/// <param name="bytesWritten">Pointer to a buffer that receives the number of bytes written. This can be set to NULL.</param>
///
/// <returns>Returns zero if successful or an error otherwise.</returns>
///
[DllImport("avifil32.dll")]
public static extern int AVIStreamWrite(IntPtr streamHandler, int start, int samples, IntPtr buffer, int bufferSize, int flags, IntPtr samplesWritten, IntPtr bytesWritten);
/// <summary>
/// Retrieve the save options for a file and returns them in a buffer.
/// </summary>
/// <param name="window">Handle to the parent window for the Compression Options dialog box.</param>
/// <param name="flags">Flags for displaying the Compression Options dialog box.</param>
/// <param name="streams">Number of streams that have their options set by the dialog box.</param>
/// <param name="streamInterfaces">Pointer to an array of stream interface pointers.</param>
/// <param name="options">Pointer to an array of pointers to AVICOMPRESSOPTIONS structures.</param>
/// <returns>Returns TRUE if the user pressed OK, FALSE for CANCEL, or an error otherwise.</returns>
[DllImport("avifil32.dll")]
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);
/// <summary>
/// Free the resources allocated by the AVISaveOptions function.
/// </summary>
/// <param name="streams">Count of the AVICOMPRESSOPTIONS structures referenced in <b>options</b>.</param>
/// <param name="options">Pointer to an array of pointers to AVICOMPRESSOPTIONS structures.</param>
/// <returns>Returns 0.</returns>
[DllImport("avifil32.dll")]
public static extern int AVISaveOptionsFree(int streams, [In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] IntPtr[] options);
/// <summary>
/// Create a compressed stream from an uncompressed stream and a
/// compression filter, and returns the address of a pointer to
/// the compressed stream.
/// </summary>
/// <param name="compressedStream">Pointer to a buffer that receives the compressed stream pointer.</param>
/// <param name="sourceStream">Pointer to the stream to be compressed.</param>
/// <param name="options">Pointer to a structure that identifies the type of compression to use and the options to apply.</param>
/// <param name="clsidHandler">Pointer to a class identifier used to create the stream.</param>
/// <returns>Returns 0 if successful or an error otherwise.</returns>
[DllImport("avifil32.dll")]
public static extern int AVIMakeCompressedStream(out IntPtr compressedStream, IntPtr sourceStream, ref AVICOMPRESSOPTIONS options, IntPtr clsidHandler);
// --- structures
/// <summary>
/// Structure, which contains information for a single stream .
/// </summary>
///
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 1)]
public struct AVISTREAMINFO
{
/// <summary>
/// Four-character code indicating the stream type.
/// </summary>
///
[MarshalAs(UnmanagedType.I4)]
public int type;
/// <summary>
/// Four-character code of the compressor handler that will compress this video stream when it is saved.
/// </summary>
///
[MarshalAs(UnmanagedType.I4)]
public int handler;
/// <summary>
/// Applicable flags for the stream.
/// </summary>
///
[MarshalAs(UnmanagedType.I4)]
public int flags;
/// <summary>
/// Capability flags; currently unused.
/// </summary>
///
[MarshalAs(UnmanagedType.I4)]
public int ñapabilities;
/// <summary>
/// Priority of the stream.
/// </summary>
///
[MarshalAs(UnmanagedType.I2)]
public short priority;
/// <summary>
/// Language of the stream.
/// </summary>
///
[MarshalAs(UnmanagedType.I2)]
public short language;
/// <summary>
/// Time scale applicable for the stream.
/// </summary>
///
/// <remarks>Dividing <b>rate</b> by <b>scale</b> gives the playback rate in number of samples per second.</remarks>
///
[MarshalAs(UnmanagedType.I4)]
public int scale;
/// <summary>
/// Rate in an integer format.
/// </summary>
///
[MarshalAs(UnmanagedType.I4)]
public int rate;
/// <summary>
/// Sample number of the first frame of the AVI file.
/// </summary>
///
[MarshalAs(UnmanagedType.I4)]
public int start;
/// <summary>
/// Length of this stream.
/// </summary>
///
/// <remarks>The units are defined by <b>rate</b> and <b>scale</b>.</remarks>
///
[MarshalAs(UnmanagedType.I4)]
public int length;
/// <summary>
/// Audio skew. This member specifies how much to skew the audio data ahead of the video frames in interleaved files.
/// </summary>
///
[MarshalAs(UnmanagedType.I4)]
public int initialFrames;
/// <summary>
/// Recommended buffer size, in bytes, for the stream.
/// </summary>
///
[MarshalAs(UnmanagedType.I4)]
public int suggestedBufferSize;
/// <summary>
/// Quality indicator of the video data in the stream.
/// </summary>
///
/// <remarks>Quality is represented as a number between 0 and 10,000.</remarks>
///
[MarshalAs(UnmanagedType.I4)]
public int quality;
/// <summary>
/// Size, in bytes, of a single data sample.
/// </summary>
///
[MarshalAs(UnmanagedType.I4)]
public int sampleSize;
/// <summary>
/// Dimensions of the video destination rectangle.
/// </summary>
///
[MarshalAs(UnmanagedType.Struct, SizeConst = 16)]
public RECT rectFrame;
/// <summary>
/// Number of times the stream has been edited.
/// </summary>
///
[MarshalAs(UnmanagedType.I4)]
public int editCount;
/// <summary>
/// Number of times the stream format has changed.
/// </summary>
///
[MarshalAs(UnmanagedType.I4)]
public int formatChangeCount;
/// <summary>
/// Description of the stream.
/// </summary>
///
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]
public string name;
}
/// <summary>
/// Structure, which contains information about a stream and how it is compressed and saved.
/// </summary>
///
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct AVICOMPRESSOPTIONS
{
/// <summary>
/// Four-character code indicating the stream type.
/// </summary>
///
[MarshalAs(UnmanagedType.I4)]
public int type;
/// <summary>
/// Four-character code for the compressor handler that will compress this video stream when it is saved.
/// </summary>
///
[MarshalAs(UnmanagedType.I4)]
public int handler;
/// <summary>
/// Maximum period between video key frames.
/// </summary>
///
[MarshalAs(UnmanagedType.I4)]
public int keyFrameEvery;
/// <summary>
/// Quality value passed to a video compressor.
/// </summary>
///
[MarshalAs(UnmanagedType.I4)]
public int quality;
/// <summary>
/// Video compressor data rate.
/// </summary>
///
[MarshalAs(UnmanagedType.I4)]
public int bytesPerSecond;
/// <summary>
/// Flags used for compression.
/// </summary>
///
[MarshalAs(UnmanagedType.I4)]
public int flags;
/// <summary>
/// Pointer to a structure defining the data format.
/// </summary>
///
[MarshalAs(UnmanagedType.I4)]
public int format;
/// <summary>
/// Size, in bytes, of the data referenced by <b>format</b>.
/// </summary>
///
[MarshalAs(UnmanagedType.I4)]
public int formatSize;
/// <summary>
/// Video-compressor-specific data; used internally.
/// </summary>
///
[MarshalAs(UnmanagedType.I4)]
public int parameters;
/// <summary>
/// Size, in bytes, of the data referenced by <b>parameters</b>.
/// </summary>
[MarshalAs(UnmanagedType.I4)]
public int parametersSize;
/// <summary>
/// Interleave factor for interspersing stream data with data from the first stream.
/// </summary>
///
[MarshalAs(UnmanagedType.I4)]
public int interleaveEvery;
}
// --- enumerations
/// <summary>
/// File access modes.
/// </summary>
///
[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
}
/// <summary>
/// .NET replacement of mmioFOURCC macros. Converts four characters to code.
/// </summary>
///
/// <param name="str">Four characters string.</param>
///
/// <returns>Returns the code created from provided characters.</returns>
///
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));
}
/// <summary>
/// Inverse to <see cref="mmioFOURCC"/>. Converts code to fout characters string.
/// </summary>
///
/// <param name="code">Code to convert.</param>
///
/// <returns>Returns four characters string.</returns>
///
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);
}
/// <summary>
/// Version of <see cref="AVISaveOptions(IntPtr, int, int, IntPtr[], IntPtr[])"/> for one stream only.
/// </summary>
///
/// <param name="stream">Stream to configure.</param>
/// <param name="options">Stream options.</param>
///
/// <returns>Returns TRUE if the user pressed OK, FALSE for CANCEL, or an error otherwise.</returns>
///
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;
}
}
}

View file

@ -0,0 +1,725 @@
/*
* Greenshot - a free and open source screenshot tool
* Copyright (C) 2007-2011 Thomas Braun, Jens Klingen, Robin Krom
*
* For more information see: http://getgreenshot.org/
* The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Printing;
using System.IO;
using System.Windows.Forms;
using Greenshot.Configuration;
using Greenshot.Drawing;
using Greenshot.Helpers;
using Greenshot.Forms;
using Greenshot.Plugin;
using GreenshotPlugin.UnmanagedHelpers;
using GreenshotPlugin.Core;
using IniFile;
namespace Greenshot.Helpers {
/// <summary>
/// CaptureHelper contains all the capture logic
/// </summary>
public class CaptureHelper {
private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(CaptureHelper));
private static CoreConfiguration conf = IniConfig.GetIniSection<CoreConfiguration>();
private static ScreenCaptureHelper screenCapture = null;
private List<WindowDetails> windows = new List<WindowDetails>();
private WindowDetails selectedCaptureWindow = null;
private Rectangle captureRect = Rectangle.Empty;
private bool captureMouseCursor = false;
private ICapture capture = null;
private ILanguage lang = Language.GetInstance();
private CaptureMode captureMode;
public static void CaptureClipboard() {
new CaptureHelper(CaptureMode.Clipboard).MakeCapture();
}
public static void CaptureRegion(bool captureMouse) {
new CaptureHelper(CaptureMode.Region, captureMouse).MakeCapture();
}
public static void CaptureRegion(bool captureMouse, IDestination destination) {
CaptureHelper captureHelper = new CaptureHelper(CaptureMode.Region, captureMouse, destination);
captureHelper.MakeCapture();
}
public static void CaptureFullscreen(bool captureMouse) {
new CaptureHelper(CaptureMode.FullScreen, captureMouse).MakeCapture();
}
public static void CaptureLastRegion(bool captureMouse) {
new CaptureHelper(CaptureMode.LastRegion, captureMouse).MakeCapture();
}
public static void CaptureIE(bool captureMouse) {
new CaptureHelper(CaptureMode.IE, captureMouse).MakeCapture();
}
public static void CaptureWindow(bool captureMouse) {
new CaptureHelper(CaptureMode.ActiveWindow, captureMouse).MakeCapture();
}
public static void CaptureWindow(WindowDetails windowToCapture) {
CaptureHelper captureHelper = new CaptureHelper(CaptureMode.ActiveWindow);
captureHelper.SelectedCaptureWindow = windowToCapture;
captureHelper.MakeCapture();
}
public static void CaptureWindowInteractive(bool captureMouse) {
new CaptureHelper(CaptureMode.Window, captureMouse).MakeCapture();
}
public static void CaptureFile(string filename) {
new CaptureHelper(CaptureMode.File).MakeCapture(filename);
}
public static void ImportCapture(ICapture captureToImport) {
CaptureHelper captureHelper = new CaptureHelper(CaptureMode.File);
captureHelper.capture = captureToImport;
captureHelper.HandleCapture();
}
public CaptureHelper(CaptureMode captureMode) {
this.captureMode = captureMode;
capture = new Capture();
}
public CaptureHelper(CaptureMode captureMode, bool captureMouseCursor) : this(captureMode) {
this.captureMouseCursor = captureMouseCursor;
}
public CaptureHelper(CaptureMode captureMode, bool captureMouseCursor, IDestination destination) : this(captureMode, captureMouseCursor) {
capture.CaptureDetails.AddDestination(destination);
}
public WindowDetails SelectedCaptureWindow {
get {
return selectedCaptureWindow;
}
set {
selectedCaptureWindow = value;
}
}
private void DoCaptureFeedback() {
if(conf.PlayCameraSound) {
SoundHelper.Play();
}
}
/// <summary>
/// Make Capture with file name
/// </summary>
/// <param name="filename">filename</param>
private void MakeCapture(string filename) {
capture.CaptureDetails.Filename = filename;
MakeCapture();
}
/// <summary>
/// Make Capture with specified destinations
/// </summary>
private void MakeCapture() {
// Experimental code
if (screenCapture != null) {
screenCapture.Stop();
screenCapture = null;
return;
}
LOG.Debug(String.Format("Capturing with mode {0} and using Cursor {1})", captureMode, captureMouseCursor));
capture.CaptureDetails.CaptureMode = captureMode;
// Add destinations if no-one passed a handler
if (capture.CaptureDetails.CaptureDestinations == null || capture.CaptureDetails.CaptureDestinations.Count == 0) {
AddConfiguredDestination();
}
PrepareForCaptureWithFeedback();
// Workaround for proble with DPI retrieval, the FromHwnd activates the window...
WindowDetails previouslyActiveWindow = WindowDetails.GetActiveWindow();
// Workaround for changed DPI settings in Windows 7
using (Graphics graphics = Graphics.FromHwnd(MainForm.instance.Handle)) {
capture.CaptureDetails.DpiX = graphics.DpiX;
capture.CaptureDetails.DpiY = graphics.DpiY;
}
if (previouslyActiveWindow != null) {
// Set previouslyActiveWindow as foreground window
previouslyActiveWindow.ToForeground();
}
// Delay for the Context menu
if (conf.CaptureDelay > 0) {
System.Threading.Thread.Sleep(conf.CaptureDelay);
} else {
conf.CaptureDelay = 0;
}
// Allways capture Mousecursor, only show when needed
capture = WindowCapture.CaptureCursor(capture);
capture.CursorVisible = false;
// Check if needed
if (captureMouseCursor && captureMode != CaptureMode.Clipboard && captureMode != CaptureMode.File) {
capture.CursorVisible = conf.CaptureMousepointer;
}
switch(captureMode) {
case CaptureMode.Window:
capture = WindowCapture.CaptureScreen(capture);
capture.CaptureDetails.AddMetaData("source", "Screen");
CaptureWithFeedback();
break;
case CaptureMode.ActiveWindow:
if (CaptureActiveWindow()) {
// 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.MoveElements(capture.ScreenBounds.Location.X-capture.Location.X, capture.ScreenBounds.Location.Y-capture.Location.Y);
capture.CaptureDetails.AddMetaData("source", "Window");
} else {
captureMode = CaptureMode.FullScreen;
capture = WindowCapture.CaptureScreen(capture);
capture.CaptureDetails.AddMetaData("source", "Screen");
capture.CaptureDetails.Title = "Screen";
}
HandleCapture();
break;
case CaptureMode.IE:
if (IECaptureHelper.CaptureIE(capture) != null) {
capture.CaptureDetails.AddMetaData("source", "Internet Explorer");
HandleCapture();
}
break;
case CaptureMode.FullScreen:
capture = WindowCapture.CaptureScreen(capture);
HandleCapture();
break;
case CaptureMode.Clipboard:
Image clipboardImage = null;
string text = "Clipboard";
if (ClipboardHelper.ContainsImage()) {
clipboardImage = ClipboardHelper.GetImage();
}
if (clipboardImage != null) {
if (capture != null) {
capture.Image = clipboardImage;
} else {
capture = new Capture(clipboardImage);
}
string title = ClipboardHelper.GetText();
if (title == null || title.Trim().Length == 0) {
title = "Clipboard";
}
capture.CaptureDetails.Title = title;
capture.CaptureDetails.AddMetaData("source", "Clipboard");
// Force Editor, keep picker
if (capture.CaptureDetails.HasDestination(Destinations.PickerDestination.DESIGNATION)) {
capture.CaptureDetails.ClearDestinations();
capture.CaptureDetails.AddDestination(DestinationHelper.GetDestination(Destinations.EditorDestination.DESIGNATION));
capture.CaptureDetails.AddDestination(DestinationHelper.GetDestination(Destinations.PickerDestination.DESIGNATION));
} else {
capture.CaptureDetails.ClearDestinations();
capture.CaptureDetails.AddDestination(DestinationHelper.GetDestination(Destinations.EditorDestination.DESIGNATION));
}
HandleCapture();
} else {
MessageBox.Show("Couldn't create bitmap from : " + text);
}
break;
case CaptureMode.File:
Bitmap fileBitmap = null;
string filename = capture.CaptureDetails.Filename;
if (!string.IsNullOrEmpty(filename)) {
try {
fileBitmap = ImageHelper.LoadBitmap(filename);
} catch (Exception e) {
LOG.Error(e.Message, e);
MessageBox.Show(lang.GetFormattedString(LangKey.error_openfile, filename));
}
}
if (fileBitmap != null) {
capture.CaptureDetails.Title = Path.GetFileNameWithoutExtension(filename);
capture.CaptureDetails.AddMetaData("file", filename);
capture.CaptureDetails.AddMetaData("source", "file");
if (capture != null) {
capture.Image = fileBitmap;
} else {
capture = new Capture(fileBitmap);
}
// Force Editor, keep picker, this is currently the only usefull destination
if (capture.CaptureDetails.HasDestination("Picker")) {
capture.CaptureDetails.ClearDestinations();
capture.CaptureDetails.AddDestination(DestinationHelper.GetDestination(Destinations.EditorDestination.DESIGNATION));
capture.CaptureDetails.AddDestination(DestinationHelper.GetDestination(Destinations.PickerDestination.DESIGNATION));
} else {
capture.CaptureDetails.ClearDestinations();
capture.CaptureDetails.AddDestination(DestinationHelper.GetDestination(Destinations.EditorDestination.DESIGNATION));
}
HandleCapture();
}
break;
case CaptureMode.LastRegion:
if (!RuntimeConfig.LastCapturedRegion.IsEmpty) {
capture = WindowCapture.CaptureScreen(capture);
capture.Crop(RuntimeConfig.LastCapturedRegion);
capture.CaptureDetails.AddMetaData("source", "screen");
HandleCapture();
}
break;
case CaptureMode.Region:
capture = WindowCapture.CaptureScreen(capture);
capture.CaptureDetails.AddMetaData("source", "screen");
CaptureWithFeedback();
break;
case CaptureMode.Video:
capture = WindowCapture.CaptureScreen(capture);
// Set the capturemode to be window
captureMode = CaptureMode.Window;
capture.CaptureDetails.AddMetaData("source", "Video");
CaptureWithFeedback();
break;
default:
LOG.Warn("Unknown capture mode: " + captureMode);
break;
}
}
/// <summary>
/// Pre-Initialization for CaptureWithFeedback, this will get all the windows before we change anything
/// </summary>
private void PrepareForCaptureWithFeedback() {
windows = new List<WindowDetails>();
// Start Enumeration of "active" windows
foreach (WindowDetails window in WindowDetails.GetAllWindows()) {
// 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);
windows.Add(window);
// Get window rectangle as capture Element
CaptureElement windowCaptureElement = new CaptureElement(windowRectangle);
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);
}
}
windows = WindowDetails.SortByZOrder(IntPtr.Zero, windows);
}
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 AddConfiguredDestination() {
foreach(string destinationDesignation in conf.OutputDestinations) {
IDestination destination = DestinationHelper.GetDestination(destinationDesignation);
if (destination != null) {
capture.CaptureDetails.AddDestination(destination);
}
}
}
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.
bool outputMade = false;
// Make sure the user sees that the capture is made
if (capture.CaptureDetails.CaptureMode != CaptureMode.File && capture.CaptureDetails.CaptureMode != CaptureMode.Clipboard) {
DoCaptureFeedback();
} else {
// If File || Clipboard
// Maybe not "made" but the original is still there... somehow
outputMade = true;
}
LOG.Debug("A capture of: " + capture.CaptureDetails.Title);
// check if someone has passed a destination
if (capture.CaptureDetails.CaptureDestinations == null || capture.CaptureDetails.CaptureDestinations.Count == 0) {
AddConfiguredDestination();
}
// Create Surface with capture, this way elements can be added automatically (like the mouse cursor)
Surface surface = new Surface(capture);
// Register notify events if this is wanted
if (conf.ShowTrayNotification) {
surface.SurfaceMessage += delegate(object source, SurfaceMessageEventArgs eventArgs) {
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:
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 (surface.LastSaveFullPath != null) {
ProcessStartInfo psi = new ProcessStartInfo("explorer");
psi.Arguments = Path.GetDirectoryName(eventArgs.Surface.LastSaveFullPath);
psi.UseShellExecute = false;
Process p = new Process();
p.StartInfo = psi;
p.Start();
}
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;
}
};
}
// Let the processors do their job
foreach(IProcessor processor in ProcessorHelper.GetAllProcessors()) {
if (processor.isActive) {
LOG.InfoFormat("Calling processor {0}", processor.Description);
processor.ProcessCapture(surface, capture.CaptureDetails);
}
}
// As the surfaces copies the reference to the image, make sure the image is not being disposed (a trick to save memory)
capture.Image = null;
// Get CaptureDetails as we need it even after the capture is disposed
ICaptureDetails captureDetails = capture.CaptureDetails;
bool canDisposeSurface = true;
if (captureDetails.HasDestination(Destinations.PickerDestination.DESIGNATION)) {
DestinationHelper.ExportCapture(Destinations.PickerDestination.DESIGNATION, surface, captureDetails);
captureDetails.CaptureDestinations.Clear();
canDisposeSurface = false;
}
// Disable capturing
captureMode = CaptureMode.None;
// Dispose the capture, we don't need it anymore (the surface copied all information and we got the title (if any)).
capture.Dispose();
capture = null;
int destinationCount = captureDetails.CaptureDestinations.Count;
if (destinationCount > 0) {
// Flag to detect if we need to create a temp file for the email
// or use the file that was written
foreach(IDestination destination in captureDetails.CaptureDestinations) {
if ("Picker".Equals(destination.Designation)) {
continue;
}
LOG.InfoFormat("Calling destination {0}", destination.Description);
bool destinationOk = destination.ExportCapture(surface, captureDetails);
if (Destinations.EditorDestination.DESIGNATION.Equals(destination.Designation) && destinationOk) {
canDisposeSurface = false;
}
outputMade = outputMade || destinationOk;
}
}
if (canDisposeSurface) {
surface.Dispose();
}
}
private bool CaptureActiveWindow() {
bool presupplied = false;
LOG.Debug("CaptureActiveWindow");
if (selectedCaptureWindow != null) {
LOG.Debug("Using supplied window");
presupplied = true;
} else {
selectedCaptureWindow = WindowDetails.GetActiveWindow();
if (selectedCaptureWindow != null) {
LOG.DebugFormat("Capturing window: {0} with {1}", selectedCaptureWindow.Text, selectedCaptureWindow.WindowRectangle);
}
}
if (selectedCaptureWindow == null || (!presupplied && selectedCaptureWindow.Iconic)) {
LOG.Warn("No window to capture!");
// Nothing to capture, code up in the stack will capture the full screen
return false;
}
if (selectedCaptureWindow != null && selectedCaptureWindow.Iconic) {
// Restore the window making sure it's visible!
// This is done mainly for a screen capture, but some applications like Excel and TOAD have weird behaviour!
selectedCaptureWindow.Restore();
}
selectedCaptureWindow.ToForeground();
selectedCaptureWindow = SelectCaptureWindow(selectedCaptureWindow);
if (selectedCaptureWindow == null) {
LOG.Warn("No window to capture, after SelectCaptureWindow!");
// Nothing to capture, code up in the stack will capture the full screen
return false;
}
// Fix for Bug #3430560
RuntimeConfig.LastCapturedRegion = selectedCaptureWindow.WindowRectangle;
bool returnValue = CaptureWindow(selectedCaptureWindow, capture, conf.WindowCaptureMode) != null;
return returnValue;
}
/// <summary>
/// Select the window to capture, this has logic which takes care of certain special applications
/// like TOAD or Excel
/// </summary>
/// <param name="windowToCapture">WindowDetails with the target Window</param>
/// <returns>WindowDetails with the target Window OR a replacement</returns>
public static WindowDetails SelectCaptureWindow(WindowDetails windowToCapture) {
Rectangle windowRectangle = windowToCapture.WindowRectangle;
if (windowToCapture.Iconic || windowRectangle.Width == 0 || windowRectangle.Height == 0) {
LOG.WarnFormat("Window {0} has nothing to capture, using workaround to find other window of same process.", windowToCapture.Text);
// Trying workaround, the size 0 arrises with e.g. Toad.exe, has a different Window when minimized
WindowDetails linkedWindow = WindowDetails.GetLinkedWindow(windowToCapture);
if (linkedWindow != null) {
windowRectangle = linkedWindow.WindowRectangle;
windowToCapture = linkedWindow;
} else {
return null;
}
}
return windowToCapture;
}
/// <summary>
/// Check if Process uses PresentationFramework.dll -> meaning it uses WPF
/// </summary>
/// <param name="process"></param>
/// <returns>true if the process uses WPF</returns>
private static bool isWPF(Process process) {
if (process != null) {
foreach(ProcessModule module in process.Modules) {
if (module.ModuleName.StartsWith("PresentationFramework")) {
LOG.InfoFormat("Found that Process {0} uses {1}, assuming it's using WPF", process.ProcessName, module.FileName);
return true;
}
}
}
return false;
}
/// <summary>
/// Capture the supplied Window
/// </summary>
/// <param name="windowToCapture">Window to capture</param>
/// <param name="captureForWindow">The capture to store the details</param>
/// <param name="windowCaptureMode">What WindowCaptureMode to use</param>
/// <returns></returns>
public static ICapture CaptureWindow(WindowDetails windowToCapture, ICapture captureForWindow, WindowCaptureMode windowCaptureMode) {
if (captureForWindow == null) {
captureForWindow = new Capture();
}
Rectangle windowRectangle = windowToCapture.WindowRectangle;
if (windowToCapture.Iconic) {
// Restore the window making sure it's visible!
windowToCapture.Restore();
}
// When Vista & DWM (Aero) enabled
bool dwmEnabled = DWM.isDWMEnabled();
// get process name to be able to exclude certain processes from certain capture modes
Process process = windowToCapture.Process;
bool isAutoMode = windowCaptureMode == WindowCaptureMode.Auto;
// For WindowCaptureMode.Auto we check:
// 1) Is window IE, use IE Capture
// 2) Is Windows >= Vista & DWM enabled: use DWM
// 3) Otherwise use GDI (Screen might be also okay but might lose content)
if (isAutoMode) {
if (conf.IECapture && windowToCapture.ClassName == "IEFrame") {
try {
ICapture ieCapture = IECaptureHelper.CaptureIE(captureForWindow);
if (ieCapture != null) {
return ieCapture;
}
} catch (Exception ex) {
LOG.WarnFormat("Problem capturing IE, skipping to normal capture. Exception message was: {0}", ex.Message);
}
}
// Take default screen
windowCaptureMode = WindowCaptureMode.Screen;
// Change to GDI, if allowed
if (conf.isGDIAllowed(process)) {
if (!dwmEnabled && isWPF(process)) {
// do not use GDI, as DWM is not enabled and the application uses PresentationFramework.dll -> isWPF
LOG.InfoFormat("Not using GDI for windows of process {0}, as the process uses WPF", process.ProcessName);
} else {
windowCaptureMode = WindowCaptureMode.GDI;
}
}
// Change to DWM, if enabled and allowed
if (dwmEnabled) {
if (conf.isDWMAllowed(process)) {
windowCaptureMode = WindowCaptureMode.Aero;
}
}
} else if (windowCaptureMode == WindowCaptureMode.Aero || windowCaptureMode == WindowCaptureMode.AeroTransparent) {
if (!dwmEnabled || !conf.isDWMAllowed(process)) {
// Take default screen
windowCaptureMode = WindowCaptureMode.Screen;
// Change to GDI, if allowed
if (conf.isGDIAllowed(process)) {
windowCaptureMode = WindowCaptureMode.GDI;
}
}
} else if (windowCaptureMode == WindowCaptureMode.GDI && !conf.isGDIAllowed(process)) {
// GDI not allowed, take screen
windowCaptureMode = WindowCaptureMode.Screen;
}
LOG.InfoFormat("Capturing window with mode {0}", windowCaptureMode);
bool captureTaken = false;
// Try to capture
while (!captureTaken) {
if (windowCaptureMode == WindowCaptureMode.GDI) {
ICapture tmpCapture = null;
if (conf.isGDIAllowed(process)) {
tmpCapture = windowToCapture.CaptureWindow(captureForWindow);
}
if (tmpCapture != null) {
captureForWindow = tmpCapture;
captureTaken = true;
} else {
// A problem, try Screen
windowCaptureMode = WindowCaptureMode.Screen;
}
} else if (windowCaptureMode == WindowCaptureMode.Aero || windowCaptureMode == WindowCaptureMode.AeroTransparent) {
ICapture tmpCapture = null;
if (conf.isDWMAllowed(process)) {
tmpCapture = windowToCapture.CaptureDWMWindow(captureForWindow, windowCaptureMode, isAutoMode);
}
if (tmpCapture != null) {
captureForWindow = tmpCapture;
captureTaken = true;
} else {
// A problem, try GDI
windowCaptureMode = WindowCaptureMode.GDI;
}
} else {
// Screen capture
windowRectangle.Intersect(captureForWindow.ScreenBounds);
try {
captureForWindow = WindowCapture.CaptureRectangle(captureForWindow, windowRectangle);
captureTaken = true;
} catch (Exception e) {
LOG.Error("Problem capturing", e);
return null;
}
}
}
if (captureForWindow != null && windowToCapture != null) {
captureForWindow.CaptureDetails.Title = windowToCapture.Text;
((Bitmap)captureForWindow.Image).SetResolution(captureForWindow.CaptureDetails.DpiX, captureForWindow.CaptureDetails.DpiY);
}
return captureForWindow;
}
#region capture with feedback
private void CaptureWithFeedback() {
using (CaptureForm captureForm = new CaptureForm(capture, windows)) {
DialogResult result = captureForm.ShowDialog();
if (result == DialogResult.OK) {
selectedCaptureWindow = captureForm.SelectedCaptureWindow;
captureRect = captureForm.CaptureRectangle;
// Get title
if (selectedCaptureWindow != null) {
capture.CaptureDetails.Title = selectedCaptureWindow.Text;
}
// Experimental code
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(15)) {
return;
}
// User clicked cancel or a problem occured
screenCapture.Stop();
screenCapture = null;
return;
}
}
if (captureRect.Height > 0 && captureRect.Width > 0) {
// Take the captureRect, this already is specified as bitmap coordinates
capture.Crop(captureRect);
// save for re-capturing later and show recapture context menu option
RuntimeConfig.LastCapturedRegion = captureRect;
HandleCapture();
}
}
}
}
#endregion
}
}

View file

@ -0,0 +1,124 @@
/*
* Greenshot - a free and open source screenshot tool
* Copyright (C) 2007-2011 Thomas Braun, Jens Klingen, Robin Krom
*
* For more information see: http://getgreenshot.org/
* The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using Greenshot.Plugin;
using GreenshotPlugin.Core;
namespace Greenshot.Helpers {
/// <summary>
/// Description of DestinationHelper.
/// </summary>
public static class DestinationHelper {
private static log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(DestinationHelper));
private static Dictionary<string, IDestination> RegisteredDestinations = new Dictionary<string, IDestination>();
/// Initialize the destinations
static DestinationHelper() {
foreach(Type destinationType in InterfaceUtils.GetSubclassesOf(typeof(IDestination),true)) {
// Only take our own
if (!"Greenshot.Destinations".Equals(destinationType.Namespace)) {
continue;
}
if (!destinationType.IsAbstract) {
IDestination destination;
try {
destination = (IDestination)Activator.CreateInstance(destinationType);
} catch (Exception e) {
LOG.ErrorFormat("Can't create instance of {0}", destinationType);
LOG.Error(e);
continue;
}
if (destination.isActive) {
LOG.DebugFormat("Found destination {0} with designation {1}", destinationType.Name, destination.Designation);
RegisterDestination(destination);
} else {
LOG.DebugFormat("Ignoring destination {0} with designation {1}", destinationType.Name, destination.Designation);
}
}
}
}
/// <summary>
/// Register your destination here, if it doesn't come from a plugin and needs to be available
/// </summary>
/// <param name="destination"></param>
public static void RegisterDestination(IDestination destination) {
// don't test the key, an exception should happen wenn it's not unique
RegisteredDestinations.Add(destination.Designation, destination);
}
/// <summary>
/// Get a list of all destinations, registered or supplied by a plugin
/// </summary>
/// <returns></returns>
public static List<IDestination> GetAllDestinations() {
List<IDestination> destinations = new List<IDestination>();
destinations.AddRange(RegisteredDestinations.Values);
foreach(IGreenshotPlugin plugin in PluginHelper.instance.Plugins.Values) {
destinations.AddRange(plugin.Destinations());
}
destinations.Sort();
return destinations;
}
/// <summary>
/// Get a destination by a designation
/// </summary>
/// <param name="designation">Designation of the destination</param>
/// <returns>IDestination or null</returns>
public static IDestination GetDestination(string designation) {
if (designation == null) {
return null;
}
if (RegisteredDestinations.ContainsKey(designation)) {
return RegisteredDestinations[designation];
}
foreach(IGreenshotPlugin plugin in PluginHelper.instance.Plugins.Values) {
foreach(IDestination destination in plugin.Destinations()) {
if (designation.Equals(destination.Designation)) {
return destination;
}
}
}
return null;
}
/// <summary>
/// A simple helper method which will call ExportCapture for the destination with the specified designation
/// </summary>
/// <param name="designation"></param>
/// <param name="surface"></param>
/// <param name="captureDetails"></param>
public static void ExportCapture(string designation, ISurface surface, ICaptureDetails captureDetails) {
if (RegisteredDestinations.ContainsKey(designation)) {
IDestination destination = RegisteredDestinations[designation];
if (destination.isActive) {
if (destination.ExportCapture(surface, captureDetails)) {
// Export worked, set the modified flag
surface.Modified = false;
}
}
}
}
}
}

View file

@ -0,0 +1,63 @@
/*
* Greenshot - a free and open source screenshot tool
* Copyright (C) 2007-2011 Thomas Braun, Jens Klingen, Robin Krom
*
* For more information see: http://getgreenshot.org/
* The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
namespace Greenshot.Helpers {
/// <summary>
/// Description of GeometryHelper.
/// </summary>
public static class GeometryHelper {
/// <summary>
/// Finds the distance between two points on a 2D surface.
/// </summary>
/// <param name="x1">The point on the x-axis of the first point</param>
/// <param name="x2">The point on the x-axis of the second point</param>
/// <param name="y1">The point on the y-axis of the first point</param>
/// <param name="y2">The point on the y-axis of the second point</param>
/// <returns></returns>
public static int Distance2D(int x1, int y1, int x2, int y2) {
//Our end result
int result = 0;
//Take x2-x1, then square it
double part1 = Math.Pow((x2 - x1), 2);
//Take y2-y1, then square it
double part2 = Math.Pow((y2 - y1), 2);
//Add both of the parts together
double underRadical = part1 + part2;
//Get the square root of the parts
result = (int)Math.Sqrt(underRadical);
//Return our result
return result;
}
/// <summary>
/// Calculates the angle of a line defined by two points on a 2D surface.
/// </summary>
/// <param name="x1">The point on the x-axis of the first point</param>
/// <param name="x2">The point on the x-axis of the second point</param>
/// <param name="y1">The point on the y-axis of the first point</param>
/// <param name="y2">The point on the y-axis of the second point</param>
/// <returns></returns>
public static double Angle2D(int x1, int y1, int x2, int y2) {
return Math.Atan2(y2 - y1, x2 - x1) * 180 / Math.PI;
}
}
}

View file

@ -0,0 +1,121 @@
/*
* Greenshot - a free and open source screenshot tool
* Copyright (C) 2007-2011 Thomas Braun, Jens Klingen, Robin Krom
*
* For more information see: http://getgreenshot.org/
* The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using Greenshot.Plugin;
using GreenshotPlugin.Core;
namespace Greenshot.Helpers {
/// <summary>
/// Description of ProcessorHelper.
/// </summary>
public static class ProcessorHelper {
private static log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(ProcessorHelper));
private static Dictionary<string, IProcessor> RegisteredProcessors = new Dictionary<string, IProcessor>();
/// Initialize the Processors
static ProcessorHelper() {
foreach(Type ProcessorType in InterfaceUtils.GetSubclassesOf(typeof(IProcessor),true)) {
// Only take our own
if (!"Greenshot.Processors".Equals(ProcessorType.Namespace)) {
continue;
}
if (!ProcessorType.IsAbstract) {
IProcessor Processor;
try {
Processor = (IProcessor)Activator.CreateInstance(ProcessorType);
} catch (Exception e) {
LOG.ErrorFormat("Can't create instance of {0}", ProcessorType);
LOG.Error(e);
continue;
}
if (Processor.isActive) {
LOG.DebugFormat("Found Processor {0} with designation {1}", ProcessorType.Name, Processor.Designation);
RegisterProcessor(Processor);
} else {
LOG.DebugFormat("Ignoring Processor {0} with designation {1}", ProcessorType.Name, Processor.Designation);
}
}
}
}
/// <summary>
/// Register your Processor here, if it doesn't come from a plugin and needs to be available
/// </summary>
/// <param name="Processor"></param>
public static void RegisterProcessor(IProcessor Processor) {
// don't test the key, an exception should happen wenn it's not unique
RegisteredProcessors.Add(Processor.Designation, Processor);
}
/// <summary>
/// Get a list of all Processors, registered or supplied by a plugin
/// </summary>
/// <returns></returns>
public static List<IProcessor> GetAllProcessors() {
List<IProcessor> Processors = new List<IProcessor>();
Processors.AddRange(RegisteredProcessors.Values);
foreach(IGreenshotPlugin plugin in PluginHelper.instance.Plugins.Values) {
Processors.AddRange(plugin.Processors());
}
Processors.Sort();
return Processors;
}
/// <summary>
/// Get a Processor by a designation
/// </summary>
/// <param name="designation">Designation of the Processor</param>
/// <returns>IProcessor or null</returns>
public static IProcessor GetProcessor(string designation) {
if (designation == null) {
return null;
}
if (RegisteredProcessors.ContainsKey(designation)) {
return RegisteredProcessors[designation];
}
foreach(IGreenshotPlugin plugin in PluginHelper.instance.Plugins.Values) {
foreach(IProcessor Processor in plugin.Processors()) {
if (designation.Equals(Processor.Designation)) {
return Processor;
}
}
}
return null;
}
/// <summary>
/// A simple helper method which will call ProcessCapture for the Processor with the specified designation
/// </summary>
/// <param name="designation"></param>
/// <param name="surface"></param>
/// <param name="captureDetails"></param>
public static void ProcessCapture(string designation, ISurface surface, ICaptureDetails captureDetails) {
if (RegisteredProcessors.ContainsKey(designation)) {
IProcessor Processor = RegisteredProcessors[designation];
if (Processor.isActive) {
Processor.ProcessCapture(surface, captureDetails);
}
}
}
}
}

View file

@ -0,0 +1,262 @@
/*
* Greenshot - a free and open source screenshot tool
* Copyright (C) 2007-2011 Thomas Braun, Jens Klingen, Robin Krom
*
* For more information see: http://getgreenshot.org/
* The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
using System.Threading;
using System.Windows.Forms;
using Greenshot;
using Greenshot.Configuration;
using Greenshot.Plugin;
using GreenshotPlugin.UnmanagedHelpers;
using GreenshotPlugin.Core;
using IniFile;
namespace Greenshot.Helpers {
/// <summary>
/// Description of ScreenCaptureHelper.
/// </summary>
public class ScreenCaptureHelper {
private static log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(ScreenCaptureHelper));
private static CoreConfiguration conf = IniConfig.GetIniSection<CoreConfiguration>();
private const int MAX_FRAMES = 500;
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;
public ScreenCaptureHelper(Rectangle recordingRectangle) {
this.recordingRectangle = recordingRectangle;
}
public ScreenCaptureHelper(WindowDetails recordingWindow) {
this.recordingWindow = recordingWindow;
}
/// <summary>
/// Helper method to create an exception that might explain what is wrong while capturing
/// </summary>
/// <param name="method">string with current method</param>
/// <param name="captureBounds">Rectangle of what we want to capture</param>
/// <returns></returns>
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;
}
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 % 8 > 0) {
LOG.InfoFormat("Correcting width to be factor 8, {0} => {1}", recordingSize.Width, recordingSize.Width + (8-(recordingSize.Width % 8)));
recordingSize = new Size(recordingSize.Width + (8-(recordingSize.Width % 8)), recordingSize.Height);
}
if (recordingSize.Height % 8 > 0) {
LOG.InfoFormat("Correcting Height to be factor 8, {0} => {1}", recordingSize.Height, recordingSize.Height + (8-(recordingSize.Height % 8)));
recordingSize = new Size(recordingSize.Width, recordingSize.Height + (8-(recordingSize.Height % 8)));
}
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 = 99;
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.Start();
return true;
} else {
// Cancel
aviWriter.Dispose();
aviWriter = null;
}
return false;
}
private void CaptureFrame() {
int MSBETWEENCAPTURES = 1000/framesPerSecond;
int msToNextCapture = MSBETWEENCAPTURES;
while (!stop) {
DateTime nextCapture = DateTime.Now.AddMilliseconds(msToNextCapture);
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 | 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 sleeptime = (int)(nextCapture.Subtract(DateTime.Now).Ticks / TimeSpan.TicksPerMillisecond);
if (sleeptime > 0) {
Thread.Sleep(sleeptime);
msToNextCapture = MSBETWEENCAPTURES;
} else {
// Compensating
msToNextCapture = Math.Max(0, MSBETWEENCAPTURES - sleeptime);
}
}
Cleanup();
}
public void Stop() {
stop = true;
if (backgroundTask != null) {
backgroundTask.Join();
}
Cleanup();
}
/// <summary>
/// Free resources
/// </summary>
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 (aviWriter != null) {
aviWriter.Dispose();
aviWriter = null;
MessageBox.Show("Recording written to " + filename);
}
}
}
}

View file

@ -0,0 +1,35 @@
/*
* Greenshot - a free and open source screenshot tool
* Copyright (C) 2007-2011 Thomas Braun, Jens Klingen, Robin Krom
*
* For more information see: http://getgreenshot.org/
* The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
namespace Greenshot.Helpers {
public class WindowWrapper : System.Windows.Forms.IWin32Window {
public WindowWrapper(IntPtr handle) {
_hwnd = handle;
}
public IntPtr Handle {
get { return _hwnd; }
}
private IntPtr _hwnd;
}
}