Hope someone can help.
I want to load the Sections of an external ini file into a ComboBox in Visual Basic 2015 and then load the Keys and Values of a selected Section into TextBoxes.
I've been pulling my hair out with this and can't even get a start on how to accomplish this.
Any helping start you can give would be greatly appreciated.
Thanks,
Dan
First create this class(Source - CodeProject Article):
Imports System.Text
Imports System.Runtime.InteropServices
Public Class INI
<DllImport("kernel32")> _
Private Shared Function GetPrivateProfileString(Section As String, Key As String, Value As String, Result As StringBuilder, Size As Integer, FileName As String) As Integer
End Function
<DllImport("kernel32")> _
Private Shared Function GetPrivateProfileString(Section As String, Key As Integer, Value As String, <MarshalAs(UnmanagedType.LPArray)> Result As Byte(), Size As Integer, FileName As String) As Integer
End Function
<DllImport("kernel32")> _
Private Shared Function GetPrivateProfileString(Section As Integer, Key As String, Value As String, <MarshalAs(UnmanagedType.LPArray)> Result As Byte(), Size As Integer, FileName As String) As Integer
End Function
Public path As String
Public Sub New(INIPath As String)
path = INIPath
End Sub
Public Function GetSectionNames() As String()
Dim maxsize As Integer = 500
While True
Dim bytes As Byte() = New Byte(maxsize - 1) {}
Dim size As Integer = GetPrivateProfileString(0, "", "", bytes, maxsize, path)
If size < maxsize - 2 Then
Dim Selected As String = Encoding.ASCII.GetString(bytes, 0, size - (If(size > 0, 1, 0)))
Return Selected.Split(New Char() {ControlChars.NullChar})
End If
maxsize *= 2
End While
End Function
Public Function GetEntryNames(section As String) As String()
Dim maxsize As Integer = 500
While True
Dim bytes As Byte() = New Byte(maxsize - 1) {}
Dim size As Integer = GetPrivateProfileString(section, 0, "", bytes, maxsize, path)
If size < maxsize - 2 Then
Dim entries As String = Encoding.ASCII.GetString(bytes, 0, size - (If(size > 0, 1, 0)))
Return entries.Split(New Char() {ControlChars.NullChar})
End If
maxsize *= 2
End While
End Function
Public Function GetEntryValue(section As String, entry As String) As Object
Dim maxsize As Integer = 250
While True
Dim result As New StringBuilder(maxsize)
Dim size As Integer = GetPrivateProfileString(section, entry, "", result, maxsize, path)
If size < maxsize - 1 Then
Return result.ToString()
End If
maxsize *= 2
End While
End Function
End Class
Add sections to the ComboBox like this:
Dim _ini As New INI("somefile.ini")
ComboBox1.Items.AddRange(ini.GetSectionNames()) 'For all sections
ComboBox1.Items.Add("section1") 'For specific section(s)
Then, in the selection changed event of the ComboBox:
Private Sub ComboBox1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ComboBox1.SelectedIndexChanged
Dim _ini As New INI("somefile.ini")
Dim section As String = ComboBox1.SelectedItem
TextBox1.Text = _ini.GetEntryValue(section, "someKey") 'for specific entry
For Each item In _ini.GetEntryNames(section) 'this is for all entries
'do whatever you want here with the item variable like this:
'TextBox1.Text = _ini.GetEntryValue(section, item)...
Next
End Sub
Related
I have a requirement to implement Pbkdf2 to secure a very old application that uses aspnet membership provider. I am following this answer which is recent and useful, but unable to follow what is inside MyRfc2898DeriveBytes class and it is giving me following issue.. (also I am a c# dev but for this project working in vb.net)
So the issue could be related to language conversion.
I am getting
Non-negative number required. Parameter name: srcOffset
at the following
Buffer.BlockCopy(m_buffer, m_startIndex, password, 0, size)
the m_startIndex here somehow becomes -1
Here is my code in vb
Imports System.IO
Imports System.Security.Cryptography
Namespace custom.hashing.keyderivation
Public Class PBKDF2Hash
Inherits KeyedHashAlgorithm
Private Const kHashBytes As Integer = 64
Private _ms As System.IO.MemoryStream
Public Property WorkFactor As Integer
Public Sub New()
MyBase.New()
Me.WorkFactor = 128000
Me.Key = New Byte(31) {}
Using rngCsp = New RNGCryptoServiceProvider()
rngCsp.GetBytes(Me.Key)
End Using
End Sub
Public Overrides ReadOnly Property HashSize As Integer
Get
Return kHashBytes * 8
End Get
End Property
Protected Overrides Sub HashCore(ByVal array As Byte(), ByVal ibStart As Integer, ByVal cbSize As Integer)
If IsNothing(_ms) Then
_ms = New MemoryStream()
End If
_ms.Write(array, ibStart, cbSize)
'(CSharpImpl.__Assign(_ms, If(_ms, New System.IO.MemoryStream()))).Write(array, ibStart, cbSize)
End Sub
Protected Overrides Function HashFinal() As Byte()
If Me.Key Is Nothing OrElse Me.Key.Length = 0 Then
Throw New CryptographicException("Missing KeyedAlgorithm key")
End If
_ms.Flush()
Dim arr = _ms.ToArray()
_ms = Nothing
Using hmac As HMACSHA512 = New HMACSHA512()
Return New MyRfc2898DeriveBytes(arr, Me.Key, Me.WorkFactor, hmac).GetBytes(kHashBytes)
End Using
End Function
Public Overrides Sub Initialize()
_ms = Nothing
End Sub
End Class
End Namespace
Imports System.Diagnostics.Contracts
Imports System.Security
Imports System.Security.Cryptography
Public Class MyRfc2898DeriveBytes
Inherits DeriveBytes
Private m_buffer As Byte()
Private m_salt As Byte()
Private m_hmac As HMAC
Private m_iterations As UInteger
Private m_block As UInteger
Private m_startIndex As Integer = 0
Private m_endIndex As Integer = 0
Private m_blockSize As Integer = 0
<SecuritySafeCritical>
Public Sub New(ByVal password As Byte(), ByVal salt As Byte(), ByVal iterations As Integer, ByVal hmac As HMAC)
salt = salt
IterationCount = iterations
hmac.Key = password
m_hmac = hmac
m_blockSize = hmac.HashSize >> 3
'''
Initialize()
End Sub
Public Property IterationCount As Integer
Get
Return CInt(m_iterations)
End Get
Set(ByVal value As Integer)
If value <= 0 Then Throw New ArgumentOutOfRangeException("value", "Error: Iteration count is zero or less")
m_iterations = CUInt(value)
Initialize()
End Set
End Property
Public Property Salt As Byte()
Get
Return CType(m_salt.Clone(), Byte())
End Get
Set(ByVal value As Byte())
If value Is Nothing Then Throw New ArgumentNullException("value")
If value.Length < 8 Then Throw New ArgumentException("Error: Salt size is less than 8")
m_salt = CType(value.Clone(), Byte())
Initialize()
End Set
End Property
Public Overrides Function GetBytes(ByVal cb As Integer) As Byte()
If cb <= 0 Then
Throw New ArgumentOutOfRangeException("cb", "Error: Hash size is zero or less")
End If
Contract.Assert(m_blockSize > 0)
Dim password As Byte() = New Byte(cb - 1) {}
Dim offset As Integer = 0
Dim size As Integer = m_endIndex - m_startIndex
If size > 0 Then
If cb >= size Then
Buffer.BlockCopy(m_buffer, m_startIndex, password, 0, size)
m_startIndex = m_endIndex = 0
offset += size
Else
Buffer.BlockCopy(m_buffer, m_startIndex, password, 0, cb)
m_startIndex += cb
Return password
End If
End If
Contract.Assert(m_startIndex = 0 AndAlso m_endIndex = 0, "Invalid start or end index in the internal buffer.")
While offset < cb
Dim T_block As Byte() = Func()
Dim remainder As Integer = cb - offset
If remainder > m_blockSize Then
Buffer.BlockCopy(T_block, 0, password, offset, m_blockSize)
offset += m_blockSize
Else
Buffer.BlockCopy(T_block, 0, password, offset, remainder)
offset += remainder
Buffer.BlockCopy(T_block, remainder, m_buffer, m_startIndex, m_blockSize - remainder)
m_endIndex += (m_blockSize - remainder)
Return password
End If
End While
Return password
End Function
Public Overrides Sub Reset()
Initialize()
End Sub
Protected Overrides Sub Dispose(ByVal disposing As Boolean)
MyBase.Dispose(disposing)
If disposing Then
If m_hmac IsNot Nothing Then
m_hmac.Dispose()
End If
If m_buffer IsNot Nothing Then
Array.Clear(m_buffer, 0, m_buffer.Length)
End If
If m_salt IsNot Nothing Then
Array.Clear(m_salt, 0, m_salt.Length)
End If
End If
End Sub
Private Sub Initialize()
If m_buffer IsNot Nothing Then Array.Clear(m_buffer, 0, m_buffer.Length)
m_buffer = New Byte(m_blockSize - 1) {}
m_block = 1
m_startIndex = m_endIndex = 0
End Sub
Friend Shared Function GetBytesFromInt(ByVal i As UInteger) As Byte()
End Function
Private Function Func() As Byte()
Dim INT_block As Byte() = GetBytesFromInt(m_block)
m_hmac.TransformBlock(m_salt, 0, m_salt.Length, Nothing, 0)
m_hmac.TransformBlock(INT_block, 0, INT_block.Length, Nothing, 0)
m_hmac.TransformFinalBlock(New Byte(-1) {}, 0, 0)
Dim temp As Byte() = m_hmac.Hash
m_hmac.Initialize()
Dim ret As Byte() = temp
For i As Integer = 2 To m_iterations
m_hmac.TransformBlock(temp, 0, temp.Length, Nothing, 0)
m_hmac.TransformFinalBlock(New Byte(-1) {}, 0, 0)
temp = m_hmac.Hash
For j As Integer = 0 To m_blockSize - 1
ret(j) = ret(j) Xor temp(j)
Next
m_hmac.Initialize()
Next
If m_block = UInteger.MaxValue Then
Throw New InvalidOperationException("Derived key too long.")
End If
m_block += 1
Return ret
End Function
End Class
So yes it was c# to vb conversion issues:
double assignment does not work in vb, so the following line was changed from
m_startIndex = m_endIndex = 0
to
m_startIndex = 0
m_endIndex = 0
Other things that I found
Property with same name as variable was not converted properly so
Public Sub New(ByVal password As Byte(), ByVal salt As Byte(), ByVal iterations As Integer, ByVal hmac As HMAC)
salt = salt
was really supposed to be
Public Sub New(ByVal password As Byte(), ByVal salt As Byte(), ByVal iterations As Integer, ByVal hmac As HMAC)
Me.Salt = salt
as Salt was a property
GetBytesFromInt(m_block) was not properly converted to vb
Friend Shared Function GetBytesFromInt(ByVal i As UInteger) As Byte()
Dim vIn As UInteger = 0
Dim vOut As Byte() = BitConverter.GetBytes(i)
Return vOut
'return unchecked(new byte[] { (byte)(i >> 24), (byte)(i >> 16), (byte)(i >> 8), (byte)i });
End Function
How do you hide the windows copy dialog box when copying files through vb.net and just use a progress bar in the vb.net form? This is the code I'm using:
Public Structure SHFILEOPSTRUCT
Public hWnd As Integer
Public wFunc As Integer
Public pFrom As String
Public pTo As String
Public fFlags As Integer
Public fAborted As Integer
Public hNameMaps As Integer
Public sProgress As String
End Structure
Private Declare Function SHFileOperation Lib "shell32.dll" Alias "SHFileOperationA" (ByRef lpFileOp As SHFILEOPSTRUCT) As Integer
Private Const FO_COPY As Int32 = &H2
Private Const FO_DELETE As Int32 = &H3
Private Const FO_MOVE As Int32 = &H1
Private Sub Copy()
Dim shStructure As New SHFILEOPSTRUCT
Dim currentpath As String = lblShare_Path.Text
Dim newpath As String = txtBackupLocation.Text
With shStructure
.wFunc = FO_COPY
.pFrom = currentpath
.pTo = newpath
End With
SHFileOperation(shStructure)
End Sub
Private Sub btnBackup_Click(sender As Object, e As EventArgs) Handles btnBackup.Click
Copy()
progbarStatus.Minimum = 0
progbarStatus.Maximum = DataGridView1.Rows.Count - 1
For i = 0 To DataGridView1.Rows.Count - 1
progbarStatus.Value = i
Next
End Sub
I suggest you to use IO.FileStream to copy file and to get the progress value this way :
Dim CF As New IO.FileStream("C:\[Copy From]", IO.FileMode.Open)
Dim CT As New IO.FileStream("C:\[Copy To]", IO.FileMode.Create)
Dim len As Long = CF.Length - 1
Dim buffer(1024) As Byte
Dim byteCFead As Integer
While CF.Position < len
byteCFead = (CF.Read(buffer, 0, 1024))
CT.Write(buffer, 0, byteCFead)
ProgressBar.Value = CInt(CF.Position / len * 100)
Application.DoEvents()
End While
CT.Flush()
CT.Close()
CF.Close()
I have a school bell project coded with Visual Basic 2010 Express. The computer which runs my program has two or more sound cards. First I will list the sound cards to user. User will select the sound card to work. Finally my program will ring the bells on that sound card. Everything is okey for my codes but i can't list the names of sound cards and ring the bell on specified sound card.
I use WMPLib to play music. I have these codes but there becomes an error "the value is not in the expected range". I spotted where the error is in my codes:
Public Declare Function waveOutGetNumDevs Lib "winmm" () As Integer
Public Declare Function mciSendCommand Lib "winmm.dll" Alias "mciSendCommandA" (ByVal wDeviceID As Integer, ByVal uMessage As String, ByVal dwParam1 As Integer, ByVal dwParam2 As Object) As Integer
Public Declare Function mciGetErrorString Lib "winmm.dll" Alias "mciGetErrorStringA" (ByVal dwError As Integer, ByVal lpstrBuffer As String, ByVal uLength As Integer) As Integer
Public Declare Function mciSendString Lib "winmm.dll" Alias "mciSendStringA" (ByVal lpstrCommand As String, ByVal lpstrReturnString As String, ByVal uReturnLength As Integer, ByVal hwndCallback As Integer) As Integer
Public Declare Function mciGetDeviceID Lib "winmm.dll" Alias "mciGetDeviceIDA" (ByVal lpstrName As String) As Integer
Public Const MMSYSERR_NOERROR = 0
Public Const MCI_SET = &H80D
Public Const MCI_WAVE_OUTPUT = &H800000
Public Structure MCI_WAVE_SET_PARMS
Dim dwCallback As Integer
Dim dwTimeFormat As Integer
Dim dwAudio As Integer
Dim wInput As Integer
Dim wOutput As Integer
Dim wFormatTag As Short
Dim wReserved2 As Short
Dim nChannels As Short
Dim wReserved3 As Short
Dim nSamplesPerSec As Integer
Dim nAvgBytesPerSec As Integer
Dim nBlockAlign As Short
Dim wReserved4 As Short
Dim wBitsPerSample As Short
Dim wReserved5 As Short
End Structure
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
Dim parms As MCI_WAVE_SET_PARMS
Dim wDeviceID As Integer
Dim ret As Integer
parms.wOutput = 0
wDeviceID = mciGetDeviceID("waveaudio")
' the value is not in the expected range error is here and it spots parms
ret = mciSendCommand(wDeviceID, MCI_SET, MCI_WAVE_OUTPUT, parms)
If (ret <> MMSYSERR_NOERROR) Then
Stop
End If
If ofd.ShowDialog Then
ret = mciSendString("Open " & Chr(34) & ofd.FileName & Chr(34) & " alias audio", CStr(0), 0, 0)
ret = mciSendString("Open audio", CStr(0), 0, 0)
End If
End Sub
WindowsMedia.Net
You can do this using WindowsMedia.Net library.
The following example is taken from the link below, it is a code blonging to a Windows form and contains the functionality needed to list all available audio devices and choose the default device (the one that will act as sound output).
Set default Wave Out Audio Device - VB.Net / DRVM_MAPPER_PREFERRED_SET
First i will try to split the code into 2 parts:
List available audio devices
Change default audio device
List available devices
Private Sub RefreshInformation()
PopulateDeviceComboBox()
DisplayDefaultWaveOutDevice()
End Sub
Private Sub PopulateDeviceComboBox()
DevicesComboBox.Items.Clear()
' How many wave out devices are there? WaveOutGetNumDevs API call.
Dim waveOutDeviceCount As Integer = waveOut.GetNumDevs()
For i As Integer = 0 To waveOutDeviceCount - 1
Dim caps As New WaveOutCaps
' Get a name - its in a WAVEOUTCAPS structure.
' The name is truncated to 31 chars by the api call. You probably have to
' dig around in the registry to get the full name.
Dim result As Integer = waveOut.GetDevCaps(i, caps, Marshal.SizeOf(caps))
If result <> MMSYSERR.NoError Then
Dim err As MMSYSERR = DirectCast(result, MMSYSERR)
Throw New Win32Exception("GetDevCaps() error, Result: " & result.ToString("x8") & ", " & err.ToString)
End If
DevicesComboBox.Items.Add(New WaveOutDevice(i, caps))
Next
DevicesComboBox.SelectedIndex = 0
End Sub
Private Sub DisplayDefaultWaveOutDevice()
Dim currentDefault As Integer = GetIdOfDefaultWaveOutDevice()
Dim device As WaveOutDevice = DirectCast(DevicesComboBox.Items(currentDefault), WaveOutDevice)
DefaultDeviceLabel.Text = "Defualt: " & device.WaveOutCaps.szPname
End Sub
Private Function GetIdOfDefaultWaveOutDevice() As Integer
Dim id As Integer = 0
Dim hId As IntPtr
Dim flags As Integer = 0
Dim hFlags As IntPtr
Dim result As Integer
Try
' It would be easier to declare a nice overload with ByRef Integers.
hId = Marshal.AllocHGlobal(4)
hFlags = Marshal.AllocHGlobal(4)
' http://msdn.microsoft.com/en-us/library/bb981557.aspx
result = waveOut.Message(WAVE_MAPPER, DRVM_MAPPER_PREFERRED_GET, hId, hFlags)
If result <> MMSYSERR.NoError Then
Dim err As MMSYSERR = DirectCast(result, MMSYSERR)
Throw New Win32Exception("waveOutMessage() error, Result: " & result.ToString("x8") & ", " & err.ToString)
End If
id = Marshal.ReadInt32(hId)
flags = Marshal.ReadInt32(hFlags)
Finally
Marshal.FreeHGlobal(hId)
Marshal.FreeHGlobal(hFlags)
End Try
' There is only one flag, DRVM_MAPPER_PREFERRED_FLAGS_PREFERREDONLY, defined as 1
' "When the DRVM_MAPPER_PREFERRED_FLAGS_PREFERREDONLY flag bit is set, ... blah ...,
' the waveIn and waveOut APIs use only the current preferred device and do not search
' for other available devices if the preferred device is unavailable.
Return id
End Function
Change default device
Private Sub SetDefaultButton_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles SetDefaultButton.Click
If DevicesComboBox.Items.Count = 0 Then Return
Dim selectedDevice As WaveOutDevice = DirectCast(DevicesComboBox.SelectedItem, WaveOutDevice)
SetDefault(selectedDevice.Id)
RefreshInformation()
End Sub
Private Sub SetDefault(ByVal id As Integer)
Dim defaultId As Integer = GetIdOfDefaultWaveOutDevice()
If defaultId = id Then Return ' no change.
Dim result As Integer
' So here we say "change the Id of the device that has id id to 0", which makes it the default.
result = waveOut.Message(WAVE_MAPPER, DRVM_MAPPER_PREFERRED_SET, New IntPtr(id), IntPtr.Zero)
If result <> MMSYSERR.NoError Then
Dim err As MMSYSERR = DirectCast(result, MMSYSERR)
Throw New Win32Exception("waveOutMessage() error, Result: " & result.ToString("x8") & ", " & err.ToString)
End If
End Sub
Full code
Imports MultiMedia
Imports System.Runtime.InteropServices
Imports System.ComponentModel
Public Class Form1
Private DevicesComboBox As New ComboBox
Private DefaultDeviceLabel As New Label
Private WithEvents SetDefaultButton As New Button
Private Const DRVM_MAPPER_PREFERRED_GET As Integer = &H2015
Private Const DRVM_MAPPER_PREFERRED_SET As Integer = &H2016
Private WAVE_MAPPER As New IntPtr(-1)
' This just brings together a device ID and a WaveOutCaps so
' that we can store them in a combobox.
Private Structure WaveOutDevice
Private m_id As Integer
Public Property Id() As Integer
Get
Return m_id
End Get
Set(ByVal value As Integer)
m_id = value
End Set
End Property
Private m_caps As WaveOutCaps
Public Property WaveOutCaps() As WaveOutCaps
Get
Return m_caps
End Get
Set(ByVal value As WaveOutCaps)
m_caps = value
End Set
End Property
Sub New(ByVal id As Integer, ByVal caps As WaveOutCaps)
m_id = id
m_caps = caps
End Sub
Public Overrides Function ToString() As String
Return WaveOutCaps.szPname
End Function
End Structure
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
' I do use the IDE for this stuff normally... (in case anyone is wondering)
Me.Controls.AddRange(New Control() {DevicesComboBox, DefaultDeviceLabel, SetDefaultButton})
DevicesComboBox.Location = New Point(5, 5)
DevicesComboBox.DropDownStyle = ComboBoxStyle.DropDownList
DevicesComboBox.Width = Me.ClientSize.Width - 10
DevicesComboBox.Anchor = AnchorStyles.Left Or AnchorStyles.Right
DefaultDeviceLabel.Location = New Point(DevicesComboBox.Left, DevicesComboBox.Bottom + 5)
DefaultDeviceLabel.AutoSize = True
SetDefaultButton.Location = New Point(DefaultDeviceLabel.Left, DefaultDeviceLabel.Bottom + 5)
SetDefaultButton.Text = "Set Default"
SetDefaultButton.AutoSize = True
RefreshInformation()
End Sub
Private Sub RefreshInformation()
PopulateDeviceComboBox()
DisplayDefaultWaveOutDevice()
End Sub
Private Sub PopulateDeviceComboBox()
DevicesComboBox.Items.Clear()
' How many wave out devices are there? WaveOutGetNumDevs API call.
Dim waveOutDeviceCount As Integer = waveOut.GetNumDevs()
For i As Integer = 0 To waveOutDeviceCount - 1
Dim caps As New WaveOutCaps
' Get a name - its in a WAVEOUTCAPS structure.
' The name is truncated to 31 chars by the api call. You probably have to
' dig around in the registry to get the full name.
Dim result As Integer = waveOut.GetDevCaps(i, caps, Marshal.SizeOf(caps))
If result <> MMSYSERR.NoError Then
Dim err As MMSYSERR = DirectCast(result, MMSYSERR)
Throw New Win32Exception("GetDevCaps() error, Result: " & result.ToString("x8") & ", " & err.ToString)
End If
DevicesComboBox.Items.Add(New WaveOutDevice(i, caps))
Next
DevicesComboBox.SelectedIndex = 0
End Sub
Private Sub DisplayDefaultWaveOutDevice()
Dim currentDefault As Integer = GetIdOfDefaultWaveOutDevice()
Dim device As WaveOutDevice = DirectCast(DevicesComboBox.Items(currentDefault), WaveOutDevice)
DefaultDeviceLabel.Text = "Defualt: " & device.WaveOutCaps.szPname
End Sub
Private Function GetIdOfDefaultWaveOutDevice() As Integer
Dim id As Integer = 0
Dim hId As IntPtr
Dim flags As Integer = 0
Dim hFlags As IntPtr
Dim result As Integer
Try
' It would be easier to declare a nice overload with ByRef Integers.
hId = Marshal.AllocHGlobal(4)
hFlags = Marshal.AllocHGlobal(4)
' http://msdn.microsoft.com/en-us/library/bb981557.aspx
result = waveOut.Message(WAVE_MAPPER, DRVM_MAPPER_PREFERRED_GET, hId, hFlags)
If result <> MMSYSERR.NoError Then
Dim err As MMSYSERR = DirectCast(result, MMSYSERR)
Throw New Win32Exception("waveOutMessage() error, Result: " & result.ToString("x8") & ", " & err.ToString)
End If
id = Marshal.ReadInt32(hId)
flags = Marshal.ReadInt32(hFlags)
Finally
Marshal.FreeHGlobal(hId)
Marshal.FreeHGlobal(hFlags)
End Try
' There is only one flag, DRVM_MAPPER_PREFERRED_FLAGS_PREFERREDONLY, defined as 1
' "When the DRVM_MAPPER_PREFERRED_FLAGS_PREFERREDONLY flag bit is set, ... blah ...,
' the waveIn and waveOut APIs use only the current preferred device and do not search
' for other available devices if the preferred device is unavailable.
Return id
End Function
Private Sub SetDefaultButton_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles SetDefaultButton.Click
If DevicesComboBox.Items.Count = 0 Then Return
Dim selectedDevice As WaveOutDevice = DirectCast(DevicesComboBox.SelectedItem, WaveOutDevice)
SetDefault(selectedDevice.Id)
RefreshInformation()
End Sub
Private Sub SetDefault(ByVal id As Integer)
Dim defaultId As Integer = GetIdOfDefaultWaveOutDevice()
If defaultId = id Then Return ' no change.
Dim result As Integer
' So here we say "change the Id of the device that has id id to 0", which makes it the default.
result = waveOut.Message(WAVE_MAPPER, DRVM_MAPPER_PREFERRED_SET, New IntPtr(id), IntPtr.Zero)
If result <> MMSYSERR.NoError Then
Dim err As MMSYSERR = DirectCast(result, MMSYSERR)
Throw New Win32Exception("waveOutMessage() error, Result: " & result.ToString("x8") & ", " & err.ToString)
End If
End Sub
End Class
System.Management
You can retrieve the available audio devices using System.Management assembly which is a part of .Net framework:
ManagementObjectSearcher mo =
new ManagementObjectSearcher("select * from Win32_SoundDevice");
foreach (ManagementObject soundDevice in mo.Get())
{
String deviceId = soundDevice.GetPropertyValue("DeviceId").ToString();
String name = soundDevice.GetPropertyValue("Name").ToString();
//saving the name and device id in array
}
References
Get list of audio devices and select one using c# (Another solution provided in this link (using Lync 2013 SDK)
Win32_SoundDevice class
I'm working on my final project in college. It is about advanced encryption standard (AES) for multimedia files (Text and image), but I need some explanation about codes that I don't understand.
Imports System
Imports System.Collections.Generic
Imports System.Text
Imports System.IO
Imports System.Security
Imports System.Security.Cryptography
Imports System.Diagnostics
Imports System.Runtime.CompilerServices
Imports System.Drawing.Imaging
Module CryptoStuff
Public key_size_bits_ku As Integer = 128
Public iv_ku() As Byte
Private Sub MakeKeyAndIV(ByVal password As String, ByVal salt() As Byte, ByVal key_size_bits As Integer,
ByVal block_size_bits As Integer, ByRef key() As Byte, ByRef iv() As Byte)
Dim derive_bytes As New Rfc2898DeriveBytes(password, salt, 1000)
key = Encoding.ASCII.GetBytes(password)
iv = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
End Sub
Region "Enkripsi file dan stream"
Public Function imgToByteArray(ByVal img As Image) As Byte()
Using mStream As New MemoryStream()
img.Save(mStream, img.RawFormat)
Return mStream.ToArray()
End Using
End Function
Public Sub EncryptFile(ByVal password As String, ByVal in_file As String,
ByVal out_file As String)
CryptFile(password, in_file, out_file, True)
End Sub
Public Sub DecryptFile(ByVal password As String, ByVal in_file As String,
ByVal out_file As String)
CryptFile(password, in_file, out_file, False)
End Sub
Public Sub CryptFile(ByVal password As String, ByVal in_file As String,
ByVal out_file As String, ByVal encrypt As Boolean)
Using in_stream As New FileStream(in_file, FileMode.Open, FileAccess.Read)
Using out_stream As New FileStream(out_file, FileMode.Create, FileAccess.Write)
CryptStream(password, in_stream, out_stream, encrypt)
End Using
End Using
End Sub
Public Function byteArrayToImage(ByVal byteArrayIn As Byte()) As Image
Using mStream As New MemoryStream(byteArrayIn)
Return Image.FromStream(mStream)
End Using
End Function
Public Sub CryptStream(ByVal password As String, ByVal in_stream As Stream,
ByVal out_stream As Stream, ByVal encrypt As Boolean)
Dim aes_provider As New AesCryptoServiceProvider()
Dim key_size_bits As Integer = 0
For i As Integer = 1024 To 1 Step -1
If (aes_provider.ValidKeySize(i)) Then
key_size_bits = i
Exit For
End If
Next i
Debug.Assert(key_size_bits > 0)
Console.WriteLine("Key size: " & key_size_bits)
Dim block_size_bits As Integer = aes_provider.BlockSize
Dim key() As Byte = Nothing
Dim iv() As Byte = Nothing
'Dim salt() As Byte = {&H0, &H0, &H1, &H2, &H3, &H4, &H5, &H6, &HF1, &HF0, &HEE, &H21, &H22, &H45}
'MakeKeyAndIV(password, salt, key_size_bits_ku, block_size_bits, key, iv)
key = Encoding.ASCII.GetBytes(password)
iv = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
Dim crypto_transform As ICryptoTransform
If (encrypt) Then
crypto_transform = aes_provider.CreateEncryptor(key, iv)
Else
crypto_transform = aes_provider.CreateDecryptor(key, iv)
End If
Try
Using crypto_stream As New CryptoStream(out_stream, crypto_transform, CryptoStreamMode.Write)
Const block_size As Integer = 1024
Dim buffer(block_size) As Byte
Dim bytes_read As Integer
Do
bytes_read = in_stream.Read(buffer, 0, block_size)
If (bytes_read = 0) Then Exit Do
crypto_stream.Write(buffer, 0, bytes_read)
Loop
End Using
Catch
End Try
crypto_transform.Dispose()
End Sub
End Region ' Encrypt Files and Streams"
End Module
The codes that I don't understand are these:
Dim key_size_bits As Integer = 0
For i As Integer = 1024 To 1 Step -1
If (aes_provider.ValidKeySize(i)) Then
key_size_bits = i
Exit For
End If
Next i
Debug.Assert(key_size_bits > 0)
Console.WriteLine("Key size: " & key_size_bits)
Dim block_size_bits As Integer = aes_provider.BlockSize
Can you explain the use of these codes?
Thanks before
This application I wrote is very effective and will encrypt whatever you want. I left notes in it to answer all your questions. At the bottom, you will see an added class to reduce memory usage of the program. It works rather well, (by 8% -10%) Enjoy.
Items needed:
*3 buttons (Browse) (Encrypt) (Decrypt)
*1 TextBox
For the project video, see my link:
Part 1: https://www.youtube.com/watch?v=sVaA2q8ttzQ
Part 2: https://www.youtube.com/watch?v=TyafeBJ53YU
'Created by: Rythorian77 | github.com/rythorian77
Imports System.IO
Imports System.Security.Cryptography
Imports System.Text
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim ramClass As New AESRam()
End Sub
Private Sub Browse_Click(sender As Object, e As EventArgs) Handles Browse.Click
'Allows you to access files from folders
Dim fetchCryptDialog As New OpenFileDialog With {
.CheckFileExists = True,
.InitialDirectory = "C:\",
.Multiselect = False
}
If fetchCryptDialog.ShowDialog = DialogResult.OK Then
TextBox1.Text = fetchCryptDialog.FileName
End If
End Sub
Private Sub Encrypt_Click(sender As Object, e As EventArgs) Handles Encrypt.Click
'File path goes to textbox
Dim Rythorian77 As String = TextBox1.Text
'This password can be whater you want.
Dim password As String = "123456789ABCDEFG!##$%^&*()_+"
'A data type is the characteristic of a variable that determines what kind of data it can hold.
'Data types include those in the following table as well as user-defined types and specific types of objects.
Dim key As Byte() = New Byte(31) {}
'When overridden in a derived class, encodes a set of characters into a sequence of bytes.
Encoding.Default.GetBytes(password).CopyTo(key, 0)
'RijndaelManaged still works but is considered obsolete in todays world so we use AES
'Represents the abstract base class from which all implementations of the Advanced Encryption Standard (AES) must inherit.
'https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.aes?view=net-6.0
Dim aes As New RijndaelManaged() With
{
.Mode = CipherMode.CBC,
.KeySize = 256,
.BlockSize = 256,
.Padding = PaddingMode.Zeros
}
'Reads a sequence of bytes from the current memory stream and advances the position within the memory stream by the number of bytes read.
Using mnemonicData As New MemoryStream
'Defines a stream that links data streams to cryptographic transformations.
Using cStream As New CryptoStream(mnemonicData, aes.CreateEncryptor(key, key), CryptoStreamMode.Write)
Dim buffer As Byte() = File.ReadAllBytes(Rythorian77)
cStream.Write(buffer, 0, buffer.Length)
Dim appendBuffer As Byte() = mnemonicData.ToArray()
Dim finalBuffer As Byte() = New Byte(appendBuffer.Length - 1) {}
appendBuffer.CopyTo(finalBuffer, 0)
File.WriteAllBytes(Rythorian77, finalBuffer)
End Using
End Using
End Sub
'The above code notes compliment the same
Private Sub Decrypt_Click(sender As Object, e As EventArgs) Handles Decrypt.Click
Dim Rythorian77 As String = TextBox1.Text
Dim password As String = "123456789ABCDEFG!##$%^&*()_+"
Dim key As Byte() = New Byte(31) {}
Encoding.Default.GetBytes(password).CopyTo(key, 0)
Dim aes As New RijndaelManaged() With
{
.Mode = CipherMode.CBC,
.KeySize = 256,
.BlockSize = 256,
.Padding = PaddingMode.Zeros
}
Using mnemonicData As New MemoryStream
'>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> < aes.CreateDecryptor > is the only change from above aes.CreateEncryptor
Using cStream As New CryptoStream(mnemonicData, aes.CreateDecryptor(key, key), CryptoStreamMode.Write)
Dim buffer As Byte() = File.ReadAllBytes(Rythorian77)
cStream.Write(buffer, 0, buffer.Length)
Dim appendBuffer As Byte() = mnemonicData.ToArray()
Dim finalBuffer As Byte() = New Byte(appendBuffer.Length - 1) {}
appendBuffer.CopyTo(finalBuffer, 0)
File.WriteAllBytes(Rythorian77, finalBuffer)
End Using
End Using
End Sub
End Class
**Add this separate Class:**
Imports System.Runtime.InteropServices
Public Class AESRam
'This controls the amount of RAM that your process uses, it doesn't otherwise have any affect on the virtual memory size of your process.
'Sets the minimum and maximum working set sizes for the specified process.
'This will cut memory usage in half.
<DllImport("KERNEL32.DLL", EntryPoint:="SetProcessWorkingSetSize", SetLastError:=True, CallingConvention:=CallingConvention.StdCall)>
Friend Shared Function SetProcessWorkingSetSize(pProcess As IntPtr, dwMinimumWorkingSetSize As Integer, dwMaximumWorkingSetSize As Integer) As Boolean
End Function
'Retrieves a pseudo handle for the current process.
<DllImport("KERNEL32.DLL", EntryPoint:="GetCurrentProcess", SetLastError:=True, CallingConvention:=CallingConvention.StdCall)>
Friend Shared Function GetCurrentProcess() As IntPtr
End Function
'See Above
Public Sub New()
Dim pHandle As IntPtr = GetCurrentProcess()
SetProcessWorkingSetSize(pHandle, -1, -1)
End Sub
End Class
I'm using the below function to generate an MD5\SH1 hash for SQL backup files.
This works well, has progress report etc but is slow if using large files.
Could I generate the MD5 at the same time as SH1 rather than having to process the file twice, doubling the time taken? What about converting an MD5 result to SHA1?
Imports System
Imports System.IO
Imports System.Security.Cryptography
Imports System.Text
Public Class ASyncFileHashAlgorithm
Protected hashAlgorithm As HashAlgorithm
Protected m_hash As Byte()
Protected cancel As Boolean = False
Protected m_bufferSize As Integer = 4096
Public Delegate Sub FileHashingProgressHandler(ByVal sender As Object, _
ByVal e As FileHashingProgressArgs)
Public Event FileHashingProgress As FileHashingProgressHandler
Public Sub New(ByVal hashAlgorithm As HashAlgorithm)
Me.hashAlgorithm = hashAlgorithm
End Sub
Public Function ComputeHash(ByVal stream As Stream) As Byte()
cancel = False
m_hash = Nothing
Dim _bufferSize As Integer = m_bufferSize
' this makes it impossible to change the buffer size while computing
Dim readAheadBuffer As Byte(), buffer As Byte()
Dim readAheadBytesRead As Integer, bytesRead As Integer
Dim size As Long, totalBytesRead As Long = 0
size = stream.Length
readAheadBuffer = New Byte(_bufferSize - 1) {}
readAheadBytesRead = stream.Read(readAheadBuffer, 0, _
readAheadBuffer.Length)
totalBytesRead += readAheadBytesRead
Do
bytesRead = readAheadBytesRead
buffer = readAheadBuffer
readAheadBuffer = New Byte(_bufferSize - 1) {}
readAheadBytesRead = stream.Read(readAheadBuffer, 0, _
readAheadBuffer.Length)
totalBytesRead += readAheadBytesRead
If readAheadBytesRead = 0 Then
hashAlgorithm.TransformFinalBlock(buffer, 0, bytesRead)
Else
hashAlgorithm.TransformBlock(buffer, 0, bytesRead, buffer, 0)
End If
RaiseEvent FileHashingProgress(Me, New _
FileHashingProgressArgs(totalBytesRead, size))
Loop While readAheadBytesRead <> 0 AndAlso Not cancel
If cancel Then
Return InlineAssignHelper(m_hash, Nothing)
End If
Return InlineAssignHelper(m_hash, hashAlgorithm.Hash)
End Function
Public Property BufferSize() As Integer
Get
Return m_bufferSize
End Get
Set(ByVal value As Integer)
m_bufferSize = value
End Set
End Property
Public ReadOnly Property Hash() As Byte()
Get
Return m_hash
End Get
End Property
'Public Sub Cancel()
' cancel = True
'End Sub
Public Overrides Function ToString() As String
Dim hex As String = ""
For Each b As Byte In Hash
hex += b.ToString("x2")
Next
Return hex
End Function
Private Shared Function InlineAssignHelper(Of T)(ByRef target As T, _
ByVal value As T) As T
target = value
Return value
End Function
End Class
Public Class FileHashingProgressArgs
Inherits EventArgs
Public Property TotalBytesRead() As Long
Get
Return m_TotalBytesRead
End Get
Set(ByVal value As Long)
m_TotalBytesRead = Value
End Set
End Property
Private m_TotalBytesRead As Long
Public Property Size() As Long
Get
Return m_Size
End Get
Set(ByVal value As Long)
m_Size = Value
End Set
End Property
Private m_Size As Long
Public Sub New(ByVal totalBytesRead__1 As Long, ByVal size__2 As Long)
TotalBytesRead = totalBytesRead__1
Size = size__2
End Sub
End Class
The following is how I'm generating a hash using the above:
Shared hasher As New ASyncFileHashAlgorithm(SHA1.Create())
Private Function Test(Byval (strFilePathAndName, as String)
Dim stream As IO.Stream = DirectCast(File.Open(strFilePathAndName, _
FileMode.Open), Stream)
AddHandler hasher.FileHashingProgress, _
AddressOf OnFileHashingProgress
Dim t = New Thread(AddressOf hasher.ComputeHash)
t.Start(stream)
While t.IsAlive
Application.DoEvents()
End While
'LblMD5.Text = hasher.ToString???
LblSHA1.Text = hasher.ToString
stream.Dispose()
End Sub
Public Sub OnFileHashingProgress(ByVal sender As Object, _
ByVal e As FileHashingProgressArgs)
SetControlPropertyValue(uxChildForm.ProgressBar, "Position", _
CInt(e.TotalBytesRead / e.Size * 100))
End Sub
You ToString method may create tremendous overhead for large strings since concatenation is expensive (it creates large temporary buffer) and you do it often. Use a StringBuilder (initialised with the correct size) instead.