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: