How to read data from serial port in vb.net? - vb.net

I made a class and there is this sub named SendUSSD, when this is called it sends a ussd code like *123# to a COM port where a gsm mobile is connected. This ussd is supposed to return the mobile balance.
If IsOpen = True Then 'checks if the port is open
SMSPort.WriteLine("AT+CUSD=1,""*123#""" vbCr) 'this sends the ussd code
Form1.TextBox2.Text = SMSPort.ReadLine().ToString() 'this shows the response
End If
Now the problem is sometimes I get the full response like "Your current balance is so and so". But, most of the time I get a part of the message like "Your curr". My guess is that it takes some time to get the response, so how do I make this Form1.TextBox2.Text = SMSPort.ReadLine().ToString() line wait until the last character which is a full-stop to appear and then execute the line?

im using this class to connect com ports.
'connect like this
Public comm As New CommunicationManager
comm.Parity = "None"
comm.StopBits = "One"
comm.DataBits = "8"
comm.BaudRate = "38400"
comm.PortName = comport_ismi
comm.OpenPort()
and the class
Imports System.Text
Imports System.Drawing
Imports System.IO.Ports
Imports System.Windows.Forms
Public Class CommunicationManager
#Region "Manager Enums"
''' <summary>
''' enumeration to hold our transmission types
''' </summary>
Public Enum TransmissionType
Text
Hex
End Enum
''' <summary>
''' enumeration to hold our message types
''' </summary>
Public Enum MessageType
Incoming
Outgoing
Normal
Warning
[Error]
End Enum
#End Region
#Region "Manager Variables"
'property variables
Private _baudRate As String = String.Empty
Private _parity As String = String.Empty
Private _stopBits As String = String.Empty
Private _dataBits As String = String.Empty
Private _portName As String = String.Empty
Private _transType As TransmissionType
Private _displayWindow As RichTextBox
'global manager variables
Private MessageColor As Color() = {Color.Blue, Color.Green, Color.Black, Color.Orange, Color.Red}
Private comPort As New SerialPort()
#End Region
#Region "Manager Properties"
''' <summary>
''' Property to hold the BaudRate
''' of our manager class
''' </summary>
Public Property BaudRate() As String
Get
Return _baudRate
End Get
Set(value As String)
_baudRate = value
End Set
End Property
''' <summary>
''' property to hold the Parity
''' of our manager class
''' </summary>
Public Property Parity() As String
Get
Return _parity
End Get
Set(value As String)
_parity = value
End Set
End Property
''' <summary>
''' property to hold the StopBits
''' of our manager class
''' </summary>
Public Property StopBits() As String
Get
Return _stopBits
End Get
Set(value As String)
_stopBits = value
End Set
End Property
''' <summary>
''' property to hold the DataBits
''' of our manager class
''' </summary>
Public Property DataBits() As String
Get
Return _dataBits
End Get
Set(value As String)
_dataBits = value
End Set
End Property
''' <summary>
''' property to hold the PortName
''' of our manager class
''' </summary>
Public Property PortName() As String
Get
Return _portName
End Get
Set(value As String)
_portName = value
End Set
End Property
''' <summary>
''' property to hold our TransmissionType
''' of our manager class
''' </summary>
Public Property CurrentTransmissionType() As TransmissionType
Get
Return _transType
End Get
Set(value As TransmissionType)
_transType = value
End Set
End Property
''' <summary>
''' property to hold our display window
''' value
''' </summary>
Public Property DisplayWindow() As RichTextBox
Get
Return _displayWindow
End Get
Set(value As RichTextBox)
_displayWindow = value
End Set
End Property
#End Region
#Region "Manager Constructors"
''' <summary>
''' Constructor to set the properties of our Manager Class
''' </summary>
''' <param name="baud">Desired BaudRate</param>
''' <param name="par">Desired Parity</param>
''' <param name="sBits">Desired StopBits</param>
''' <param name="dBits">Desired DataBits</param>
''' <param name="name">Desired PortName</param>
Public Sub New(baud As String, par As String, sBits As String, dBits As String, name As String, rtb As RichTextBox)
_baudRate = baud
_parity = par
_stopBits = sBits
_dataBits = dBits
_portName = name
_displayWindow = rtb
'now add an event handler
AddHandler comPort.DataReceived, New SerialDataReceivedEventHandler(AddressOf comPort_DataReceived)
End Sub
''' <summary>
''' Comstructor to set the properties of our
''' serial port communicator to nothing
''' </summary>
Public Sub New()
_baudRate = String.Empty
_parity = String.Empty
_stopBits = String.Empty
_dataBits = String.Empty
_portName = comport_ismi
_displayWindow = Nothing
'add event handler
AddHandler comPort.DataReceived, New SerialDataReceivedEventHandler(AddressOf comPort_DataReceived)
End Sub
#End Region
#Region "WriteData"
Public Sub WriteData(msg As String)
Select Case CurrentTransmissionType
Case TransmissionType.Text
'first make sure the port is open
'if its not open then open it
If Not (comPort.IsOpen = True) Then
comPort.Open()
End If
'send the message to the port
comPort.Write(msg)
'display the message
DisplayData(MessageType.Outgoing, msg & Convert.ToString(vbLf))
Exit Select
Case TransmissionType.Hex
Try
'convert the message to byte array
Dim newMsg As Byte() = HexToByte(msg)
'send the message to the port
comPort.Write(newMsg, 0, newMsg.Length)
'convert back to hex and display
DisplayData(MessageType.Outgoing, ByteToHex(newMsg) & Convert.ToString(vbLf))
Catch ex As FormatException
'display error message
DisplayData(MessageType.[Error], ex.Message)
Finally
_displayWindow.SelectAll()
End Try
Exit Select
Case Else
'first make sure the port is open
'if its not open then open it
If Not (comPort.IsOpen = True) Then
comPort.Open()
End If
'send the message to the port
comPort.Write(msg)
'display the message
DisplayData(MessageType.Outgoing, msg & Convert.ToString(vbLf))
Exit Select
End Select
End Sub
#End Region
#Region "HexToByte"
''' <summary>
''' method to convert hex string into a byte array
''' </summary>
''' <param name="msg">string to convert</param>
''' <returns>a byte array</returns>
Private Function HexToByte(msg As String) As Byte()
'remove any spaces from the string
msg = msg.Replace(" ", "")
'create a byte array the length of the
'divided by 2 (Hex is 2 characters in length)
Dim comBuffer As Byte() = New Byte(msg.Length / 2 - 1) {}
'loop through the length of the provided string
For i As Integer = 0 To msg.Length - 1 Step 2
'convert each set of 2 characters to a byte
'and add to the array
comBuffer(i / 2) = CByte(Convert.ToByte(msg.Substring(i, 2), 16))
Next
'return the array
Return comBuffer
End Function
#End Region
#Region "ByteToHex"
''' <summary>
''' method to convert a byte array into a hex string
''' </summary>
''' <param name="comByte">byte array to convert</param>
''' <returns>a hex string</returns>
Private Function ByteToHex(comByte As Byte()) As String
'create a new StringBuilder object
Dim builder As New StringBuilder(comByte.Length * 3)
'loop through each byte in the array
For Each data As Byte In comByte
'convert the byte to a string and add to the stringbuilder
builder.Append(Convert.ToString(data, 16).PadLeft(2, "0"c).PadRight(3, " "c))
Next
'return the converted value
Return builder.ToString().ToUpper()
End Function
#End Region
#Region "DisplayData"
''' <summary>
''' method to display the data to & from the port
''' on the screen
''' </summary>
''' <param name="type">MessageType of the message</param>
''' <param name="msg">Message to display</param>
<STAThread> _
Private Sub DisplayData(type As MessageType, msg As String)
'_displayWindow.Invoke(New EventHandler(Sub()
' _displayWindow.SelectedText = String.Empty
' _displayWindow.SelectionFont = New Font(_displayWindow.SelectionFont, FontStyle.Bold)
' _displayWindow.SelectionColor = MessageColor(CInt(type))
' _displayWindow.AppendText(msg)
' _displayWindow.ScrollToCaret()
' End Sub))
End Sub
#End Region
#Region "OpenPort"
Public Function OpenPort() As Boolean
Try
'first check if the port is already open
'if its open then close it
If comPort.IsOpen = True Then
comPort.Close()
End If
'set the properties of our SerialPort Object
comPort.BaudRate = Integer.Parse(_baudRate)
'BaudRate
comPort.DataBits = Integer.Parse(_dataBits)
'DataBits
comPort.StopBits = DirectCast([Enum].Parse(GetType(StopBits), _stopBits), StopBits)
'StopBits
comPort.Parity = DirectCast([Enum].Parse(GetType(Parity), _parity), Parity)
'Parity
comPort.PortName = _portName
'PortName
'now open the port
comPort.Open()
'display message
DisplayData(MessageType.Normal, "Port AÇILDI: " + DateTime.Now + vbLf)
'return true
Return True
Catch ex As Exception
DisplayData(MessageType.[Error], ex.Message)
Return False
End Try
End Function
#End Region
#Region "ClosePort"
Public Function ClosePort() As Boolean
Try
'first check if the port is already open
'if its open then close it
If comPort.IsOpen = True Then
comPort.Close()
End If
'display message
DisplayData(MessageType.Normal, "Port KAPANDI: " + DateTime.Now + vbLf)
'return true if port is closed
If comPort.IsOpen = False Then
Return True
End If
DisplayData(MessageType.Normal, "Kapatmada hata oluştu" & vbLf)
Return False
Catch ex As Exception
DisplayData(MessageType.[Error], ex.Message)
Return False
End Try
End Function
#End Region
#Region "SetParityValues"
Public Sub SetParityValues(obj As Object)
For Each str As String In [Enum].GetNames(GetType(Parity))
DirectCast(obj, ComboBox).Items.Add(str)
Next
End Sub
#End Region
#Region "SetStopBitValues"
Public Sub SetStopBitValues(obj As Object)
For Each str As String In [Enum].GetNames(GetType(StopBits))
DirectCast(obj, ComboBox).Items.Add(str)
Next
End Sub
#End Region
#Region "SetPortNameValues"
Public Sub SetPortNameValues(obj As Object)
For Each str As String In SerialPort.GetPortNames()
DirectCast(obj, ComboBox).Items.Add(str)
Next
End Sub
#End Region
#Region "comPort_DataReceived"
''' <summary>
''' method that will be called when theres data waiting in the buffer
''' </summary>
''' <param name="sender"></param>
''' <param name="e"></param>
Private Sub comPort_DataReceived(sender As Object, e As SerialDataReceivedEventArgs)
'determine the mode the user selected (binary/string)
Select Case CurrentTransmissionType
'user chose string
Case TransmissionType.Text
'read data waiting in the buffer
Dim msg As String = comPort.ReadExisting()
'display the data to the user
DisplayData(MessageType.Incoming, msg)
' + "\n"); **************
Exit Select
'user chose binary
Case TransmissionType.Hex
'retrieve number of bytes in the buffer
Dim bytes As Integer = comPort.BytesToRead
'create a byte array to hold the awaiting data
Dim comBuffer As Byte() = New Byte(bytes - 1) {}
'read the data and store it
comPort.Read(comBuffer, 0, bytes)
'display the data to the user
DisplayData(MessageType.Incoming, ByteToHex(comBuffer))
' + "\n");
Exit Select
Case Else
'read data waiting in the buffer
Dim str As String = comPort.ReadExisting()
'display the data to the user
DisplayData(MessageType.Incoming, str)
' + "\n");
Exit Select
End Select
End Sub
#End Region
End Class

I guess you are using the DataReceived event, if so, you can just take the data and split it by the lastIndexOf(Enviroment.NewLine).
you will have two part the first one is a string with some amount of lines and the second one is a string that contain no more lines.
You can take the first part and split it by new line and even create a new event (LineReceived).
for the second part(the part after the lastIndexOf(Enviroment.NewLine)) of the data just concatenate it to the beginning of the data that will arrive the next time.

Try setting comm.Newline. Probably should be vbCR.

Related

Why does my for loop not work?

I am trying to run a small test to see if the value sent matches the value received. however, in most cases the value received seems to be one step behind!
For i As Decimal = 0 To 127
j = Hex(i)
stsResult = PCANBasic.Read(m_PcanHandle, myCANMsg, CANTimeStamp)
CANMsg = New TPCANMsg()
CANMsg.DATA = CType(Array.CreateInstance(GetType(Byte), 8), Byte())
CANMsg.ID = Convert.ToInt32(240, 16)
CANMsg.LEN = Convert.ToByte(8)
CANMsg.MSGTYPE = TPCANMessageType.PCAN_MESSAGE_STANDARD
CANMsg.DATA(3) = Convert.ToByte(10, 16)
CANMsg.DATA(4) = Convert.ToByte(j, 16)
CANMsg.DATA(5) = Convert.ToByte(99, 16)
PCANBasic.Write(m_PcanHandle, CANMsg)
ReadAnalogVal() ' Sents a request message so that the it updates the message about to be read
stsResult = PCANBasic.Read(m_PcanHandle, myCANMsg, CANTimeStamp) 'reads bus and populates var myCANMsg with the data
hiBit = Hex(myCANMsg.DATA(0))
If (stsResult <> TPCANStatus.PCAN_ERROR_QRCVEMPTY) Then
If myCANMsg.ID = 960 And hiBit = j Then
MessageBox.Show("you sent: " & j & " and Recieved: " & hiBit)
Else
MessageBox.Show("Response did NOT match output. Output:" & j & " Recieved: " & hiBit)
End If
End If
Next
CANMsg = New TPCANMsg()
CANMsg.DATA = CType(Array.CreateInstance(GetType(Byte), 8), Byte())
CANMsg.ID = Convert.ToInt32(240, 16)
CANMsg.LEN = Convert.ToByte(8)
CANMsg.MSGTYPE = TPCANMessageType.PCAN_MESSAGE_STANDARD
CANMsg.DATA(3) = Convert.ToByte(0, 16)
CANMsg.DATA(4) = Convert.ToByte(0, 16)
PCANBasic.Write(m_PcanHandle, CANMsg)
iBuffer = PCANBasic.PCAN_FILTER_OPEN
result = PCANBasic.SetValue(PCANBasic.PCAN_USBBUS1, TPCANParameter.PCAN_MESSAGE_FILTER, iBuffer, Convert.ToUInt32(Len(iBuffer)))
If result <> TPCANStatus.PCAN_ERROR_OK Then
' An error occurred, get a text describing the error and show it
'
PCANBasic.GetErrorText(result, 0, strMsg)
MessageBox.Show(strMsg.ToString)
Else
MessageBox.Show("Filter is open again")
End If
End Function
This seems to work for some cases and then most of the time it does not match, any advise would be appreciated. this is my first VB.NET application so i may be making an amateur mistake. I have looked into Multi-threading but I'm not entirely sure how to make it work in this case.
Here is more of the application:
Imports System.Text
' Inclusion of PEAK PCAN-Basic namespace
'
Imports System.Text
Inclusion of PEAK PCAN-Basic namespace
Imports Peak.Can.Basic
Imports TPCANHandle = System.UInt16
Imports TPCANBitrateFD = System.String
Imports TPCANTimestampFD = System.UInt64
Public Class Form1
Public Sub New()
' Initializes Form's component
'
InitializeComponent()
' Initializes specific components
'
InitializeBasicComponents()
End Sub
''' <summary>
''' Message Status structure used to show CAN Messages
''' in a ListView
''' </summary>
Private Class MessageStatus
Private m_Msg As TPCANMsgFD
Private m_TimeStamp As TPCANTimestampFD
Private m_oldTimeStamp As TPCANTimestampFD
Private m_iIndex As Integer
Private m_Count As Integer
Private m_bShowPeriod As Boolean
Private m_bWasChanged As Boolean
Public Sub New(ByVal canMsg As TPCANMsgFD, ByVal canTimestamp As TPCANTimestampFD, ByVal listIndex As Integer)
m_Msg = canMsg
m_TimeStamp = canTimestamp
m_oldTimeStamp = canTimestamp
m_iIndex = listIndex
m_Count = 1
m_bShowPeriod = True
m_bWasChanged = False
End Sub
Public Sub Update(ByVal canMsg As TPCANMsgFD, ByVal canTimestamp As TPCANTimestampFD)
m_Msg = canMsg
m_oldTimeStamp = m_TimeStamp
m_TimeStamp = canTimestamp
m_bWasChanged = True
m_Count += 1
End Sub
Private Function GetMsgTypeString() As String
Dim strTemp As String
If (m_Msg.MSGTYPE And TPCANMessageType.PCAN_MESSAGE_STATUS) = TPCANMessageType.PCAN_MESSAGE_STATUS Then
Return "STATUS"
End If
If (m_Msg.MSGTYPE And TPCANMessageType.PCAN_MESSAGE_ERRFRAME) = TPCANMessageType.PCAN_MESSAGE_ERRFRAME Then
Return "ERROR"
End If
If (m_Msg.MSGTYPE And TPCANMessageType.PCAN_MESSAGE_EXTENDED) = TPCANMessageType.PCAN_MESSAGE_EXTENDED Then
strTemp = "EXT"
Else
strTemp = "STD"
End If
If (m_Msg.MSGTYPE And TPCANMessageType.PCAN_MESSAGE_RTR) = TPCANMessageType.PCAN_MESSAGE_RTR Then
strTemp += "/RTR"
Else
If (m_Msg.MSGTYPE > TPCANMessageType.PCAN_MESSAGE_EXTENDED) Then
strTemp += " [ "
If ((m_Msg.MSGTYPE And TPCANMessageType.PCAN_MESSAGE_FD) = TPCANMessageType.PCAN_MESSAGE_FD) Then
strTemp += " FD"
End If
If ((m_Msg.MSGTYPE And TPCANMessageType.PCAN_MESSAGE_BRS) = TPCANMessageType.PCAN_MESSAGE_BRS) Then
strTemp += " BRS"
End If
If ((m_Msg.MSGTYPE And TPCANMessageType.PCAN_MESSAGE_ESI) = TPCANMessageType.PCAN_MESSAGE_ESI) Then
strTemp += " ESI"
End If
strTemp += " ]"
End If
End If
Return strTemp
End Function
Private Function GetIdString() As String
If (m_Msg.MSGTYPE And TPCANMessageType.PCAN_MESSAGE_EXTENDED) = TPCANMessageType.PCAN_MESSAGE_EXTENDED Then
Return String.Format("{0:X8}h", m_Msg.ID)
Else
Return String.Format("{0:X3}h", m_Msg.ID)
End If
End Function
Private Function GetDataString() As String
Dim strTemp As String
strTemp = ""
If (m_Msg.MSGTYPE And TPCANMessageType.PCAN_MESSAGE_RTR) = TPCANMessageType.PCAN_MESSAGE_RTR Then
strTemp = "Remote Request"
Else
For i As Integer = 0 To Form1.GetLengthFromDLC(m_Msg.DLC, (m_Msg.MSGTYPE And TPCANMessageType.PCAN_MESSAGE_FD) = 0) - 1
strTemp += String.Format("{0:X2} ", m_Msg.DATA(i))
Next
End If
Return strTemp
End Function
Private Function GetTimeString() As String
Dim fTime As Double
fTime = (m_TimeStamp / 1000.0R)
If m_bShowPeriod Then
fTime -= (m_oldTimeStamp / 1000.0R)
End If
Return fTime.ToString("F1")
End Function
Public ReadOnly Property CANMsg() As TPCANMsgFD
Get
Return m_Msg
End Get
End Property
Public ReadOnly Property Timestamp() As TPCANTimestampFD
Get
Return m_TimeStamp
End Get
End Property
Public ReadOnly Property Position() As Integer
Get
Return m_iIndex
End Get
End Property
Public ReadOnly Property TypeString() As String
Get
Return GetMsgTypeString()
End Get
End Property
Public ReadOnly Property IdString() As String
Get
Return GetIdString()
End Get
End Property
Public ReadOnly Property DataString() As String
Get
Return GetDataString()
End Get
End Property
Public ReadOnly Property Count() As Integer
Get
Return m_Count
End Get
End Property
Public Property ShowingPeriod() As Boolean
Get
Return m_bShowPeriod
End Get
Set(ByVal value As Boolean)
If m_bShowPeriod Xor value Then
m_bShowPeriod = value
m_bWasChanged = True
End If
End Set
End Property
Public Property MarkedAsUpdated() As Boolean
Get
Return m_bWasChanged
End Get
Set(ByVal value As Boolean)
m_bWasChanged = value
End Set
End Property
Public ReadOnly Property TimeString() As String
Get
Return GetTimeString()
End Get
End Property
End Class
''' <summary>
''' Read-Delegate Handler
''' </summary>
Private Delegate Sub ReadDelegateHandler()
''' <summary>
''' Saves the desired connection mode
''' </summary>
Private m_IsFD As Boolean
''' <summary>
''' Saves the handle of a PCAN hardware
''' </summary>
Private m_PcanHandle As TPCANHandle
''' <summary>
''' Saves the baudrate register for a conenction
''' </summary>
Private m_Baudrate As TPCANBaudrate
''' <summary>
''' Saves the type of a non-plug-and-play hardware
''' </summary>
Private m_HwType As TPCANType
''' <summary>
''' Stores the status of received messages for its display
''' </summary>
Private m_LastMsgsList As System.Collections.ArrayList
''' <summary>
''' Read Delegate for calling the function "ReadMessages"
''' </summary>
Private m_ReadDelegate As ReadDelegateHandler
''' <summary>
''' Receive-Event
''' </summary>
Private m_ReceiveEvent As System.Threading.AutoResetEvent
''' <summary>
''' Thread for message reading (using events)
''' </summary>
Private m_ReadThread As System.Threading.Thread
''' <summary>
''' Handles of the current available PCAN-Hardware
''' </summary>
Private m_HandlesArray As TPCANHandle()

How to make LinearLayout in Visual Basic (visual studio 2013)

(this is not related to VB6)
like above, I want to make a 'textbox' control between separated 'label' controls.
I used method to load those three controls (two labels and one textbox), but I cannot precisely locate the textbox and the following label.
In the application, there will be more than hundreds of sentences with almost the same number of blanks(textbox), so the perfect lining is required.
So, is there any good method to do that?
Thank you!
You can make a class that inherits from Panel and includes two Labels and a Textbox that get automatically realigned. I did something like that to get you started. Just paste the code into your project, recompile once and you can add these to your Form from the Toolbox (or create them dynamically of course). This is nowhere complete. You should make properties for the fonts for example and additional events based on your needs but you get my idea I think.
Public Class ctrlBlankSentence
Inherits Panel
Private WithEvents lblLeft As Label 'The left part of the sentence
Private WithEvents tbBlank As TextBox 'The blank text
Private WithEvents lblRight As Label 'The right part of the sentence
Public Event BlankTextChanged() 'Use events to react to user input
Private _Spacing As Integer
''' <summary>
''' Determines the distance between the labels and the textbox
''' </summary>
Public Property Spacing As Integer
Get
Return _Spacing
End Get
Set(value As Integer)
_Spacing = value
DoreAlign()
End Set
End Property
Private _TextboxWidth As Integer
''' <summary>
''' Determines the width of the textbox
''' </summary>
Public Property TextboxWidth As Integer
Get
Return _TextboxWidth
End Get
Set(value As Integer)
_TextboxWidth = value
DoreAlign()
End Set
End Property
Private _AutosizeControl As Boolean
''' <summary>
''' Determines if the panel is automatically resized.
''' </summary>
Public Property AutosizeControl As Boolean
Get
Return _AutosizeControl
End Get
Set(value As Boolean)
_AutosizeControl = value
DoreAlign()
End Set
End Property
''' <summary>
''' Used to get or set the left part of the sentence
''' </summary>
Public Property LeftText As String
Get
Return lblLeft.Text
End Get
Set(value As String)
lblLeft.Text = value
DoreAlign()
End Set
End Property
''' <summary>
''' Used to set the right part of the sentence
''' </summary>
Public Property RightText As String
Get
Return lblRight.Text
End Get
Set(value As String)
lblRight.Text = value
DoreAlign()
End Set
End Property
''' <summary>
''' Used to get or set the user input
''' </summary>
Public Property BlankText As String
Get
Return tbBlank.Text
End Get
Set(value As String)
tbBlank.Text = value
RaiseEvent BlankTextChanged()
End Set
End Property
#Region "Constructor"
Public Sub New()
lblLeft = New Label With {.AutoSize = True, .Text = "Left Text"}
lblRight = New Label With {.AutoSize = True, .Text = "Right Text"}
tbBlank = New TextBox
Spacing = 3
TextboxWidth = 100
AutosizeControl = True
Me.Controls.Add(lblLeft)
Me.Controls.Add(lblRight)
Me.Controls.Add(tbBlank)
DoreAlign()
End Sub
#End Region
#Region "The method the realigns the controls"
Private Sub DoreAlign()
lblLeft.Left = 0
tbBlank.Left = lblLeft.Right + Spacing
tbBlank.Width = TextboxWidth
lblRight.Left = tbBlank.Right + Spacing
If AutosizeControl Then
Me.Width = lblRight.Right
Me.Height = tbBlank.Height
End If
lblRight.Top = CInt(Me.Height / 2 - lblRight.Height / 2)
lblLeft.Top = lblRight.Top
End Sub
#End Region
Private Sub thisTextChanged() Handles tbBlank.TextChanged
RaiseEvent BlankTextChanged()
End Sub
End Class

VB.net - Simultaneous Audio

So I'm working on a simple VB.net game for school, in which you pop bubbles. We need to have a sound play when you pop a bubble, which is very simple with the audio play function;
Private Sub bubblePop(sender As Object, e As EventArgs) Handles bubble.Click
My.Computer.Audio.Play(My.Resources.pop, _
AudioPlayMode.Background)
End Sub
However we also have a little backing track for the game that we want to loop in the background infinitely. We tried this with a similar instance of that function;
Private Sub GameScreen_Load(sender As Object, e As EventArgs) Handles MyBase.Load
My.Computer.Audio.Play(My.Resources.musicLoop, _
AudioPlayMode.BackgroundLoop)
End Sub
The function shown above only allows one audio file to be played at once, meaning when a bubble is popped the music disappears for good.
I've tried using two seperate windows media player things, but that isn't working either;
Public pop As String = "pop.wav"
Public minesound As String = "mine.wav"
Public Sub soundEffects(sound)
If sound = pop Then
GameScreen.AxWindowsMediaPlayer2.URL = pop
ElseIf sound = minesound Then
GameScreen.AxWindowsMediaPlayer2.URL = minesound
End If
End Sub
Any help or advice is very appreciated! Thank you!
Basically you need to run an asynchronous operation to play more than one file at once.
I've started writting a solution using My.Computer method but even using a Task/Thread it seems that (strangely) is not sufficient to play a secondary file without stopping the playback of the first file ran so maybe other factor (unknown for me) could be involved, then I've solved it using MCI.
The usage can be this:
Dim TaskCancellationTokenSource As New CancellationTokenSource
Dim TaskToken As CancellationToken = TaskCancellationTokenSource.Token
Private Sub BubbleLoop(ByVal CancellationToken As Threading.CancellationToken)
Dim AudioFileLoop = New MCIPlayer(Me, "C:\BubbleLoop.wav")
Do Until CancellationToken.IsCancellationRequested
AudioFileLoop.Play(AudioPlayMode.WaitToComplete)
Loop
AudioFileLoop.Close()
End Sub
Private Sub Test()
' This plays a file asynchronously into an infinite loop.
Task.Factory.StartNew(Sub() BubbleLoop(TaskToken), TaskToken)
' Wait 2 seconds (just to demonstrate this example)
Threading.Thread.Sleep(2 * 1000)
' Play any other file while the loop is still playing.
Dim AudioFile = New MCIPlayer(Me, "C:\SingleBubble.mp3")
AudioFile.Play(AudioPlayMode.Background)
' Cancel the Bubble Loop.
TaskCancellationTokenSource.Cancel()
End Sub
And you need to add this basic MCI class that I've did (It's not full tsted):
' [ MCI Player ]
'
' // By Elektro H#cker
#Region " Usage Examples "
'Dim AudioFile As New MCIPlayer(Me, "C:\Audio.wav")
'AudioFile.Play(AudioPlayMode.BackgroundLoop)
'Dim sb As New System.Text.StringBuilder
'sb.AppendLine("Filename: " & AudioFile.Filename)
'sb.AppendLine("State...: " & AudioFile.State.ToString)
'sb.AppendLine("Mode....: " & AudioFile.PlaybackMode.ToString)
'sb.AppendLine("Channels: " & CStr(AudioFile.Channels))
'sb.AppendLine("Duration: " & TimeSpan.FromMilliseconds(AudioFile.Duration).ToString("hh\:mm\:ss"))
'MessageBox.Show(sb.ToString, "MCI Player", MessageBoxButtons.OK, MessageBoxIcon.Information)
'AudioFile.Stop()
#End Region
#Region " MCI Player "
''' <summary>
''' Play Wave, MP3 or MIDI files
''' </summary>
Public Class MCIPlayer
Inherits NativeWindow
Implements IDisposable
#Region " API "
''' <summary>
''' Sends a command string to an MCI device.
''' The device that the command is sent to is specified in the command string.
''' </summary>
''' <param name="command">
''' Pointer to a null-terminated string that specifies an MCI command string.
''' For a list, see Multimedia Command Strings.
''' </param>
''' <param name="buffer">
''' Buffer that receives return information.
''' If no return information is needed, this parameter can be NULL.
''' </param>
''' <param name="bufferSize">
''' Size, in characters, of the return buffer specified.
''' </param>
''' <param name="hwndCallback">
''' Handle to a callback window if the "notify" flag was specified in the command string.
''' </param>
<System.Runtime.InteropServices.
DllImport("winmm.dll", SetLastError:=True)>
Private Shared Function mciSendString(
ByVal command As String,
ByVal buffer As System.Text.StringBuilder,
ByVal bufferSize As Integer,
ByVal hwndCallback As IntPtr
) As Integer
End Function
#End Region
#Region " Variables "
''' <summary>
''' The form to manage Windows Messages.
''' </summary>
Private WithEvents form As Form = Nothing
''' <summary>
''' Indicates the audio play command of mciSendString.
''' </summary>
Private PlayCommand As String = String.Empty
''' <summary>
''' Buffer that receives return information.
''' </summary>
Private ReturnInfo As New System.Text.StringBuilder() With {.Capacity = 255}
''' <summary>
''' The current filename of the file that is to be played.
''' </summary>
Private _filename As String = String.Empty
''' <summary>
''' Indicates the current playback mode.
''' </summary>
Private _PlaybackMode As AudioPlayMode
''' <summary>
''' Flag to cancel the BackgroundLoop PlaybackMode.
''' </summary>
Private CancelLoop As Boolean = False
#End Region
#Region " Properties "
''' <summary>
''' The current filename of the file that is to be played.
''' </summary>
Public Property Filename() As String
Get
Return _filename
End Get
Set(ByVal value As String)
If Not IO.File.Exists(value) Then
Throw New IO.FileNotFoundException
Exit Property
End If
_filename = value
End Set
End Property
''' <summary>
''' Gets che current Playback State.
''' </summary>
Public ReadOnly Property State As PlaybackState
Get
mciSendString("status file mode", ReturnInfo, ReturnInfo.Capacity, IntPtr.Zero)
Return [Enum].Parse(GetType(PlaybackState), ReturnInfo.ToString, True)
End Get
End Property
''' <summary>
''' Gets or sets the playback mode of the current file.
''' </summary>
Public Property PlaybackMode As AudioPlayMode
Get
Return _PlaybackMode
End Get
Set(value As AudioPlayMode)
_PlaybackMode = value
End Set
End Property
''' <summary>
''' Gets the channels of the file.
''' </summary>
ReadOnly Property Channels() As Integer
Get
mciSendString("status file channels", ReturnInfo, ReturnInfo.Capacity, IntPtr.Zero)
Return If(IsNumeric(ReturnInfo.ToString),
CInt(ReturnInfo.ToString),
-1)
End Get
End Property
''' <summary>
''' Gets the file duration in Milleseconds.
''' </summary>
ReadOnly Property Duration() As Integer
Get
mciSendString("set file time format milliseconds", Nothing, 0, IntPtr.Zero)
mciSendString("status file length", ReturnInfo, ReturnInfo.Capacity, IntPtr.Zero)
Return If(String.IsNullOrEmpty(ReturnInfo.ToString), 0, CInt(ReturnInfo.ToString))
End Get
End Property
#End Region
#Region " Enumerations "
''' <summary>
''' Audio File playback state.
''' </summary>
Public Enum PlaybackState As Short
''' <summary>
''' File is playing.
''' </summary>
Playing = 0
''' <summary>
''' File is paused.
''' </summary>
Paused = 1
''' <summary>
''' File is stopped.
''' </summary>
Stopped = 2
End Enum
''' <summary>
''' Windows Message Identifiers.
''' </summary>
Public Enum KnownMessages As Integer
''' <summary>
''' Notifies an application that an MCI device has completed an operation.
''' MCI devices send this message only when the MCI_NOTIFY flag is used.
''' </summary>
MM_MCINOTIFY = 953
End Enum
#End Region
#Region " Constructor "
''' <summary>
''' Play Wave, MP3 or MIDI files.
''' </summary>
''' <param name="AudioFile">Indicates the filename of the media to play.</param>
''' <remarks></remarks>
Public Sub New(ByVal form As Form, ByVal AudioFile As String)
Me.Filename = AudioFile
' Set the Formulary.
Me.form = form
' Assign the form handle.
SetFormHandle()
End Sub
#End Region
#Region " Public Methods "
''' <summary>
''' Plays the file that is specified as the filename.
''' </summary>
''' <remarks></remarks>
Public Sub Play(ByVal PlayMode As AudioPlayMode)
DisposedCheck()
Select Case PlayMode
Case AudioPlayMode.Background
PlayCommand = "play file from 0"
Me.PlaybackMode = AudioPlayMode.Background
Case AudioPlayMode.BackgroundLoop
PlayCommand = "play file from 0 notify"
Me.PlaybackMode = AudioPlayMode.BackgroundLoop
Case AudioPlayMode.WaitToComplete
PlayCommand = "play file from 0 wait"
Me.PlaybackMode = AudioPlayMode.WaitToComplete
End Select
' Open command
Select Case Me.Filename.Split(".").LastOrDefault
Case "mp3"
mciSendString(String.Format("open ""{0}"" type mpegvideo alias file", Me.Filename),
Nothing,
0,
IntPtr.Zero)
Case "wav"
mciSendString(String.Format("open ""{0}"" type waveaudio alias file", Me.Filename),
Nothing,
0,
IntPtr.Zero)
Case "mid", "midi"
mciSendString("stop midi", Nothing, 0, 0)
mciSendString("close midi", Nothing, 0, 0)
mciSendString(String.Format("open sequencer! ""{0}"" alias file", Me.Filename),
Nothing,
0, IntPtr.Zero)
Case Else
Throw New Exception("File type not supported.")
[Close]()
End Select
' Play command
mciSendString(PlayCommand, Nothing, 0, If(PlaybackMode = AudioPlayMode.BackgroundLoop,
Me.Handle,
IntPtr.Zero))
End Sub
''' <summary>
''' Pause the current playback.
''' </summary>
''' <remarks></remarks>
Public Sub Pause()
DisposedCheck()
CancelLoop = True
mciSendString("pause file", Nothing, 0, IntPtr.Zero)
End Sub
''' <summary>
''' Resume the current playback if it is currently paused.
''' </summary>
Public Sub [Resume]()
DisposedCheck()
If Me.State = PlaybackState.Paused Then
CancelLoop = False
mciSendString("resume file", Nothing, 0, IntPtr.Zero)
End If
End Sub
''' <summary>
''' Stop the current playback.
''' </summary>
Public Sub [Stop]()
DisposedCheck()
CancelLoop = True
mciSendString("stop file", Nothing, 0, IntPtr.Zero)
End Sub
''' <summary>
''' Close the current file.
''' </summary>
Public Overloads Sub [Close]()
DisposedCheck()
CancelLoop = True
mciSendString("close file", Nothing, 0, IntPtr.Zero)
End Sub
#End Region
#Region " Event Handlers "
''' <summary>
''' Assign the handle of the target form to this NativeWindow,
''' necessary to override WndProc.
''' </summary>
Private Sub SetFormHandle() _
Handles form.HandleCreated, form.Load, form.Shown
Try
If Not Me.Handle.Equals(Me.form.Handle) Then
Me.AssignHandle(Me.form.Handle)
End If
Catch ' ex As InvalidOperationException
End Try
End Sub
''' <summary>
''' Releases the Handle.
''' </summary>
Private Sub OnHandleDestroyed() _
Handles form.HandleDestroyed
Me.ReleaseHandle()
End Sub
#End Region
#Region " Windows Messages "
''' <summary>
''' Processes Windows messages for this Window.
''' </summary>
''' <param name="m">
''' Contains the Windows Message parameters.
''' </param>
Protected Overrides Sub WndProc(ByRef m As Message)
MyBase.WndProc(m)
If m.Msg = KnownMessages.MM_MCINOTIFY Then
If Not CancelLoop Then
Play(AudioPlayMode.BackgroundLoop)
Else
CancelLoop = False
End If
End If
End Sub
#End Region
#Region " IDisposable "
''' <summary>
''' To detect redundant calls when disposing.
''' </summary>
Private IsDisposed As Boolean = False
''' <summary>
''' Prevents calls to methods after disposing.
''' </summary>
Private Sub DisposedCheck()
If Me.IsDisposed Then
Throw New ObjectDisposedException(Me.GetType().FullName)
End If
End Sub
''' <summary>
''' Disposes the objects generated by this instance.
''' </summary>
Public Sub Dispose() Implements IDisposable.Dispose
Dispose(True)
GC.SuppressFinalize(Me)
End Sub
' IDisposable
Protected Overridable Sub Dispose(IsDisposing As Boolean)
If Not Me.IsDisposed Then
If IsDisposing Then
[Close]()
Me.form = Nothing
Me.ReleaseHandle()
Me.DestroyHandle()
End If
End If
Me.IsDisposed = True
End Sub
#End Region
End Class
#End Region

Adding items to ListView from a Class

I am having trouble adding an item to a listview from one of my classes. I am missing something that is obviously over my head. If someone could help me to understand what I am missing that would be great.
I don't know how much detail I need to provide. What I am trying to do is to basic so I know I have to be missing something. I have a class that I am trying to use to add an item to a listview I have on a form. There are no errors thrown, yet nothing gets added.
I have even tried using something as simple as frmGiveaways.lstAccounts.items.add("wtf") in the class, it doesn't throw any errors, the line is processed, yet no items appear in the list.
What are some things that would keep me from being able to do this?
Here is the class
Imports Simple_IRC_Client.Delegates
Imports System.Text.RegularExpressions
''' <summary>
''' Handles minimal IRC server response messages.
''' </summary>
Public Class OutputMessages : Implements IDisposable
#Region " Private Members "
Private ReadOnly ColorQuit As Color = Color.FromArgb(102, 54, 31)
Private ReadOnly ColorPrivmsg As Color = Color.FromArgb(76, 76, 76)
Private ReadOnly ColorTopic As Color = Color.FromArgb(176, 55, 176)
Private ReadOnly ColorKick As Color = Color.FromArgb(199, 50, 50)
Private ReadOnly ColorUserEvent As Color = Color.FromArgb(128, 128, 128)
Private WithEvents _ircConnection As InitiateConnection
Private _mainView As MainView
Private _window As RichTextBox
#End Region
#Region " Constructor "
Public Sub New(ByVal mainView As MainView, ByVal ircConnection As InitiateConnection)
_mainView = mainView
_ircConnection = ircConnection
_window = _mainView.rtbChannelView
End Sub
#End Region
#Region " EventArghs "
Private Sub ServerResponse(ByVal serverResponse As String) Handles _ircConnection.ServerResponseOutputEventArghs
' This setting has only been added for demonstration purposes of what raw data
' looks like.
If _mainView.mnuMainMenuOptionsrawData.Checked Then
OutputResponse(_window, serverResponse, Color.Black)
Exit Sub
End If
Dim parts() As String = serverResponse.Split(" "c)
Dim address As String = parts(0)
Select Case parts(1)
Case "PRIVMSG" : Privmsg(address, serverResponse.Substring(indexOf(serverResponse, 3) + 1).Substring(1))
Case "JOIN" : Join(address)
Case "PART", "QUIT" : Quit(address)
Case "ERROR" : Disconnected()
Case "332" : TopicOnjoin(serverResponse.Substring(indexOf(serverResponse, 4) + 1).Substring(1))
End Select
End Sub
#End Region
#Region " Private"
''' <summary>
''' Outputs a GUI message on me/user Privmsg.
''' </summary>
''' <param name="address">The source of the user's local host.</param>
''' <param name="message">The message text.</param>
''' <remarks>
''' Displays an output message to the normalview window with correct format and colouring on Me,
''' User Privmsg.
''' </remarks>
Private Sub Privmsg(ByVal address As String, ByVal message As String)
Dim outputFormat As String = String.Format("<{0}> {1}", Split(address), message)
OutputResponse(_window, outputFormat, Color.Black)
Select Case message
Case "" : _ircConnection.SendMessage(String.Format("PRIVMSG " & ConnectionInformation.Channel & " :" & "{0}", Split(address)))
Case frmGiveaways.keyword
_ircConnection.SendMessage(String.Format("PRIVMSG " & ConnectionInformation.Channel & " :" & "recieved keyword", Split(address)))
frmGiveaways.lstAccountsEntered.Items.Add(Split(address))
End Select
End Sub
Private Sub Join(ByVal address As String)
If Split(address) = ConnectionInformation.ChannelNick Then
Exit Sub
End If
Dim outputFortmat As String = String.Format("{0} has joined the conversation.", Split(address))
OutputResponse(_window, outputFortmat, ColorUserEvent)
'Welcome message proof of concept
'_ircConnection.SendMessage(String.Format("PRIVMSG " & ConnectionInformation.Channel & " :" & "Welcome, {0}", Split(address)))
End Sub
''' <summary>
''' Outputs a GUI message on user Quitting.
''' </summary>
''' <param name="address">The source of the user's local host.</param>
''' <remarks>
''' Displays an output message to the normalview window with correct format on user Quitting with Quit message.
''' </remarks>
Private Sub Quit(ByVal address As String)
Dim outputFortmat As String = String.Format("{0} has left the conversation.", Split(address))
OutputResponse(_window, outputFortmat, ColorUserEvent)
End Sub
Private Sub Disconnected()
Dim outputFortmat As String = "Disconnected!"
OutputResponse(_window, outputFortmat, Color.Red)
End Sub
Private Sub TopicOnjoin(ByVal subject As String)
OutputResponse(_window, String.Format("The chat's topic is: {0} ", subject), Color.Black)
NewLine()
End Sub
#End Region
#Region " Output Response "
''' <summary>
''' Displays the servers output response message.
''' </summary>
''' <param name="control">The control name.</param>
''' <param name="output">The server output.</param>
''' <param name="color">The control output line color</param>
''' <remarks>
''' Responsible for displaying all server and user response messages.
''' </remarks>
Public Sub OutputResponse(ByVal control As RichTextBox, ByVal output As String, ByVal color As Color)
Dim outputFormat As String = String.Format("{0}", output)
If control.InvokeRequired Then
control.Invoke(New OutputEventHandler(AddressOf OutputResponse), control, output, color)
Else
Dim start = control.TextLength
Dim length = outputFormat.Length
With control
.AppendText(outputFormat & Environment.NewLine)
.ScrollToCaret()
.Select(start, length)
.SelectionColor = color
End With
End If
End Sub
Private Sub NewLine()
If _window.InvokeRequired Then
_window.Invoke(New MethodInvoker(AddressOf NewLine))
Else
_window.AppendText(Environment.NewLine)
End If
End Sub
#End Region
#Region " Functions "
''' <summary>
'''
''' </summary>
''' <param name="s"></param>
''' <param name="instance"></param>
''' <returns></returns>
''' <remarks></remarks>
Private Function indexOf(ByVal s As String, ByVal instance As Integer) As Integer
Dim startAt As Integer = -1
For x As Integer = 1 To instance
startAt = s.IndexOf(" "c, startAt + 1)
Next
Return startAt
End Function
Private Function Split(ByVal name As String) As String
Return name.Split("!"c)(0)
End Function
#End Region
#Region " IDisposable "
Public Sub dispose() Implements IDisposable.Dispose
End Sub
#End Region
End Class
The part I am having a problem with is PrivMsg under the Region Private.
you could create a method on the form which receives a string to create a new LV item from the text passed:
Public Sub AddNewLVItem(txtName As String)
Dim LVI as New ListViewItem
LVI.Text = txtName
LVI.Group = xxx ' whatever other props there are
lstaccounts.items.Add(LVI)
End Sub
or shorthand, if there are no subitems, groups etc
lstaccounts.items.Add(New ListViewItem(txtName))
EDIT:
TYPICALLY, the form name is blank on MDI child forms only, I am not sure why that is the case here, but it obviously is. Forms are classes and SHOULD be instanced for use. They can use the old default instance method (FormName.Show) but that exists mainly for compatibility back to the VB4/5/6 days when forms were something apart from classes. The old default instance also makes it easier for tinkerers (non programmers) who dont have a clue about OOP, to get something woking easily.
First, you will need a reference to frmGiveAways with app level scope so that other classes all reference the same object. Add a module to your project (if there is not already one) and add:
Friend frmGive As frmGiveAways
(Or change the form name to something like FormGiveAways so the instance name and all the code referencing it can still use frmGiveAways).
Now, when you go to show the form in the menu:
If frmGive Is Nothing Then ' check to see if it already exists
frmGive = New frmGiveAways
frmGive.Show ' could be a separate 'If' if needed
End if
Now there is one instance of frmGiveAways using the reference frmGive and as long as everyone uses that reference, things will work fine. In the 'Sub AddEntry' it would pay to set a break and monitor the Me.Name value for a while to make sure all the calling code is properly refactored.
HTH
Instead of hard coding the listview, try passing it into the sub as a parameter.
Something like this:
Private Sub Privmsg(ByVal address As String, ByVal message As String, ByRef LV as ListView)
Dim outputFormat As String = String.Format("<{0}> {1}", Split(address), message)
OutputResponse(_window, outputFormat, Color.Black)
Select Case message
Case "" : _ircConnection.SendMessage(String.Format("PRIVMSG " & ConnectionInformation.Channel & " :" & "{0}", Split(address)))
Case frmGiveaways.keyword
_ircConnection.SendMessage(String.Format("PRIVMSG " & ConnectionInformation.Channel & " :" & "recieved keyword", Split(address)))
LV.Items.Add(Split(address))
End Select
End Sub
The basic syntax to add items to a ListView is this:
' Create list view items
Dim item1 As New ListViewItem("Item #1", 0)
Dim item2 As New ListViewItem("Item #2", 1)
Dim item3 As New ListViewItem("Item #3", 2)
Then you can add the list view items to the list view, either individually or as a group, like this:
Adding item one-by-one:
ListView1.Items.Add(item1)
ListView1.Items.Add(item2)
ListView1.Items.Add(item3)
Adding several items at once:
ListView1.Items.AddRange(New ListViewItem() {item1, item2, item3})
Note: The ListView1.Items.Add() and ListView1.Items.AddRange() methods both need ListViewItem objects, not string values.

Audio file class

I am using VB.net VS2012 and would like some help playing an Audio file.
Here is my code:
''' <summary>
''' This class is a wrapper for the Windows API calls to play wave, midi or mp3 files.
''' </summary>
''' <remarks>
''' </remarks>
Public Class AudioFile
'***********************************************************************************************************
' Class: PlayFile
' Written By: Blake Pell (bpell#indiana.edu)
' Initial Date: 03/31/2007
' Last Updated: 02/04/2009
'***********************************************************************************************************
' Windows API Declarations
Private Declare Function mciSendString Lib "winmm.dll" Alias "mciSendStringA" (ByVal lpstrCommand As String, ByVal lpstrReturnString As String, ByVal uReturnLength As Int32, ByVal hwndCallback As Int32) As Int32
''' <summary>
''' Constructor: Location is the filename of the media to play. Wave files and Mp3 files are the supported formats.
''' </summary>
''' <param name="Location"></param>
''' <remarks></remarks>
Public Sub New(ByVal location As String)
Me.Filename = location
End Sub
''' <summary>
''' Plays the file that is specified as the filename.
''' </summary>
''' <remarks></remarks>
Public Sub Play()
If _filename = "" Or Filename.Length <= 4 Then Exit Sub
Select Case Right(Filename, 3).ToLower
Case "mp3"
mciSendString("open """ & _filename & """ type mpegvideo alias audiofile", Nothing, 0, IntPtr.Zero)
Dim playCommand As String = "play audiofile from 0"
If _wait = True Then playCommand += " wait"
mciSendString(playCommand, Nothing, 0, IntPtr.Zero)
Case "wav"
mciSendString("open """ & _filename & """ type waveaudio alias audiofile", Nothing, 0, IntPtr.Zero)
mciSendString("play audiofile from 0", Nothing, 0, IntPtr.Zero)
Case "mid", "idi"
mciSendString("stop midi", "", 0, 0)
mciSendString("close midi", "", 0, 0)
mciSendString("open sequencer!" & _filename & " alias midi", "", 0, 0)
mciSendString("play midi", "", 0, 0)
Case Else
Throw New Exception("File type not supported.")
Call Close()
End Select
IsPaused = False
End Sub
''' <summary>
''' Pause the current play back.
''' </summary>
''' <remarks></remarks>
Public Sub Pause()
mciSendString("pause audiofile", Nothing, 0, IntPtr.Zero)
IsPaused = True
End Sub
''' <summary>
''' Resume the current play back if it is currently paused.
''' </summary>
''' <remarks></remarks>
Public Sub [Resume]()
mciSendString("resume audiofile", Nothing, 0, IntPtr.Zero)
IsPaused = False
End Sub
''' <summary>
''' Stop the current file if it's playing.
''' </summary>
''' <remarks></remarks>
Public Sub [Stop]()
mciSendString("stop audiofile", Nothing, 0, IntPtr.Zero)
End Sub
''' <summary>
''' Close the file.
''' </summary>
''' <remarks></remarks>
Public Sub Close()
mciSendString("close audiofile", Nothing, 0, IntPtr.Zero)
End Sub
Private _wait As Boolean = False
''' <summary>
''' Halt the program until the .wav file is done playing. Be careful, this will lock the entire program up until the
''' file is done playing. It behaves as if the Windows Sleep API is called while the file is playing (and maybe it is, I don't
''' actually know, I'm just theorizing). :P
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
Public Property Wait() As Boolean
Get
Return _wait
End Get
Set(ByVal value As Boolean)
_wait = value
End Set
End Property
''' <summary>
''' Sets the audio file's time format via the mciSendString API.
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
ReadOnly Property Milleseconds() As Integer
Get
Dim buf As String = Space(255)
mciSendString("set audiofile time format milliseconds", Nothing, 0, IntPtr.Zero)
mciSendString("status audiofile length", buf, 255, IntPtr.Zero)
buf = Replace(buf, Chr(0), "") ' Get rid of the nulls, they muck things up
If buf = "" Then
Return 0
Else
Return CInt(buf)
End If
End Get
End Property
''' <summary>
''' Gets the status of the current playback file via the mciSendString API.
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
ReadOnly Property Status() As String
Get
Dim buf As String = Space(255)
mciSendString("status audiofile mode", buf, 255, IntPtr.Zero)
buf = Replace(buf, Chr(0), "") ' Get rid of the nulls, they muck things up
Return buf
End Get
End Property
''' <summary>
''' Gets the file size of the current audio file.
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
ReadOnly Property FileSize() As Integer
Get
Try
Return My.Computer.FileSystem.GetFileInfo(_filename).Length
Catch ex As Exception
Return 0
End Try
End Get
End Property
''' <summary>
''' Gets the channels of the file via the mciSendString API.
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
ReadOnly Property Channels() As Integer
Get
Dim buf As String = Space(255)
mciSendString("status audiofile channels", buf, 255, IntPtr.Zero)
If IsNumeric(buf) = True Then
Return CInt(buf)
Else
Return -1
End If
End Get
End Property
''' <summary>
''' Used for debugging purposes.
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
ReadOnly Property Debug() As String
Get
Dim buf As String = Space(255)
mciSendString("status audiofile channels", buf, 255, IntPtr.Zero)
Return Str(buf)
End Get
End Property
Private _isPaused As Boolean = False
''' <summary>
''' Whether or not the current playback is paused.
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
Public Property IsPaused() As Boolean
Get
Return _isPaused
End Get
Set(ByVal value As Boolean)
_isPaused = value
End Set
End Property
Private _filename As String
''' <summary>
''' The current filename of the file that is to be played back.
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
Public Property Filename() As String
Get
Return _filename
End Get
Set(ByVal value As String)
If My.Computer.FileSystem.FileExists(value) = False Then
Throw New System.IO.FileNotFoundException
Exit Property
End If
_filename = value
End Set
End Property
End Class
This code works well. Can I please have some help to create an Event that will be called when the Audio file has finished playing. When an Audio file has finished, the 'Status' is 'Stopped'. How can I check to see when this happens and create an Event for it?
There doesn't seem to a way to register a callback for when the playback status changes, so you'll have to use an observer (i.e. a timer).
Private WithEvents StatusMonitor As New Timers.Timer(100)
Private Property LastStatus As String
Private Sub StatusMonitor_Elapsed(sender As Object, e As Timers.ElapsedEventArgs) Handles StatusMonitor.Elapsed
If Not String.Equals(Me.Status, Me.LastStatus) Then
Me.LastStatus = Me.Status
RaiseEvent PlaybackStatusChanged(Me, New PlaybackStatusChangedEventArgs(Me.Status))
End If
End Sub
Public Event PlaybackStatusChanged(sender As Object, e As PlaybackStatusChangedEventArgs)
Public Class PlaybackStatusChangedEventArgs
Inherits EventArgs
Private _status As String
Public Sub New(status As String)
_status = status
End Sub
Public ReadOnly Property Status As String
Get
Return _status
End Get
End Property
End Class
What this does is it stores the status in a private property and compares it to the current status every 100ms. If the status has changed, it fires the PlaybackStatusChanged event, along with arguments containing the new status. You can then listen for this event, and check e.Status in the event callback as if you were directly getting it from AudioFile.Status.
EDIT
After doing a couple of test runs, I've found that the status property behaves inconsistently. It seems to return a lot of whitespace as well, for reasons that I can't seem to figure out. Anyway, as a result, the status passed to the status event is wrong.
I'm not sure how to do that. But what you could do is this. On your main form, Dim a string like lol as string
Now for a button, set this code:
lol = "Audio file path goes here :3"
Dim audio As New AudioFile(lol)
Timer1.Start()
audio.Play()
Add a timer, and set its interval to 10.
For the timer code add this:
Dim audio As New AudioFile(lol)
If audio.Status.Contains("stopped") Then
audio.Play()
End If
That way, when the song is done playing, the timer will automatically start playing it again. And its set for the audio file that's on that variable, so just have the button set the path on that variable and boom. Your set.
Hope that helped...