Create Full Featured Screen Capturing App - C#
Screen Capturing SDK sample in C# demonstrating ‘Create Full Featured Screen Capturing App’
CapturingThread.cs
using System;
using System.Drawing;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows.Forms;
using BytescoutScreenCapturingLib;
// NOTE: if you are getting error like "invalid image" related to loading the SDK's dll then
// try to do the following:
// 1) remove the reference to the SDK by View - Solution Explorer
// then click on References, select Bytescout... reference name and right-click it and select Remove
// 2) To re-add click on the menu: Project - Add Reference
// 3) In "Add Reference" dialog switch to "COM" tab and find Bytescout...
// 4) Select it and click "Add"
// 5) Recompile the application
// Note: if you need to run on both x64 and x86 then please make sure you have set "Embed Interop Types" to True for this reference
namespace ScreenCapturing
{
public class CapturingThreadData
{
public CaptureAreaType CaptureType;
public String TempFile;
public Rectangle CaptureRectangle;
public bool ShowWebCamStream;
public int Result = 0; // 0 - success; 1 - error
public string ErrorText;
}
public class CapturingThread
{
public static void ThreadProc(Object obj)
{
Capturer capturer = new Capturer(); // create new screen capturer object
CapturingThreadData data = (CapturingThreadData) obj;
if (Program.Cfg.WriteLog)
capturer.SetLogFile(Path.GetTempPath() + Application.ProductName + " log.txt");
capturer.RegistrationName = "demo";
capturer.RegistrationKey = "demo";
if (Program.Cfg.AudioDevice != "")
{
capturer.CurrentAudioDeviceName = Program.Cfg.AudioDevice;
}
if (Program.Cfg.AudioLine != "")
{
capturer.CurrentAudioDeviceLineName = Program.Cfg.AudioLine;
}
if (Program.Cfg.SelectedVideoCodecTab == 0)
{
capturer.CurrentWMVAudioCodecName = Program.Cfg.WmvAudioCodec;
capturer.CurrentWMVAudioFormat = Program.Cfg.WmvAudioFormat;
capturer.CurrentWMVVideoCodecName = Program.Cfg.WmvVideoCodec;
Program.Cfg.WmvAudioCodec = capturer.CurrentWMVAudioCodecName;
Program.Cfg.WmvAudioFormat = capturer.CurrentWMVAudioFormat;
Program.Cfg.WmvVideoCodec = capturer.CurrentWMVVideoCodecName;
}
else
{
capturer.CurrentAudioCodecName = Program.Cfg.AviAudioCodec;
capturer.CurrentVideoCodecName = Program.Cfg.AviVideoCodec;
}
capturer.AudioEnabled = Program.Cfg.EnableAudio;
// this option tells to use captured area dimensions as output video width/height
// or use user defined video dimensions
capturer.MatchOutputSizeToTheSourceSize = !Program.Cfg.ResizeOutputVideo;
capturer.FPS = Program.Cfg.FPS;
capturer.ShowMouseHotSpot = Program.Cfg.ShowMouseHotSpot;
capturer.CaptureMouseCursor = Program.Cfg.CaptureMouseCursor;
capturer.AnimateMouseClicks = Program.Cfg.AnimateMouseClicks;
capturer.AnimateMouseButtons = Program.Cfg.AnimateMouseButtons;
capturer.MouseAnimationDuration = Program.Cfg.MouseAnimationDuration;
capturer.MouseSpotRadius = Program.Cfg.MouseSpotRadius;
capturer.MouseHotSpotColor = (uint) ColorTranslator.ToOle(Program.Cfg.MouseHotSpotColor);
capturer.MouseCursorLeftClickAnimationColor = (uint) ColorTranslator.ToOle(Program.Cfg.MouseCursorLeftClickAnimationColor);
capturer.MouseCursorRightClickAnimationColor = (uint) ColorTranslator.ToOle(Program.Cfg.MouseCursorRightClickAnimationColor);
capturer.CaptureRectLeft = data.CaptureRectangle.Left;
capturer.CaptureRectTop = data.CaptureRectangle.Top;
capturer.CaptureRectWidth = data.CaptureRectangle.Width;
capturer.CaptureRectHeight = data.CaptureRectangle.Height;
capturer.KeepAspectRatio = Program.Cfg.KeepAspectRatio;
// show recording time stamp
capturer.OverlayingRedTextCaption = "Recording: {RUNNINGMIN}:{RUNNINGSEC}:{RUNNINGMSEC} on {CURRENTYEAR}-{CURRENTMONTH}-{CURRENTDAY} at {CURRENTHOUR}:{CURRENTMIN}:{CURRENTSEC}:{CURRENTMSEC}";
capturer.OutputWidth = Program.Cfg.OutputWidth;
capturer.OutputHeight = Program.Cfg.OutputHeight;
if ((capturer.WebCamCount > 0) && (data.ShowWebCamStream))
{
capturer.AddWebCamVideo = true;
if (!String.IsNullOrEmpty(Program.Cfg.WebCameraDevice))
{
capturer.CurrentWebCamName = Program.Cfg.WebCameraDevice;
}
capturer.SetWebCamVideoRectangle(Program.Cfg.WebCameraWindowX, Program.Cfg.WebCameraWindowY, Program.Cfg.WebCameraWindowWidth, Program.Cfg.WebCameraWindowHeight);
}
data.TempFile = Path.GetTempFileName();
data.TempFile = Path.ChangeExtension(data.TempFile, (Program.Cfg.SelectedVideoCodecTab == 0) ? ".wmv" : ".avi");
capturer.OutputFileName = data.TempFile;
capturer.CapturingType = data.CaptureType;
// set border around captured area if we are not capturing entire screen
if (capturer.CapturingType != CaptureAreaType.catScreen &&
capturer.CapturingType != CaptureAreaType.catWebcamFullScreen)
{
// set border style
capturer.CaptureAreaBorderType = Program.Cfg.CaptureAreaBorderType;
capturer.CaptureAreaBorderColor = (uint) ColorTranslator.ToOle(Program.Cfg.CaptureAreaBorderColor);
capturer.CaptureAreaBorderWidth = Program.Cfg.CaptureAreaBorderWidth;
}
try
{
capturer.Run();
// IMPORTANT: if you want to check for some code if need to stop the recording then make sure you are
// using Thread.Sleep(1) inside the checking loop, so you have the loop like
// Do
// Thread.Sleep(1)
// While StopButtonNotClicked
}
catch (COMException ex)
{
data.ErrorText = ex.Message;
data.Result = 1;
Marshal.ReleaseComObject(capturer);
return;
}
try
{
Thread.Sleep(Timeout.Infinite);
}
catch (ThreadInterruptedException)
{
capturer.Stop();
data.Result = 0;
}
catch (Exception ex)
{
data.ErrorText = ex.Message;
data.Result = 1;
}
finally
{
Marshal.ReleaseComObject(capturer);
}
}
}
}
ColorControl.cs
using System;
using System.Drawing;
using System.Windows.Forms;
using System.ComponentModel;
namespace ScreenCapturing
{
public enum CustomBorderStyle { None, Dashed, Dotted, Bump, Etched, Flat, Raised, Sunken };
public class ColorControl : Control
{
private CustomBorderStyle _borderStyle = CustomBorderStyle.None;
private ToolTip _toolTip;
private IContainer components;
[DefaultValue(CustomBorderStyle.None)]
public CustomBorderStyle BorderStyle
{
get { return _borderStyle; }
set
{
_borderStyle = value;
Refresh();
}
}
public ColorControl()
{
InitializeComponent();
SetStyle(ControlStyles.AllPaintingInWmPaint, true);
SetStyle(ControlStyles.UserPaint, true);
SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
UpdateStyles();
AutoSize = false;
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
e.Graphics.FillRectangle(new SolidBrush(ForeColor), ClientRectangle);
if (BorderStyle == CustomBorderStyle.Dotted)
{
ControlPaint.DrawBorder(e.Graphics, ClientRectangle, SystemColors.ControlDarkDark, ButtonBorderStyle.Dotted);
}
else if (BorderStyle == CustomBorderStyle.Dashed)
{
ControlPaint.DrawBorder(e.Graphics, ClientRectangle, SystemColors.ControlDarkDark, ButtonBorderStyle.Dashed);
}
else if (BorderStyle != CustomBorderStyle.None)
{
Border3DStyle style;
switch (BorderStyle)
{
case CustomBorderStyle.Bump: style = Border3DStyle.Bump; break;
case CustomBorderStyle.Etched: style = Border3DStyle.Etched; break;
case CustomBorderStyle.Raised: style = Border3DStyle.Raised; break;
case CustomBorderStyle.Sunken: style = Border3DStyle.Sunken; break;
default: style = Border3DStyle.Flat; break;
}
ControlPaint.DrawBorder3D(e.Graphics, ClientRectangle, style);
}
if (Focused)
{
Rectangle focusRect = new Rectangle(ClientRectangle.X + 2, ClientRectangle.Y + 2, ClientRectangle.Width - 4, ClientRectangle.Height - 4);
ControlPaint.DrawFocusRectangle(e.Graphics, focusRect);
}
}
protected override void OnGotFocus(EventArgs e)
{
base.OnGotFocus(e);
Invalidate();
}
protected override void OnLostFocus(EventArgs e)
{
base.OnLostFocus(e);
Invalidate();
}
protected override void OnMouseClick(MouseEventArgs e)
{
base.OnMouseClick(e);
Focus();
if (e.Button == MouseButtons.Left)
{
using (ColorDialog fd = new ColorDialog())
{
fd.AnyColor = true;
fd.FullOpen = true;
fd.Color = Color.FromArgb(255, ForeColor);
int[] customColors = Program.Cfg.CustomColors;
if (customColors != null && customColors.Length > 0)
{
fd.CustomColors = customColors;
}
if (fd.ShowDialog() == DialogResult.OK)
{
ForeColor = fd.Color;
Program.Cfg.CustomColors = fd.CustomColors;
}
}
}
else if (e.Button == MouseButtons.Right)
{
ContextMenu menu = new ContextMenu();
menu.MenuItems.Add(new MenuItem("Select Transparent Color", menu_Click));
menu.Show(this, e.Location);
}
}
void menu_Click(object sender, EventArgs e)
{
ForeColor = Color.Transparent;
}
protected override void OnKeyDown(KeyEventArgs e)
{
using (ColorDialog fd = new ColorDialog())
{
fd.AnyColor = true;
fd.FullOpen = true;
fd.Color = ForeColor;
int[] customColors = Program.Cfg.CustomColors;
if (customColors != null && customColors.Length > 0)
{
fd.CustomColors = customColors;
}
if (fd.ShowDialog() == DialogResult.OK)
{
ForeColor = fd.Color;
Program.Cfg.CustomColors = fd.CustomColors;
}
}
base.OnKeyDown(e);
}
protected override void OnForeColorChanged(EventArgs e)
{
String colorName = String.Empty, rgb, tooltip;
if (ForeColor.ToKnownColor() != 0)
{
colorName = ForeColor.ToKnownColor().ToString();
}
else if (ForeColor.IsNamedColor)
{
colorName = ForeColor.ToString();
}
rgb = String.Format("R={0}; G={1}; B={2}", ForeColor.R, ForeColor.G, ForeColor.B);
if (colorName.Length > 0)
{
tooltip = String.Format("{0} ({1})", colorName, rgb);
}
else
{
tooltip = rgb;
}
_toolTip.SetToolTip(this, tooltip);
base.OnForeColorChanged(e);
}
private void InitializeComponent()
{
components = new Container();
_toolTip = new ToolTip(components);
SuspendLayout();
//
// ColorControl
//
_toolTip.SetToolTip(this, "Color");
ResumeLayout(false);
}
}
}
Config.cs
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using Microsoft.Win32;
using BytescoutScreenCapturingLib;
// NOTE: if you are getting error like "invalid image" related to loading the SDK's dll then
// try to do the following:
// 1) remove the reference to the SDK by View - Solution Explorer
// then click on References, select Bytescout... reference name and right-click it and select Remove
// 2) To re-add click on the menu: Project - Add Reference
// 3) In "Add Reference" dialog switch to "COM" tab and find Bytescout...
// 4) Select it and click "Add"
// 5) Recompile the application
// Note: if you need to run on both x64 and x86 then please make sure you have set "Embed Interop Types" to True for this reference
namespace ScreenCapturing
{
public class Config
{
public int[] CustomColors { get { return Get<int[]>("CustomColors", null); } set { Options["CustomColors"] = value; } }
public Point WindowLocation { get { return Get<Point>("WindowLocation", Point.Empty); } set { Options["WindowLocation"] = value; } }
public string AudioDevice { get { return Get<string>("AudioDevice", ""); } set { Options["AudioDevice"] = value; } }
public string AudioLine { get { return Get<string>("AudioLine", ""); } set { Options["AudioLine"] = value; } }
public string AviAudioCodec { get { return Get<string>("AviAudioCodec", "PCM"); } set { Options["AviAudioCodec"] = value; } }
public string AviVideoCodec { get { return Get<string>("AviVideoCodec", "Bytescout Lossless Video Codec"); } set { Options["AviVideoCodec"] = value; } }
public string WmvAudioCodec { get { return Get<string>("WmvAudioCodec", "Windows Media Audio 9"); } set { Options["WmvAudioCodec"] = value; } }
public int WmvAudioFormat { get { return Get<int>("WmvAudioFormat", 28); } set { Options["WmvAudioFormat"] = value; } } // 28 is 128 kbps audio format for WMV
public string WmvVideoCodec { get { return Get<string>("WmvVideoCodec", "Windows Media Video 9"); } set { Options["WmvVideoCodec"] = value; } }
public bool EnableAudio { get { return Get<bool>("EnableAudio", false); } set { Options["EnableAudio"] = value; } }
public bool ResizeOutputVideo { get { return Get<bool>("ResizeOutputVideo", true); } set { Options["ResizeOutputVideo"] = value; } }
public int OutputWidth { get { return Get<int>("OutputWidth", 1024); } set { Options["OutputWidth"] = value; } }
public int OutputHeight { get { return Get<int>("OutputHeight", 600); } set { Options["OutputHeight"] = value; } }
public bool KeepAspectRatio { get { return Get<bool>("KeepAspectRatio", true); } set { Options["KeepAspectRatio"] = value; } }
public float FPS { get { return Get<float>("FPS", 14.985f); } set { Options["FPS"] = value; } }
public bool WriteLog { get { return Get<bool>("WriteLog", false); } set { Options["WriteLog"] = value; } }
public bool DoNotShowMessage1 { get { return Get<bool>("DoNotShowMessage1", false); } set { Options["DoNotShowMessage1"] = value; } }
public string LastUsedFolder { get { return Get<string>("LastUsedFolder", ""); } set { Options["LastUsedFolder"] = value; } }
public int SelectedVideoCodecTab { get { return Get<int>("SelectedVideoCodecTab", 0); } set { Options["SelectedVideoCodecTab"] = value; } }
public string WebCameraDevice { get { return Get<string>("WebCameraDevice", ""); } set { Options["WebCameraDevice"] = value; } }
public int WebCameraWindowX { get { return Get<int>("WebCameraWindowX", 10); } set { Options["WebCameraWindowX"] = value; } }
public int WebCameraWindowY { get { return Get<int>("WebCameraWindowY", 10); } set { Options["WebCameraWindowY"] = value; } }
public int WebCameraWindowWidth { get { return Get<int>("WebCameraWindowWidth", 160); } set { Options["WebCameraWindowWidth"] = value; } }
public int WebCameraWindowHeight { get { return Get<int>("WebCameraWindowHeight", 120); } set { Options["WebCameraWindowHeight"] = value; } }
public bool ShowMouseHotSpot { get { return Get<bool>("ShowMouseHotSpot", true); } set { Options["ShowMouseHotSpot"] = value; } }
public bool CaptureMouseCursor { get { return Get<bool>("CaptureMouseCursor", true); } set { Options["CaptureMouseCursor"] = value; } }
public bool AnimateMouseClicks { get { return Get<bool>("AnimateMouseClicks", true); } set { Options["AnimateMouseClicks"] = value; } }
public bool AnimateMouseButtons { get { return Get<bool>("AnimateMouseButtons", false); } set { Options["AnimateMouseButtons"] = value; } }
public int MouseAnimationDuration { get { return Get<int>("MouseAnimationDuration", 600); } set { Options["MouseAnimationDuration"] = value; } }
public int MouseSpotRadius { get { return Get<int>("MouseSpotRadius", 60); } set { Options["MouseSpotRadius"] = value; } }
public Color MouseHotSpotColor { get { return Get<Color>("MouseHotSpotColor", Color.FromArgb(255, 255, 0)); } set { Options["MouseHotSpotColor"] = value; } }
public Color MouseCursorLeftClickAnimationColor { get { return Get<Color>("MouseCursorLeftClickAnimationColor", Color.FromArgb(0, 0, 255)); } set { Options["MouseCursorLeftClickAnimationColor"] = value; } }
public Color MouseCursorRightClickAnimationColor { get { return Get<Color>("MouseCursorRightClickAnimationColor", Color.FromArgb(0, 255, 0)); } set { Options["MouseCursorRightClickAnimationColor"] = value; } }
public CaptureAreaBorderType CaptureAreaBorderType { get { return Get<CaptureAreaBorderType>("CaptureAreaBorderType", CaptureAreaBorderType.cabtSolid); } set { Options["CaptureAreaBorderType"] = value; } }
public Color CaptureAreaBorderColor { get { return Get<Color>("CaptureAreaBorderColor", Color.Red); } set { Options["CaptureAreaBorderColor"] = value; } }
public int CaptureAreaBorderWidth { get { return Get<int>("CaptureAreaBorderWidth", 2); } set { Options["CaptureAreaBorderWidth"] = value; } }
private readonly String _strKey;
public Dictionary<string, object> Options = new Dictionary<string, object>();
public bool Subsection;
public Config()
{
_strKey = Program.RegistryKey;
}
public Config(String section)
{
Debug.Assert(!String.IsNullOrEmpty(section));
Subsection = true;
_strKey = Program.RegistryKey + "\\" + section;
}
public T Get<T>(String optionName, Object defaultValue)
{
Debug.Assert(!String.IsNullOrEmpty(optionName));
object value;
if (Options.TryGetValue(optionName, out value))
{
return (T) value;
}
else
{
String s = (String) Registry.GetValue("HKEY_CURRENT_USER\\" + _strKey, optionName, null);
if (s == null)
{
return (T) defaultValue;
}
else
{
TypeConverter tc;
if (typeof(T) == typeof(int[]))
{
tc = new IntegerArrayConverter();
}
else
{
tc = TypeDescriptor.GetConverter(typeof(T));
}
try
{
value = tc.ConvertFromString(s);
}
catch (Exception)
{
value = defaultValue;
}
Options.Add(optionName, value);
return (T) value;
}
}
}
public void Set(String optionName, Object value)
{
Debug.Assert(!String.IsNullOrEmpty(optionName));
Options[optionName] = value;
}
public void Save()
{
RegistryKey key = Registry.CurrentUser.CreateSubKey(_strKey);
if (key != null)
{
foreach (KeyValuePair<string, object> de in Options)
{
TypeConverter tc;
String s;
if (de.Value == null)
{
s = "";
}
else
{
if (de.Value is int[])
{
tc = new IntegerArrayConverter();
}
else
{
tc = TypeDescriptor.GetConverter(de.Value);
}
s = tc.ConvertToString(de.Value);
}
key.SetValue(de.Key, s);
}
key.Flush();
}
}
}
public class IntegerArrayConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
if (sourceType == typeof(string))
{
return true;
}
return base.CanConvertFrom(context, sourceType);
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
if (value is string)
{
string[] ss = ((string) value).Split(new char[] { ';' });
List<int> list = new List<int>();
foreach (string s in ss)
{
if (!String.IsNullOrEmpty(s))
{
list.Add(Int32.Parse(s));
}
}
return list.ToArray();
}
return base.ConvertFrom(context, culture, value);
}
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
if (destinationType == typeof(string))
{
return true;
}
return base.CanConvertTo(context, destinationType);
}
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
{
if (destinationType == typeof(string) && value is int[])
{
StringBuilder sb = new StringBuilder();
foreach (int x in (int[]) value)
{
if (sb.Length > 0)
{
sb.Append(";");
}
sb.Append(x.ToString());
}
return sb.ToString();
}
return base.ConvertTo(context, culture, value, destinationType);
}
}
}
CustomMessageBox.cs
using System;
using System.Windows.Forms;
namespace ScreenCapturing
{
public partial class CustomMessageBox : Form
{
public bool DoNotShow = false;
public CustomMessageBox(string title, string text)
{
InitializeComponent();
base.Text = title;
label1.Text = text;
}
private void cbDoNotAsk_CheckedChanged(object sender, EventArgs e)
{
DoNotShow = cbDoNotShow.Checked;
}
}
}
CustomMessageBox.designer.cs
��n a m e s p a c e S c r e e n C a p t u r i n g
{
p a r t i a l c l a s s C u s t o m M e s s a g e B o x
{
/ / / <