Recently I needed to take some screenshots of my screen that include the mouse pointer. While there are many programs out there that do just that I failed to find anything that is simple and easy enough and most importantly is free. There are some screen capture utilities that have free versions but non of them have the ability to include the mouse pointer or if they does this is included in the commercial version of the program.
After couple of hours evaluating I found the most promising solution - Cropper by Brian Scott (http://www.codeplex.com/cropper). It is not only free but it is open source C# application. Unfortunately it can't capture the mouse pointer. At first I though it is difficult to do that since most of the tools include this in the commercial version. After some time investigating I saw one article from Zarko Gajic in Delphi About (http://delphi.about.com/od/graphics/l/aa021004a.htm). I used to read him a lot when I was doing Delphi development.
I had what I needed so I guess the next step was obvious. I modified the excellent Cropper tool to include the mouse pointer. The truth is that the tool is designed to be extensible enough and it is not much of a code so the task went very easy. I will post here the method that does the cursor capturing. The rest I intend to send to Brian Scott to include it in the next version of the tool. Here it is
The NativeMethods.cs contains additions for the needed interop signatures.
[StructLayout(LayoutKind.Sequential)]
public struct CURSORINFO
{
public Int32 cbSize;
public Int32 flags;
public IntPtr hCursor;
public POINT ptScreenPos;
}
[DllImport("user32.dll")]
public static extern bool GetCursorInfo(out CURSORINFO pci);
public const Int32 CURSOR_SHOWING = 0x00000001;
[DllImport("user32.dll")]
public static extern IconHandle CopyIcon(IntPtr hIcon);
[StructLayout(LayoutKind.Sequential)]
public struct ICONINFO
{
public bool fIcon;
public Int32 xHotspot;
public Int32 yHotspot;
public IntPtr hbmMask;
public IntPtr hbmColor;
}
[DllImport("user32.dll")]
public static extern bool GetIconInfo(IconHandle hIcon, out ICONINFO piconinfo);
[SuppressUnmanagedCodeSecurity, SecurityCritical,
DllImport("user32.dll", EntryPoint = "DestroyIcon", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool DestroyIcon(IntPtr hIcon);
[SecurityCritical, SuppressUnmanagedCodeSecurity,
DllImport("gdi32.dll", EntryPoint = "DeleteObject", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool DeleteObject(IntPtr hObject);
[SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
public class IconHandle : SafeHandle
{
[SecurityCritical, SecurityTreatAsSafe]
public IconHandle()
: base(IntPtr.Zero, true)
{
}
[SecurityCritical]
protected override bool ReleaseHandle()
{
return DestroyIcon(base.handle);
}
public override bool IsInvalid
{
[SecurityCritical, SecurityTreatAsSafe]
get
{
return (base.handle == IntPtr.Zero);
}
}
}
And the additional method added to Fusion8.Cropper.Core.ImageCapture class.
private void AddCursor(Image image, Rectangle capturedRectangle)
{
using (Graphics graphics = Graphics.FromImage(image))
{
NativeMethods.CURSORINFO cursorInfo;
cursorInfo.cbSize = Marshal.SizeOf(typeof(NativeMethods.CURSORINFO));
if (NativeMethods.GetCursorInfo(out cursorInfo))
{
if (cursorInfo.flags == NativeMethods.CURSOR_SHOWING)
{
using (NativeMethods.IconHandle handle = NativeMethods.CopyIcon(cursorInfo.hCursor))
{
NativeMethods.ICONINFO iconInfo;
if (NativeMethods.GetIconInfo(handle, out iconInfo))
{
try
{
using (Icon icon = Icon.FromHandle(handle.DangerousGetHandle()))
{
int targetX = cursorInfo.ptScreenPos.X - capturedRectangle.X - iconInfo.xHotspot;
int targetY = cursorInfo.ptScreenPos.Y - capturedRectangle.Y - iconInfo.yHotspot;
graphics.DrawIcon(icon, targetX, targetY);
}
}
finally
{
NativeMethods.DeleteObject(iconInfo.hbmColor);
NativeMethods.DeleteObject(iconInfo.hbmMask);
}
}
}
}
}
else
{
Debug.WriteLine(Marshal.GetLastWin32Error());
}
}
}
Note the DeleteObject calls in the finally statement. I found couple of articles on the web that do not free these objects. You should avoid this mistake.
Here is the final result
Although I found the code quality not very good I think this is a great tool with all the functionality and the plug-ins. It does a wonderful job and is very user friendly. I will send my changes to Brian and hope you will like it. After all the biggest support you can give for an open source project is to use it.
Have fun!
Lubo
Currently rated 5.0 by 1 people
- Currently 5/5 Stars.
- 1
- 2
- 3
- 4
- 5