Link Search Menu Expand Document

Record Screen Video From Separate Thread - VB.NET

Screen Capturing SDK sample in VB.NET demonstrating ‘Record Screen Video From Separate Thread’

CapturingThread.vb
Imports System.Drawing
Imports System.IO
Imports System.Runtime.InteropServices
Imports System.Threading
Imports 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

Public Class CapturingThread

    Public Shared Sub ThreadProc(ByVal obj As Object)

        Dim data As CapturingThreadData = DirectCast(obj, CapturingThreadData)
        data.Success = True

        ' Prepare Capturer:

        Dim capturer As New Capturer()
        capturer.RegistrationName = "demo"
        capturer.RegistrationKey = "demo"

        capturer.CaptureRectLeft = data.CaptureRectangle.Left
        capturer.CaptureRectTop = data.CaptureRectangle.Top
        capturer.CaptureRectWidth = data.CaptureRectangle.Width
        capturer.CaptureRectHeight = data.CaptureRectangle.Height

        capturer.OutputWidth = 640
        capturer.OutputHeight = 480

        ' // WMV and WEBM output use WMVVideoBitrate property to control output video bitrate
        ' // so try to increase it by x2 or x3 times if you think the output video are you are getting is laggy
        ' capturer.WMVVideoBitrate = capturer.WMVVideoBitrate * 2
        
        data.TempFile = Path.GetTempFileName()
        data.TempFile = Path.ChangeExtension(data.TempFile, ".wmv")

        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 And capturer.CapturingType <> CaptureAreaType.catWebcamFullScreen Then

            capturer.CaptureAreaBorderType = CaptureAreaBorderType.cabtDashed
            capturer.CaptureAreaBorderColor = CType(ColorTranslator.ToOle(Color.Red), UInteger)

        End If


        ' Wait for events:

        Dim events As WaitHandle() = New WaitHandle() {data.StartOrResumeEvent, data.PauseEvent, data.StopEvent}

        Try

            While (True)

                Dim i As Integer = WaitHandle.WaitAny(events)

                If events(i) Is data.StartOrResumeEvent Then

                    If Not capturer.IsRunning Then
                        capturer.Run()
                    End If

                ElseIf events(i) Is data.PauseEvent Then

                    If capturer.IsRunning Then
                        capturer.Pause()
                    End If

                ElseIf events(i) Is data.StopEvent Then

                    capturer.Stop()
                    Exit While

                End If
                
            End While

        Catch ex As Exception

            data.ErrorText = ex.Message
            data.Success = False

        Finally

            ' Release resources
            Marshal.ReleaseComObject(capturer)

        End Try

    End Sub

End Class

CapturingThreadData.vb
Imports System.Drawing
Imports System.Threading
Imports BytescoutScreenCapturingLib

Public Class CapturingThreadData

    Public CaptureType As CaptureAreaType
    Public TempFile As String
    Public CaptureRectangle As Rectangle = New Rectangle(0, 0, 320, 240)

    Public Success As Boolean
    Public ErrorText As String

    Public StartOrResumeEvent As AutoResetEvent = New AutoResetEvent(False) ' event signalling to start or resume the recodring
    Public PauseEvent As AutoResetEvent = New AutoResetEvent(False) ' event signalling to pause the recodring
    Public StopEvent As AutoResetEvent = New AutoResetEvent(False) ' event signalling to stop the recording 

End Class



Form1.Designer.vb
��Partial Class Form1

	''' <summary>

	''' Required designer variable.

	''' </summary>

	Private components As System.ComponentModel.IContainer = Nothing



	''' <summary>

	''' Clean up any resources being used.

	''' </summary>

	''' <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>

	Protected Overrides Sub Dispose(disposing As Boolean)

		If disposing AndAlso (components IsNot Nothing) Then

			components.Dispose()

		End If

		MyBase.Dispose(disposing)

	End Sub



	#Region "Windows Form Designer generated code"



	''' <summary>

	''' Required method for Designer support - do not modify

	''' the contents of this method with the code editor.

	''' </summary>

	Private Sub InitializeComponent()

        Me.cmbCapturingType = New System.Windows.Forms.ComboBox()

        Me.label1 = New System.Windows.Forms.Label()

        Me.tableLayoutPanel1 = New System.Windows.Forms.TableLayoutPanel()

        Me.btnPauseResume = New System.Windows.Forms.Button()

        Me.btnStart = New System.Windows.Forms.Button()

        Me.btnStop = New System.Windows.Forms.Button()

        Me.tableLayoutPanel1.SuspendLayout()

        Me.SuspendLayout()

        '

        'cmbCapturingType

        '

        Me.cmbCapturingType.Anchor = CType(((System.Windows.Forms.AnchorStyles.Top Or System.Windows.Forms.AnchorStyles.Left) _

            Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles)

        Me.cmbCapturingType.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList

        Me.cmbCapturingType.FormattingEnabled = True

        Me.cmbCapturingType.Items.AddRange(New Object() {"Area around the mouse pointer", "Full screen"})

        Me.cmbCapturingType.Location = New System.Drawing.Point(97, 12)

        Me.cmbCapturingType.Name = "cmbCapturingType"

        Me.cmbCapturingType.Size = New System.Drawing.Size(378, 21)

        Me.cmbCapturingType.TabIndex = 0

        '

        'label1

        '

        Me.label1.AutoSize = True

        Me.label1.Location = New System.Drawing.Point(12, 15)

        Me.label1.Name = "label1"

        Me.label1.Size = New System.Drawing.Size(79, 13)

        Me.label1.TabIndex = 3

        Me.label1.Text = "Capturing Type"

        '

        'tableLayoutPanel1

        '

        Me.tableLayoutPanel1.Anchor = CType((((System.Windows.Forms.AnchorStyles.Top Or System.Windows.Forms.AnchorStyles.Bottom) _

            Or System.Windows.Forms.AnchorStyles.Left) _

            Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles)

        Me.tableLayoutPanel1.ColumnCount = 3

        Me.tableLayoutPanel1.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33.0!))

        Me.tableLayoutPanel1.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33.0!))

        Me.tableLayoutPanel1.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 34.0!))

        Me.tableLayoutPanel1.Controls.Add(Me.btnPauseResume, 0, 0)

        Me.tableLayoutPanel1.Controls.Add(Me.btnStart, 0, 0)

        Me.tableLayoutPanel1.Controls.Add(Me.btnStop, 2, 0)

        Me.tableLayoutPanel1.Location = New System.Drawing.Point(12, 52)

        Me.tableLayoutPanel1.Name = "tableLayoutPanel1"

        Me.tableLayoutPanel1.RowCount = 1

        Me.tableLayoutPanel1.RowStyles.Add(New System.Windows.Forms.RowStyle())

        Me.tableLayoutPanel1.Size = New System.Drawing.Size(463, 57)

        Me.tableLayoutPanel1.TabIndex = 6

        '

        'btnPauseResume

        '

        Me.btnPauseResume.Enabled = False

        Me.btnPauseResume.Location = New System.Drawing.Point(155, 3)

        Me.btnPauseResume.Name = "btnPauseResume"

        Me.btnPauseResume.Size = New System.Drawing.Size(143, 44)

        Me.btnPauseResume.TabIndex = 5

        Me.btnPauseResume.Text = "Pause"

        Me.btnPauseResume.UseVisualStyleBackColor = True

        '

        'btnStart

        '

        Me.btnStart.Location = New System.Drawing.Point(3, 3)

        Me.btnStart.Name = "btnStart"

        Me.btnStart.Size = New System.Drawing.Size(143, 44)

        Me.btnStart.TabIndex = 1

        Me.btnStart.Text = "Start"

        Me.btnStart.UseVisualStyleBackColor = True

        '

        'btnStop

        '

        Me.btnStop.Enabled = False

        Me.btnStop.Location = New System.Drawing.Point(307, 3)

        Me.btnStop.Name = "btnStop"

        Me.btnStop.Size = New System.Drawing.Size(143, 44)

        Me.btnStop.TabIndex = 4

        Me.btnStop.Text = "Stop"

        Me.btnStop.UseVisualStyleBackColor = True

        '

        'Form1

        '

        Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)

        Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font

        Me.ClientSize = New System.Drawing.Size(487, 121)

        Me.Controls.Add(Me.tableLayoutPanel1)

        Me.Controls.Add(Me.label1)

        Me.Controls.Add(Me.cmbCapturingType)

        Me.MaximizeBox = False

        Me.MinimizeBox = False

        Me.Name = "Form1"

        Me.ShowIcon = False

        Me.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen

        Me.Text = "Capture From Separate Thread"

        Me.tableLayoutPanel1.ResumeLayout(False)

        Me.ResumeLayout(False)

        Me.PerformLayout()



    End Sub



	#End Region



	Private cmbCapturingType As System.Windows.Forms.ComboBox

    Private label1 As System.Windows.Forms.Label

    Private WithEvents tableLayoutPanel1 As System.Windows.Forms.TableLayoutPanel

    Private WithEvents btnPauseResume As System.Windows.Forms.Button

    Private WithEvents btnStart As System.Windows.Forms.Button

    Private WithEvents btnStop As System.Windows.Forms.Button

End Class




Form1.vb
Imports System.Diagnostics
Imports System.IO
Imports System.Threading
Imports System.Windows.Forms
Imports 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

Public Partial Class Form1
	Inherits Form

    Private _capturingThread As Thread
    Private _capturingThreadData As CapturingThreadData  ' data to exchange between form and capturing thread

    Public Sub New()

        InitializeComponent()

        _capturingThreadData = New CapturingThreadData()

        cmbCapturingType.SelectedIndex = 0

    End Sub

    Private Sub btnStart_Click(sender As Object, e As EventArgs) Handles btnStart.Click

        Dim captureType As CaptureAreaType = CaptureAreaType.catMouse

        If cmbCapturingType.SelectedIndex = 1 Then
            captureType = CaptureAreaType.catScreen
        End If

        StartRecording(captureType)

    End Sub

    Private Sub btnPauseResume_Click(sender As System.Object, e As System.EventArgs) Handles btnPauseResume.Click

        PauseOrResumeRecording()

    End Sub

    Private Sub btnStop_Click(sender As Object, e As EventArgs) Handles btnStop.Click

        StopRecording()

    End Sub

    Private Sub StartRecording(ByVal captureType As CaptureAreaType)

        btnStart.Enabled = False
        btnPauseResume.Enabled = True
        btnStop.Enabled = True

        _capturingThreadData.CaptureType = captureType

        ' Start thread
        _capturingThread = New Thread(AddressOf CapturingThread.ThreadProc)
        _capturingThread.Start(_capturingThreadData)

        ' Signal to start the recording
        _capturingThreadData.StartOrResumeEvent.Set()
        
    End Sub

    Private Sub PauseOrResumeRecording()

        btnStart.Enabled = False
        btnPauseResume.Enabled = True
        btnStop.Enabled = True

        If btnPauseResume.Text = "Pause" Then
            ' Signal to pause
            _capturingThreadData.PauseEvent.Set()
            btnPauseResume.Text = "Resume"

        Else
            ' Signal to resume
            _capturingThreadData.StartOrResumeEvent.Set()
            btnPauseResume.Text = "Pause"
        End If

    End Sub

    Private Sub StopRecording()

        Cursor = Cursors.WaitCursor

        ' Signal to stop
        _capturingThreadData.StopEvent.Set()

        Try
            _capturingThread.Join()
        Finally
            Cursor = Cursors.Default
        End Try

        If Not _capturingThreadData.Success Then
            MessageBox.Show("Capturing failed. Error: " & _capturingThreadData.ErrorText)
        Else
            Dim dlg As New SaveFileDialog()
            dlg.DefaultExt = "*.wmv"
            dlg.Filter = "WMV files (*.wmv)|*.wmv|All files (*.*)|*.*"

            dlg.FileName = "Screencast"
            dlg.Title = "Save captured video as"

            If dlg.ShowDialog() = DialogResult.OK Then
                File.Copy(_capturingThreadData.TempFile, dlg.FileName, True)
                ' start the video in default associated application
                Process.Start(dlg.FileName)
            End If

            File.Delete(_capturingThreadData.TempFile)
        End If

        btnStart.Enabled = True
        btnPauseResume.Enabled = False
        btnStop.Enabled = False
        btnPauseResume.Text = "Pause"

    End Sub

    Private Sub Form1_FormClosing(sender As System.Object, e As System.Windows.Forms.FormClosingEventArgs) Handles MyBase.FormClosing

        _capturingThreadData.StopEvent.Set()

    End Sub
End Class

Program.vb
Imports System.Collections.Generic
Imports System.Windows.Forms

NotInheritable Class Program
	Private Sub New()
	End Sub
	''' <summary>
	''' The main entry point for the application.
	''' </summary>
	<STAThread> _
	Friend Shared Sub Main()
		Application.EnableVisualStyles()
		Application.SetCompatibleTextRenderingDefault(False)
		Application.Run(New Form1())
	End Sub
End Class

Resources.Designer.vb
��'------------------------------------------------------------------------------

' <auto-generated>

'     This code was generated by a tool.

'     Runtime Version:2.0.50727.5448

'

'     Changes to this file may cause incorrect behavior and will be lost if

'     the code is regenerated.

' </auto-generated>

'------------------------------------------------------------------------------



Namespace Properties





	''' <summary>

	'''   A strongly-typed resource class, for looking up localized strings, etc.

	''' </summary>

	' This class was auto-generated by the StronglyTypedResourceBuilder

	' class via a tool like ResGen or Visual Studio.

	' To add or remove a member, edit your .ResX file then rerun ResGen

	' with the /str option, or rebuild your VS project.

	<System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "2.0.0.0")> _

	<System.Diagnostics.DebuggerNonUserCodeAttribute> _

	<System.Runtime.CompilerServices.CompilerGeneratedAttribute> _

	Friend Class Resources



		Private Shared resourceMan As Global.System.Resources.ResourceManager



		Private Shared resourceCulture As Global.System.Globalization.CultureInfo



		<System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")> _

		Friend Sub New()

		End Sub



		''' <summary>

		'''   Returns the cached ResourceManager instance used by this class.

		''' </summary>

		<System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _

		Friend Shared ReadOnly Property ResourceManager() As Global.System.Resources.ResourceManager

			Get

				If Object.ReferenceEquals(resourceMan, Nothing) Then

					Dim temp As New Global.System.Resources.ResourceManager("CaptureFromSeparateThread.Properties.Resources", GetType(Resources).Assembly)

					resourceMan = temp

				End If

				Return resourceMan

			End Get

		End Property



		''' <summary>

		'''   Overrides the current thread's CurrentUICulture property for all

		'''   resource lookups using this strongly typed resource class.

		''' </summary>

		<System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _

		Friend Shared Property Culture() As Global.System.Globalization.CultureInfo

			Get

				Return resourceCulture

			End Get

			Set

				resourceCulture = value

			End Set

		End Property

	End Class

End Namespace


Settings.Designer.vb
��'------------------------------------------------------------------------------

' <auto-generated>

'     This code was generated by a tool.

'     Runtime Version:2.0.50727.5448

'

'     Changes to this file may cause incorrect behavior and will be lost if

'     the code is regenerated.

' </auto-generated>

'------------------------------------------------------------------------------



Namespace Properties





	<System.Runtime.CompilerServices.CompilerGeneratedAttribute> _

	<System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "8.0.0.0")> _

	Friend NotInheritable Partial Class Settings

		Inherits Global.System.Configuration.ApplicationSettingsBase



		Private Shared defaultInstance As Settings = DirectCast(Global.System.Configuration.ApplicationSettingsBase.Synchronized(New Settings()), Settings)



		Public Shared ReadOnly Property [Default]() As Settings

			Get

				Return defaultInstance

			End Get

		End Property

	End Class

End Namespace


Download Source Code (.zip)

Return to the previous page Explore Screen Capturing SDK