NAudio Microphone Recording, Live Camera Feed & Memory Management...Will Be Implementing Video & Audio Recording simultaneously. For anyone's Use.

Rythorian

RYTHORIAN
Joined
Nov 5, 2024
Messages
49
Programming Experience
5-10
VB.NET:
Imports System.ComponentModel
Imports System.IO
Imports System.Runtime.InteropServices
Imports AForge.Video
Imports AForge.Video.DirectShow
Imports NAudio.Wave

' Main class that handles memory operations, process management, and more.
Public Class Memory

#Region "Constants"
    ' Constants for process access rights, used with OpenProcess
    Private Const PROCESS_VM_READ As Integer = &H10
    Private Const PROCESS_VM_WRITE As Integer = &H20
    Private Const PROCESS_VM_OPERATION As Integer = &H8
    Private Const PROCESS_QUERY_INFORMATION As Integer = &H400 ' Needed for enumerating modules
    Private Const PROCESS_ACCESS_REQUIRED As Integer = PROCESS_VM_READ Or PROCESS_VM_WRITE Or PROCESS_VM_OPERATION Or PROCESS_QUERY_INFORMATION
    ' Constants for start and end indices
    Private Shared ReadOnly startIndex As Integer
    Private Shared ReadOnly endIndex As Integer
#End Region

#Region "Structures"
    ''' <summary>
    ''' Represents a 4x4 Matrix of Single-precision floating-point numbers.
    ''' Ensures sequential layout in memory for interop.
    ''' Original name W2SMatrix kept.
    ''' </summary>
    <StructLayout(LayoutKind.Sequential)>
    Public Structure W2SMatrix ' Kept original name
        Public M11, M12, M13, M14 As Single ' Renamed fields for clarity (M = Matrix, Row, Col)
        Public M21, M22, M23, M24 As Single
        Public M31, M32, M33, M34 As Single
        Public M41, M42, M43, M44 As Single

        ' Optional: Add methods for matrix operations if needed
        ' Example: Public Shared Function Identity() As W2SMatrix
    End Structure

    ''' <summary>
    ''' Represents a 2D Vector of Single-precision floating-point numbers.
    ''' Ensures sequential layout in memory for interop.
    ''' Original name FVec2 kept.
    ''' </summary>
    <StructLayout(LayoutKind.Sequential)>
    Public Structure FVec2 ' Kept original name
        Public X As Single
        Public Y As Single
    End Structure

    ''' <summary>
    ''' Represents a 3D Vector of Single-precision floating-point numbers.
    ''' Ensures sequential layout in memory for interop.
    ''' Original name FVec3 kept.
    ''' </summary>
    <StructLayout(LayoutKind.Sequential)>
    Public Structure FVec3 ' Kept original name
        Public X As Single
        Public Y As Single
        Public Z As Single
    End Structure
#End Region

#Region "Windows API Declarations (P/Invoke)"
    ''' <summary>
    ''' Opens an existing local process object.
    ''' </summary>
    <DllImport("kernel32.dll", SetLastError:=True)>
    Private Shared Function OpenProcess(ByVal dwDesiredAccess As Integer, <MarshalAs(UnmanagedType.Bool)> ByVal bInheritHandle As Boolean, ByVal dwProcessId As Integer) As IntPtr
    End Function

    ''' <summary>
    ''' Closes an open object handle.
    ''' </summary>
    <DllImport("kernel32.dll", SetLastError:=True)>
    Private Shared Function CloseHandle(ByVal hObject As IntPtr) As Boolean
    End Function

    ''' <summary>
    ''' Reads data from an area of memory in a specified process.
    ''' </summary>
    <DllImport("kernel32.dll", SetLastError:=True)>
    Private Shared Function ReadProcessMemory(
        ByVal hProcess As IntPtr,
        ByVal lpBaseAddress As IntPtr,
        <Out()> ByVal lpBuffer As IntPtr, ' Use IntPtr for buffer flexibility
        ByVal nSize As IntPtr, ' Size as IntPtr for 64-bit compatibility
        ByRef lpNumberOfBytesRead As IntPtr ' Bytes read as IntPtr
    ) As Boolean
    End Function

    ''' <summary>
    ''' Writes data to an area of memory in a specified process.
    ''' </summary>
    <DllImport("kernel32.dll", SetLastError:=True)>
    Private Shared Function WriteProcessMemory(
        ByVal hProcess As IntPtr,
        ByVal lpBaseAddress As IntPtr,
        ByVal lpBuffer As IntPtr, ' Use IntPtr for buffer flexibility
        ByVal nSize As IntPtr, ' Size as IntPtr for 64-bit compatibility
        ByRef lpNumberOfBytesWritten As IntPtr ' Bytes written as IntPtr
    ) As Boolean
    End Function
#End Region

#Region "Process Handling"
    ''' <summary>
    ''' Finds a process by its name (without the .exe extension).
    ''' </summary>
    ''' <param name="processName">The name of the process.</param>
    ''' <returns>The first Process object found, or Nothing if not found.</returns>
    Public Shared Function GetProcessByName(ByVal processName As String) As Process
        If String.IsNullOrWhiteSpace(processName) Then
            Throw New ArgumentNullException(NameOf(processName), "Process name cannot be null or empty.")
        End If
        Dim processes As Process() = Process.GetProcessesByName(processName)
        Return processes.FirstOrDefault()
    End Function

    ''' <summary>
    ''' Opens a process with required access rights.
    ''' </summary>
    ''' <param name="process">The Process object to open.</param>
    ''' <returns>An IntPtr handle to the process.</returns>
    ''' <exception cref="ArgumentNullException">Thrown if the process is null.</exception>
    ''' <exception cref="Win32Exception">Thrown if OpenProcess fails.</exception>
    Public Shared Function GetHandle(ByVal process As Process) As IntPtr
        If process Is Nothing Then
            Throw New ArgumentNullException(NameOf(process), "Process object cannot be null.")
        End If

        Dim handle As IntPtr = OpenProcess(PROCESS_ACCESS_REQUIRED, False, process.Id)
        If handle = IntPtr.Zero Then
            Throw New Win32Exception(Marshal.GetLastWin32Error(), $"Failed to open process '{process.ProcessName}' (ID: {process.Id}). Check permissions.")
        End If
        Return handle
    End Function

    ''' <summary>
    ''' Closes the handle to a process. It's crucial to call this when done.
    ''' </summary>
    ''' <param name="processHandle">The process handle obtained from GetHandle.</param>
    ''' <returns>True if the handle was closed successfully or was already zero, False otherwise.</returns>
    Public Shared Function CloseProcessHandle(ByVal processHandle As IntPtr) As Boolean
        If processHandle <> IntPtr.Zero Then
            Return CloseHandle(processHandle)
        End If
        Return True
    End Function

    ''' <summary>
    ''' Gets the base address of a specific module within a process.
    ''' </summary>
    ''' <param name="process">The target process.</param>
    ''' <param name="moduleName">The name of the module (e.g., "client.dll"). Case-insensitive.</param>
    ''' <returns>The base address of the module as IntPtr, or IntPtr.Zero if not found or an error occurs.</returns>
    Public Shared Function GetModuleBase(ByVal process As Process, ByVal moduleName As String) As IntPtr
        If process Is Nothing Then Return IntPtr.Zero
        If String.IsNullOrWhiteSpace(moduleName) Then Return IntPtr.Zero

        Try
            process.Refresh()
            Dim targetModule As ProcessModule = process.Modules.Cast(Of ProcessModule)().
                                                FirstOrDefault(Function(m) String.Equals(m.ModuleName, moduleName, StringComparison.OrdinalIgnoreCase))

            Return If(targetModule IsNot Nothing, targetModule.BaseAddress, IntPtr.Zero)

        Catch ex As Exception
            Console.WriteLine($"Error getting module base for '{moduleName}' in process '{process.ProcessName}': {ex.Message}")
            Return IntPtr.Zero
        End Try
    End Function

    ''' <summary>
    ''' Calculates a final memory address by resolving a pointer chain.
    ''' </summary>
    ''' <param name="processHandle">Handle to the target process.</param>
    ''' <param name="baseAddress">The starting base address.</param>
    ''' <param name="offsets">An array of offsets to follow.</param>
    ''' <returns>The final calculated address.</returns>
    Public Shared Function ResolvePointerChain(ByVal processHandle As IntPtr, ByVal baseAddress As IntPtr, ByVal offsets As Integer()) As IntPtr
        Dim currentAddress As IntPtr = baseAddress
        Try
            For Each offset As Integer In offsets
                currentAddress = ReadIntPtr(processHandle, currentAddress)
                If currentAddress = IntPtr.Zero Then
                    Console.WriteLine("Error resolving pointer chain: Read null pointer.")
                    Return IntPtr.Zero
                End If
                currentAddress = IntPtr.Add(currentAddress, offset)
            Next
            Return currentAddress
        Catch ex As Exception
            Console.WriteLine($"Error resolving pointer chain: {ex.Message}")
            Return IntPtr.Zero
        End Try
    End Function
#End Region

#Region "Memory Reading Methods (Generic and Specific)"
    ''' <summary>
    ''' Generic method to read a structure of type T from memory.
    ''' </summary>
    ''' <typeparam name="T">The type of the value/structure to read.</typeparam>
    ''' <param name="processHandle">Handle to the target process.</param>
    ''' <param name="address">The memory address to read from.</param>
    ''' <returns>The value/structure read from memory.</returns>
    Public Shared Function ReadStructure(Of T As Structure)(ByVal processHandle As IntPtr, ByVal address As IntPtr) As T
        Dim structSize As Integer = Marshal.SizeOf(GetType(T))
        If structSize <= 0 Then Throw New ArgumentException("Structure size must be greater than zero.")

        Dim bufferPtr As IntPtr = Marshal.AllocHGlobal(structSize) ' Allocate unmanaged memory
        Dim bytesRead As IntPtr = IntPtr.Zero

        Try
            If Not ReadProcessMemory(processHandle, address, bufferPtr, CType(structSize, IntPtr), bytesRead) Then
                Dim errorCode As Integer = Marshal.GetLastWin32Error()
                Throw New Win32Exception(errorCode, $"ReadProcessMemory failed at address {address.ToString("X")}. Error Code: {errorCode}")
            End If

            If bytesRead.ToInt64() <> structSize Then
                Throw New Exception($"ReadProcessMemory read {bytesRead.ToInt64()} bytes, but expected {structSize} bytes for type {GetType(T).Name} at address {address.ToString("X")}.")
            End If

            ' Convert the data from unmanaged memory to the managed structure
            Return Marshal.PtrToStructure(Of T)(bufferPtr)

        Finally
            Marshal.FreeHGlobal(bufferPtr) ' Always free allocated unmanaged memory
        End Try
    End Function

    ' Specific methods for reading different types
    Public Shared Function RPMInt(ByVal hProcess As IntPtr, ByVal address As IntPtr) As Integer
        Return ReadStructure(Of Integer)(hProcess, address)
    End Function

    Public Shared Function RPMFloat(ByVal hProcess As IntPtr, ByVal address As IntPtr) As Single
        Return ReadStructure(Of Single)(hProcess, address)
    End Function

    Public Shared Function RPMBool(ByVal hProcess As IntPtr, ByVal address As IntPtr) As Boolean
        Dim byteValue As Byte = ReadStructure(Of Byte)(hProcess, address)
        Return Convert.ToBoolean(byteValue)
    End Function

    Public Shared Function ReadIntPtr(ByVal hProcess As IntPtr, ByVal address As IntPtr) As IntPtr
        Return ReadStructure(Of IntPtr)(hProcess, address)
    End Function

    Public Shared Function RPMViewMatrix(ByVal hProcess As IntPtr, ByVal address As IntPtr) As W2SMatrix
        Return ReadStructure(Of W2SMatrix)(hProcess, address)
    End Function

    Public Shared Function RPMFVec2(ByVal hProcess As IntPtr, ByVal address As IntPtr) As FVec2
        Return ReadStructure(Of FVec2)(hProcess, address)
    End Function

    Public Shared Function RPMFVec3(ByVal hProcess As IntPtr, ByVal address As IntPtr) As FVec3
        Return ReadStructure(Of FVec3)(hProcess, address)
    End Function

    ''' <summary>
    ''' Reads a specified number of bytes from memory into a byte array.
    ''' </summary>
    ''' <param name="processHandle">Handle to the target process.</param>
    ''' <param name="address">The memory address to read from.</param>
    ''' <param name="count">The number of bytes to read.</param>
    ''' <returns>A byte array containing the data read.</returns>
    Public Shared Function ReadBytes(ByVal processHandle As IntPtr, ByVal address As IntPtr, ByVal count As Integer) As Byte()
        If count <= 0 Then Throw New ArgumentOutOfRangeException(NameOf(count), "Number of bytes to read must be positive.")

        Dim buffer(count - 1) As Byte
        Dim bufferHandle As GCHandle = GCHandle.Alloc(buffer, GCHandleType.Pinned) ' Pin the managed buffer
        Dim bytesRead As IntPtr = IntPtr.Zero

        Try
            Dim bufferPtr As IntPtr = bufferHandle.AddrOfPinnedObject()
            If Not ReadProcessMemory(processHandle, address, bufferPtr, CType(count, IntPtr), bytesRead) Then
                Dim errorCode As Integer = Marshal.GetLastWin32Error()
                Throw New Win32Exception(errorCode, $"Failed to read {count} bytes at address {address.ToString("X")}. Error Code: {errorCode}")
            End If

            If bytesRead.ToInt64() <> count Then
                Throw New Exception($"ReadProcessMemory read {bytesRead.ToInt64()} bytes, but expected {count} bytes at address {address.ToString("X")}.")
            End If

            Return buffer
        Finally
            If bufferHandle.IsAllocated Then
                bufferHandle.Free() ' Unpin the buffer
            End If
        End Try
    End Function
#End Region

#Region "Memory Writing Methods (Generic and Specific)"
    ''' <summary>
    ''' Generic method to write a structure of type T to memory.
    ''' </summary>
    ''' <typeparam name="T">The type of the value/structure to write.</typeparam>
    ''' <param name="processHandle">Handle to the target process.</param>
    ''' <param name="address">The memory address to write to.</param>
    ''' <param name="value">The value/structure to write.</param>
    ''' <returns>True if the write operation was successful, False otherwise.</returns>
    Public Shared Function WriteStructure(Of T As Structure)(ByVal processHandle As IntPtr, ByVal address As IntPtr, ByVal value As T) As Boolean
        Dim structSize As Integer = Marshal.SizeOf(GetType(T))
        If structSize <= 0 Then Throw New ArgumentException("Structure size must be greater than zero.")

        Dim bufferPtr As IntPtr = Marshal.AllocHGlobal(structSize) ' Allocate unmanaged memory
        Dim bytesWritten As IntPtr = IntPtr.Zero

        Try
            Marshal.StructureToPtr(value, bufferPtr, False) ' Copy structure to unmanaged memory

            If Not WriteProcessMemory(processHandle, address, bufferPtr, CType(structSize, IntPtr), bytesWritten) Then
                Dim errorCode As Integer = Marshal.GetLastWin32Error()
                Console.WriteLine($"WriteProcessMemory failed at address {address:X} with error code {errorCode}")
                Return False
            End If

            Return bytesWritten.ToInt64() = structSize

        Catch ex As Exception
            Console.WriteLine($"Error writing structure {GetType(T).Name} at {address:X}: {ex.Message}")
            Return False
        Finally
            Marshal.FreeHGlobal(bufferPtr) ' Always free allocated unmanaged memory
        End Try
    End Function

    ' Specific methods for writing different types
    Public Shared Function WPMInt(ByVal hProcess As IntPtr, ByVal address As IntPtr, ByVal value As Integer) As Boolean
        Return WriteStructure(Of Integer)(hProcess, address, value)
    End Function

    Public Shared Function WPMFloat(ByVal hProcess As IntPtr, ByVal address As IntPtr, ByVal value As Single) As Boolean
        Return WriteStructure(Of Single)(hProcess, address, value)
    End Function

    Public Shared Function WPMBool(ByVal hProcess As IntPtr, ByVal address As IntPtr, ByVal value As Boolean) As Boolean
        Dim byteValue As Byte = Convert.ToByte(value)
        Return WriteStructure(Of Byte)(hProcess, address, byteValue)
    End Function

    Public Shared Function WriteIntPtr(ByVal hProcess As IntPtr, ByVal address As IntPtr, ByVal value As IntPtr) As Boolean
        Return WriteStructure(Of IntPtr)(hProcess, address, value)
    End Function

    ' Methods for writing more complex structures can be added similarly
    ' Public Shared Function WPMViewMatrix(ByVal hProcess As IntPtr, ByVal address As IntPtr, ByVal value As W2SMatrix) As Boolean
    '     Return WriteStructure(Of W2SMatrix)(hProcess, address, value)
    ' End Function

    ' Public Shared Function WPMFVec2(ByVal hProcess As IntPtr, ByVal address As IntPtr, ByVal value As FVec2) As Boolean
    '     Return WriteStructure(Of FVec2)(hProcess, address, value)
    ' End Function

    ' Public Shared Function WPMFVec3(ByVal hProcess As IntPtr, ByVal address As IntPtr, ByVal value As FVec3) As Boolean
    '     Return WriteStructure(Of FVec3)(hProcess, address, value)
    ' End Function

    ''' <summary>
    ''' Writes an array of bytes to memory.
    ''' </summary>
    ''' <param name="processHandle">Handle to the target process.</param>
    ''' <param name="address">The memory address to write to.</param>
    ''' <param name="data">The byte array containing data to write.</param>
    ''' <returns>True if the write operation was successful, False otherwise.</returns>
    Public Shared Function WriteBytes(ByVal processHandle As IntPtr, ByVal address As IntPtr, ByVal data As Byte()) As Boolean
        If data Is Nothing OrElse data.Length = 0 Then
            Console.WriteLine("WriteBytes called with null or empty data array.")
            Return False
        End If

        Dim bufferHandle As GCHandle = GCHandle.Alloc(data, GCHandleType.Pinned) ' Pin the managed buffer
        Dim bytesWritten As IntPtr = IntPtr.Zero
        Dim dataSize As Integer = data.Length

        Try
            Dim bufferPtr As IntPtr = bufferHandle.AddrOfPinnedObject()
            If Not WriteProcessMemory(processHandle, address, bufferPtr, CType(dataSize, IntPtr), bytesWritten) Then
                Dim errorCode As Integer = Marshal.GetLastWin32Error()
                Console.WriteLine($"WriteProcessMemory failed writing {dataSize} bytes at address {address:X} with error code {errorCode}")
                Return False
            End If

            Return bytesWritten.ToInt64() = dataSize

        Catch ex As Exception
            Console.WriteLine($"Error writing {data.Length} bytes at {address:X}: {ex.Message}")
            Return False
        Finally
            If bufferHandle.IsAllocated Then
                bufferHandle.Free() ' Unpin the buffer
            End If
        End Try
    End Function
#End Region

#Region "Offset Parsing"
    ''' <summary>
    ''' Parses an offset value from a specific string format.
    ''' </summary>
    ''' <param name="rawData">The string containing the offset definitions.</param>
    ''' <param name="offsetName">The name of the offset to find.</param>
    ''' <returns>The parsed offset as an Integer, or 0 if not found or parsing fails.</returns>
    Public Shared Function GetOffsetByName(ByVal rawData As String, ByVal offsetName As String) As Integer
        If String.IsNullOrWhiteSpace(rawData) OrElse String.IsNullOrWhiteSpace(offsetName) Then Return 0

        Try
            Dim searchPattern As String = offsetName.Trim() & " = 0x"
            Dim startIndex As Integer = rawData.IndexOf(searchPattern, StringComparison.OrdinalIgnoreCase)

            If startIndex = -1 Then
                Console.WriteLine($"Offset pattern '{searchPattern}' not found in provided data.")
                Return 0
            End If

            startIndex += searchPattern.Length
            Dim endIndex As Integer = -1
            Dim possibleEndChars() As Char = {";"c, " "c, vbCr, vbLf}
            For i As Integer = startIndex To rawData.Length - 1
                If Array.IndexOf(possibleEndChars, rawData(i)) <> -1 Then
                    endIndex = i
                    Exit For
                End If
            Next

            If endIndex = -1 Then endIndex = Math.Min(startIndex + 10, rawData.Length)

            If endIndex <= startIndex Then
                Console.WriteLine($"Could not determine end index for offset '{offsetName}'.")
                Return 0
            End If

            Dim hexValue As String = rawData.Substring(startIndex, endIndex - startIndex).Trim()

            Return Convert.ToInt32(hexValue, 16)

        Catch formatEx As FormatException
            Console.WriteLine($"Error parsing hex value for offset '{offsetName}'. Found string: '{rawData.Substring(startIndex, endIndex - startIndex)}'. Error: {formatEx.Message}")
            Return 0
        Catch ex As Exception
            Console.WriteLine($"Generic error parsing offset '{offsetName}': {ex.Message}")
            Return 0
        End Try
    End Function
#End Region

End Class

' Form class that handles UI components and operations for recording video and audio.
Public Class Form1

    ' Variables for video and audio capture
    Private videoSource As VideoCaptureDevice
    Private waveIn As WaveInEvent
    Private writer As WaveFileWriter
    Private isRecording As Boolean = False
    Private Const targetFrameRate As Integer = 30
    Private audioFilePath As String
    Private videoDevices As FilterInfoCollection

    ' Variables for process management
    ' Target process and its handle
    Private targetProcess As Process
    Private targetProcessHandle As IntPtr = IntPtr.Zero

    ' Nested Memory class (consider combining with the top-level Memory class)
    Public Class Memory
        ' DllImport declarations for process management functions
        <Runtime.InteropServices.DllImport("kernel32.dll", SetLastError:=True, ExactSpelling:=True)>
        Public Shared Function OpenProcess(dwDesiredAccess As Integer, bInheritHandle As Boolean, dwProcessId As Integer) As IntPtr
        End Function

        <Runtime.InteropServices.DllImport("kernel32.dll", SetLastError:=True, ExactSpelling:=True)>
        Public Shared Function CloseHandle(hObject As IntPtr) As Boolean
        End Function

        ' DllImport declarations for memory read/write functions
        <Runtime.InteropServices.DllImport("kernel32.dll", SetLastError:=True)>
        Public Shared Function ReadProcessMemory(hProcess As IntPtr, lpBaseAddress As IntPtr, lpBuffer As IntPtr, nSize As Integer, ByRef lpNumberOfBytesRead As Integer) As Boolean
        End Function

        <Runtime.InteropServices.DllImport("kernel32.dll", SetLastError:=True)>
        Public Shared Function WriteProcessMemory(hProcess As IntPtr, lpBaseAddress As IntPtr, lpBuffer As IntPtr, nSize As Integer, ByRef lpNumberOfBytesWritten As Integer) As Boolean
        End Function

        ' Constants for process access rights
        Public Const PROCESS_VM_READ As Integer = &H10
        Public Const PROCESS_VM_WRITE As Integer = &H20
        Public Const PROCESS_VM_OPERATION As Integer = &H8
        Public Const PROCESS_ALL_ACCESS As Integer = &H1F0FFF

        ''' <summary>
        ''' Finds a process by its name.
        ''' </summary>
        ''' <param name="processName">The name of the process.</param>
        ''' <returns>The first Process object found, or Nothing if not found.</returns>
        Public Shared Function GetProcessByName(processName As String) As Process
            Try
                Return Process.GetProcessesByName(processName)(0)
            Catch ex As IndexOutOfRangeException
                Return Nothing
            End Try
        End Function

        ''' <summary>
        ''' Opens a process with all access rights.
        ''' </summary>
        ''' <param name="process">The Process object to open.</param>
        ''' <returns>An IntPtr handle to the process.</returns>
        Public Shared Function GetHandle(process As Process) As IntPtr
            Return OpenProcess(PROCESS_ALL_ACCESS, False, process.Id)
        End Function

        ''' <summary>
        ''' Reads an Integer from memory.
        ''' </summary>
        ''' <param name="handle">Handle to the target process.</param>
        ''' <param name="address">The memory address to read from.</param>
        ''' <returns>The Integer read from memory.</returns>
        Public Shared Function RPMInt(handle As IntPtr, address As Integer) As Integer
            Dim buffer As Integer = 0
            Dim bytesRead As Integer = 0
            Dim bufferPtr As IntPtr = Runtime.InteropServices.Marshal.AllocHGlobal(Runtime.InteropServices.Marshal.SizeOf(buffer))

            Try
                If ReadProcessMemory(handle, New IntPtr(address), bufferPtr, Runtime.InteropServices.Marshal.SizeOf(buffer), bytesRead) Then
                    If bytesRead = Runtime.InteropServices.Marshal.SizeOf(buffer) Then
                        buffer = Runtime.InteropServices.Marshal.ReadInt32(bufferPtr)
                        Return buffer
                    Else
                        Return -1 ' Partial read error
                    End If
                Else
                    Return -2 ' ReadProcessMemory failed
                End If
            Finally
                Runtime.InteropServices.Marshal.FreeHGlobal(bufferPtr) ' Always free allocated unmanaged memory
            End Try
        End Function

        ''' <summary>
        ''' Writes an Integer to memory.
        ''' </summary>
        ''' <param name="handle">Handle to the target process.</param>
        ''' <param name="address">The memory address to write to.</param>
        ''' <param name="value">The Integer value to write.</param>
        ''' <returns>True if the write operation was successful, False otherwise.</returns>
        Public Shared Function WPMInt(handle As IntPtr, address As Integer, value As Integer) As Boolean
            Dim bufferPtr As IntPtr = Runtime.InteropServices.Marshal.AllocHGlobal(Runtime.InteropServices.Marshal.SizeOf(value))
            Dim bytesWritten As Integer = 0
            Runtime.InteropServices.Marshal.WriteInt32(bufferPtr, value)

            Try
                Return WriteProcessMemory(handle, New IntPtr(address), bufferPtr, Runtime.InteropServices.Marshal.SizeOf(value), bytesWritten)
            Finally
                Runtime.InteropServices.Marshal.FreeHGlobal(bufferPtr) ' Always free allocated unmanaged memory
            End Try
        End Function
    End Class

    ''' <summary>
    ''' Initializes the form and sets up video and audio components.
    ''' </summary>
    <Obsolete>
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Try
            ' Set the audio file path to the desktop
            audioFilePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "audio.wav")
            ' Initialize video device selector
            InitializeCameraSelector()
            ' Disable stop button initially
            stopButton.Enabled = False
            ' Initialize audio recorder
            InitializeAudioRecorder()

            ' Find the target process by name
            targetProcess = Memory.GetProcessByName("exampleProcessName")
            If targetProcess IsNot Nothing Then
                ' Get handle to the target process
                targetProcessHandle = Memory.GetHandle(targetProcess)
                If targetProcessHandle = IntPtr.Zero Then
                    Debug.WriteLine("Failed to get process handle.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
                End If
            Else
                Debug.WriteLine("Target process not found.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
            End If

        Catch ex As Exception
            Debug.WriteLine($"Error on form load: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
        End Try
    End Sub

    ''' <summary>
    ''' Populates the camera selector with available video capture devices.
    ''' </summary>
    Private Sub InitializeCameraSelector()
        Try
            videoDevices = New FilterInfoCollection(FilterCategory.VideoInputDevice)
            If videoDevices.Count > 0 Then
                For Each device As FilterInfo In videoDevices
                    cameraSelector.Items.Add(device.Name)
                Next
                cameraSelector.SelectedIndex = 0
            Else
                Debug.WriteLine("No video capture devices found.")
                startButton.Enabled = False
            End If
        Catch ex As Exception
            Debug.WriteLine($"Error listing video capture devices: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
        End Try
    End Sub

    ''' <summary>
    ''' Initializes the audio recorder.
    ''' </summary>
    <Obsolete>
    Private Sub InitializeAudioRecorder()
        Try
            ' Set up audio format and event handlers
            waveIn = New WaveInEvent With {
                .WaveFormat = New WaveFormat(44100, 1)
            }
            AddHandler waveIn.DataAvailable, AddressOf OnAudioDataAvailable
            AddHandler waveIn.RecordingStopped, AddressOf OnRecordingStopped
        Catch ex As Exception
            Debug.WriteLine($"Error initializing audio recorder: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
        End Try
    End Sub

    ''' <summary>
    ''' Starts video and audio recording.
    ''' </summary>
    Private Sub StartButton_Click(sender As Object, e As EventArgs) Handles startButton.Click
        If cameraSelector.SelectedItem IsNot Nothing Then
            Try
                StartVideoRecording()
                StartAudioRecording()
            Catch ex As Exception
                Debug.WriteLine($"Error starting recording: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
                CleanUpResources()
            End Try
        Else
            Debug.WriteLine("No camera selected.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
        End If
    End Sub

    ''' <summary>
    ''' Starts video recording using the selected video capture device.
    ''' </summary>
    Private Sub StartVideoRecording()
        Try
            ' Get selected video capture device
            Dim selectedDevice As FilterInfo = videoDevices(cameraSelector.SelectedIndex)
            videoSource = New VideoCaptureDevice(selectedDevice.MonikerString)

            ' Set video frame size (optional)
            Dim frameWidth As Integer = 640
            Dim frameHeight As Integer = 480
            If videoSource.VideoCapabilities.Length > 0 Then
                Dim cap As VideoCapabilities = videoSource.VideoCapabilities(0)
                frameWidth = cap.FrameSize.Width
                frameHeight = cap.FrameSize.Height
            End If

            ' Add event handler for new frames and start recording
            AddHandler videoSource.NewFrame, AddressOf VideoSource_NewFrame
            isRecording = True
            startButton.Enabled = False
            stopButton.Enabled = True
            videoSource.Start()
        Catch ex As Exception
            Debug.WriteLine("Could not start video recording.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning)
        End Try
    End Sub

    ''' <summary>
    ''' Starts audio recording.
    ''' </summary>
    Private Sub StartAudioRecording()
        Try
            If writer Is Nothing Then
                ' Initialize WaveFileWriter if not already done
                writer = New WaveFileWriter(audioFilePath, waveIn.WaveFormat)
            End If
            waveIn.StartRecording()
            Debug.WriteLine("Audio recording started.", "Info", MessageBoxButtons.OK, MessageBoxIcon.Information)
        Catch ex As Exception
            Debug.WriteLine($"Error starting audio recording: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
        End Try
    End Sub

    ''' <summary>
    ''' Stops video and audio recording.
    ''' </summary>
    Private Sub StopButton_Click(sender As Object, e As EventArgs) Handles stopButton.Click
        Try
            StopVideoRecording()
            StopAudioRecording()
        Catch ex As Exception
            Debug.WriteLine($"Error stopping recording: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
        End Try
    End Sub

    ''' <summary>
    ''' Stops audio recording.
    ''' </summary>
    Private Sub StopAudioRecording()
        Try
            waveIn.StopRecording()
        Catch ex As Exception
            Debug.WriteLine($"Error stopping audio recording: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
        End Try
    End Sub

    ''' <summary>
    ''' Stops video recording.
    ''' </summary>
    Private Sub StopVideoRecording()
        If videoSource IsNot Nothing AndAlso videoSource.IsRunning Then
            videoSource.SignalToStop()
            videoSource.WaitForStop()
            RemoveHandler videoSource.NewFrame, AddressOf VideoSource_NewFrame
            Try
                ' videoSource.Release() ' Assuming 'Release' is the correct method
            Catch ex As Exception
                Debug.WriteLine($"Error releasing video source: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
            End Try
            videoSource = Nothing
        End If
    End Sub

    ''' <summary>
    ''' Handles audio data available event.
    ''' </summary>
    <Obsolete>
    Private Sub OnAudioDataAvailable(sender As Object, e As WaveInEventArgs)
        Try
            ' Write audio data to file
            writer?.WriteData(e.Buffer, 0, e.BytesRecorded)
        Catch ex As Exception
            Debug.WriteLine($"Error writing audio data: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
        End Try
    End Sub

    ''' <summary>
    ''' Handles recording stopped event.
    ''' </summary>
    Private Sub OnRecordingStopped(sender As Object, e As StoppedEventArgs)
        Try
            If writer IsNot Nothing Then
                writer.Dispose()
                writer = Nothing
            End If
            If e.Exception IsNot Nothing Then
                Debug.WriteLine($"Error during recording: {e.Exception.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
            End If
        Catch ex As Exception
            Debug.WriteLine($"Error in OnRecordingStopped: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
        End Try
    End Sub

    ''' <summary>
    ''' Handles new video frame event.
    ''' </summary>
    Private Sub VideoSource_NewFrame(sender As Object, eventArgs As NewFrameEventArgs)
        Try
            ' Clone and dispose of the original frame
            Dim newFrame As Bitmap = DirectCast(eventArgs.Frame.Clone(), Bitmap)
            eventArgs.Frame.Dispose()
            ' Update the video preview with the new frame
            UpdateVideoPreview(newFrame)
        Catch ex As Exception
            Debug.WriteLine($"Error processing new frame: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
        End Try
    End Sub

    ''' <summary>
    ''' Updates the video preview.
    ''' </summary>
    ''' <param name="frame">The new video frame to display.</param>
    Private Sub UpdateVideoPreview(frame As Bitmap)
        Try
            ' Check if invoke is required due to cross-thread operation
            If videoPreview.InvokeRequired Then
                videoPreview.Invoke(New Action(Of Bitmap)(Sub(bmp) UpdateVideoPreview(bmp)), frame)
            Else
                DisposeCurrentImage()
                videoPreview.Image = frame
            End If
        Catch ex As Exception
            Debug.WriteLine($"Error updating video preview: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
        End Try
    End Sub

    ''' <summary>
    ''' Disposes the current image displayed in the video preview.
    ''' </summary>
    Private Sub DisposeCurrentImage()
        If videoPreview.Image IsNot Nothing Then
            videoPreview.Image.Dispose()
        End If
    End Sub

    ''' <summary>
    ''' Cleans up resources when the form is closing.
    ''' </summary>
    Private Sub Form1_FormClosing(sender As Object, e As FormClosingEventArgs) Handles MyBase.FormClosing
        CleanUpResources()
    End Sub

    ''' <summary>
    ''' Releases all resources used by video and audio components.
    ''' </summary>
    Private Sub CleanUpResources()
        Try
            ' Stop and dispose of video source if running
            If videoSource IsNot Nothing Then
                If videoSource.IsRunning Then
                    videoSource.SignalToStop()
                    videoSource.WaitForStop()
                End If
                RemoveHandler videoSource.NewFrame, AddressOf VideoSource_NewFrame
                videoSource = Nothing
            End If

            ' Stop and dispose of audio recorder if running
            If waveIn IsNot Nothing Then
                waveIn.StopRecording()
                waveIn.Dispose()
                waveIn = Nothing
            End If

            ' Dispose of WaveFileWriter if not already disposed
            If writer IsNot Nothing Then
                writer.Dispose()
                writer = Nothing
            End If

            ' Dispose of the current image in video preview
            If videoPreview.Image IsNot Nothing Then
                videoPreview.Image.Dispose()
                videoPreview.Image = Nothing
            End If

            ' Close the process handle if not already closed
            If targetProcessHandle <> IntPtr.Zero Then
                Memory.CloseHandle(targetProcessHandle)
                targetProcessHandle = IntPtr.Zero
            End If

        Catch ex As Exception
            Debug.WriteLine($"Error cleaning up resources: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
        End Try
    End Sub
End Class

' ConceptualWavWriter Class:
Imports System.Drawing.Imaging
Imports System.IO

Public Class ConceptualWavWriter
    Implements IDisposable

    Private writer As BinaryWriter
    Private ReadOnly sampleRate As Integer
    Private ReadOnly channels As Integer
    Private ReadOnly bitsPerSample As Integer
    Private frameCount As Integer = 0

    ' Constructor
    Public Sub New(filePath As String, sampleRate As Integer, channels As Integer, bitsPerSample As Integer)
        Me.sampleRate = sampleRate
        Me.channels = channels
        Me.bitsPerSample = bitsPerSample
        writer = New BinaryWriter(File.Open(filePath, FileMode.Create))
        WriteHeader()
    End Sub

    ' Add audio data
    Public Sub AddAudioData(data As Byte())
        If writer Is Nothing Then
            Throw New InvalidOperationException("Writer is not initialized.")
        End If

        writer.Write(data)
        frameCount += data.Length / (channels * (bitsPerSample / 8))
    End Sub

    ' Close the WAV file and finalize headers
    Public Sub Close()
        If writer IsNot Nothing Then
            UpdateHeader()
            writer.Close()
            writer.Dispose()
            writer = Nothing
        End If
    End Sub

    ' Release resources
    Public Sub Dispose() Implements IDisposable.Dispose
        Close()
    End Sub

    ' Write the initial WAV header
    Private Sub WriteHeader()
        writer.Write(System.Text.Encoding.ASCII.GetBytes("RIFF"))
        writer.Write(CUInt(0)) ' Placeholder for file size
        writer.Write(System.Text.Encoding.ASCII.GetBytes("WAVE"))
        writer.Write(System.Text.Encoding.ASCII.GetBytes("fmt "))
        writer.Write(CUInt(16)) ' Subchunk1Size for PCM
        writer.Write(CUInt(1)) ' AudioFormat (PCM)
        writer.Write(CUInt(channels)) ' Number of channels
        writer.Write(CUInt(sampleRate)) ' Sample rate
        writer.Write(CUInt(sampleRate * channels * (bitsPerSample / 8))) ' Byte rate
        writer.Write(CUInt(channels * (bitsPerSample / 8))) ' Block align
        writer.Write(CUInt(bitsPerSample)) ' Bits per sample
        writer.Write(System.Text.Encoding.ASCII.GetBytes("data"))
        writer.Write(CUInt(0)) ' Placeholder for data chunk size
    End Sub

    ' Update the WAV header with the final file size
    Private Sub UpdateHeader()
        If writer IsNot Nothing Then
            Dim currentPosition As Long = writer.BaseStream.Position
            writer.Seek(4, SeekOrigin.Begin)
            writer.Write(CUInt(currentPosition - 8)) ' File size - 8
            writer.Seek(40, SeekOrigin.Begin)
            writer.Write(CUInt(currentPosition - 44)) ' Data chunk size
            writer.Seek(currentPosition, SeekOrigin.Begin) ' Go back to the end
        End If
    End Sub
End Class
Add:
Friend Class AVIWriter
End Class
 
Last edited by a moderator:
Back
Top