file deletion exception on vb.net - vb.net

My VB.NET junk cleaner cannot delete aria-Debug-10144.log since it is used by another process.
I tried this:
Imports System.Collections.ObjectModel
Imports System.IO
Public Class Form1
Dim TempDirs As ReadOnlyCollection(Of String)
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
TempDirs = (My.Computer.FileSystem.GetDirectories("C:\Users\Aitor\AppData\Local\Temp"))
Dim ListDirs As List(Of String) = TempDirs.ToList
Dim directoryName As String = "C:\Users\Aitor\AppData\Local\Temp"
For Each deleteFile In Directory.GetFiles(directoryName, "*.*", SearchOption.TopDirectoryOnly)
If Not deleteFile.ToString = "aria-Debug-10144.log" Then
File.Delete(deleteFile)
End If
Next
MsgBox("Clean completed!", MsgBoxStyle.OkOnly + MsgBoxStyle.Information, "Results")
End Sub
End Class
But it still tries to do it.
Can anybody help me?

There are two reasons:
Firstly, the selected file is being occupied by another program. In this case, you need to determine whether the selected file is occupied before deleting it. Here is a small example.
Imports System.Runtime.InteropServices
Public Class Form1
<DllImport("kernel32.dll")>
Public Shared Function _lopen(ByVal lpPathName As String, ByVal iReadWrite As Integer) As IntPtr
End Function
<DllImport("kernel32.dll")>
Public Shared Function CloseHandle(ByVal hObject As IntPtr) As Boolean
End Function
Public Const OF_READWRITE As Integer = 2
Public Const OF_SHARE_DENY_NONE As Integer = &H40
Public Shared ReadOnly HFILE_ERROR As IntPtr = New IntPtr(-1)
Public Shared Function IsFileOccupied(ByVal filePath As String) As Boolean
Dim vHandle As IntPtr = _lopen(filePath, OF_READWRITE Or OF_SHARE_DENY_NONE)
CloseHandle(vHandle)
Return If(vHandle = HFILE_ERROR, True, False)
End Function
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
If (IsFileOccupied("C:\Users\juliex\AppData\Local\Temp\aria-debug-13836.log")) Then
MessageBox.Show("File is already occupied")
Else
MessageBox.Show("File is not occupied")
'Then do some delete operation.
End If
End Sub
End Class
Secondly, the selected file is a temporary file and is currently locked. If you want to clear the temporary files it owns, you need to have full control to unlock these files and then delete them!
You should be very careful if you want to delete the TEMP file, whether it is owned by the application or by another owner. The original application may have applied the lock because it wanted to use the file!
At this time you can refer to this link below:
1.How can I unlock a file that is locked by a process in .NET
2.https://social.msdn.microsoft.com/Forums/vstudio/en-US/9e2044c5-ae5d-4552-a335-01cc567dfc58/how-to-unlock-a-file-used-by-other-process?forum=csharpgeneral

Related

see what is attached to a com port and show in combo box

Using the code below I can create a box with a combo box that shows the current com ports
What I need to do is show what is attached to the com Port, for example I want it to list
COM PORT1 FTDI USB serial adapter, the reason is to let you the user know which port to enter in a batch file that runs when another button is clicked ( i have removed that part of the code as its not important)
I have done some google work and found this link http://social.msdn.microsoft.com/Forums/en-US/vbgeneral/thread/331a26c1-0f42-4cf1-8adb-32fb09a18953/ But that just errors out
Imports System
Imports System.Threading
Imports System.IO.Ports
Imports System.ComponentModel
Public Class Form1
'------------------------------------------------
Dim myPort As Array
Delegate Sub SetTextCallback(ByVal [text] As String) 'Added to prevent threading
errors during receiveing of data
'------------------------------------------------
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
myPort = IO.Ports.SerialPort.GetPortNames()
ComboBox1.Items.AddRange(myPort)
End Sub
End Class
The following shows how to get a list of COM devices in VB.NET for both .NET 6 and .NET Framework 4.8 in VS 2022. If a USB COM (serial port) device is added/removed, the ComboBox will be updated.
Option 1 - Windows Forms App: (.NET 6)
Create a new project: Windows Forms App (name: SerialPortGetComDevices)
Download/install the following NuGet packages:
System.IO.Ports
System.Management
Option 2 - Windows Forms App (.NET Framework) - v4.8:
Create a new project: Windows Forms App (.NET Framework) (name: SerialPortGetComDevices)
Add Reference:
In VS menu, click Project
Select Add Reference...
Select Assemblies
Check System.Management
Click OK
The instructions below are the same for both Windows Forms App and Windows Forms App (.NET Framework) (ie: the instructions below are the same regardless of which option you've chosen above).
Create a class (name: ComPortInfo.vb)
In VS menu, select Project
Select Add Class... (name: ComPortInfo.vb)
Click Add
ComPortInfo.vb:
Public Class ComPortInfo
Public Property Caption As String
Public Property PortName As String
End Class
Open Solution Explorer:
In VS menu, click View
Select Solution Explorer
Open Properties Window:
In VS menu, click View
Select Properties Window
Add Load Event Handler
In Solution Explorer, right-click Form1.vb and select View Designer.
In Properties Window, click
Double-click Load
Add FormClosing Event Handler
In Solution Explorer, right-click Form1.vb and select View Designer.
In Properties Window, click
Double-click FormClosing
Add a ComboBox to the Form (name: ComboBoxComPorts)
In VS menu, click View
Select Toolbox
In Toolbox, select ComboBox, and drag it to the Form.
In the Properties Window, change (Name) to ComboBoxComPorts
In the Properties Window, change DropDownStyle to DropDownList
Select one of the options below. The 1st option uses ManagementEventWatcher to detect USB device insertion and removal. The 2nd option overrides WndProc.
Note: The WndProc version (Option 2) seems to have slightly better performance.
Option 1 (ManagementEventWatcher)
Note: The code for detecting the insertion and removal of a USB device, is adapted from here.
Add the code below in your Form (ex: Form1.vb)
Form1.vb
Imports System.ComponentModel
Imports System.Management
Imports System.IO.Ports
Public Class Form1
'create new instance
Private _comPorts As BindingList(Of ComPortInfo) = New BindingList(Of ComPortInfo)
Private _managementEventWatcher1 As ManagementEventWatcher = New ManagementEventWatcher()
Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
InitializeManagementEventWatcher()
UpdateCOM()
'set properties
ComboBoxComPorts.DataSource = _comPorts
ComboBoxComPorts.DisplayMember = "Caption"
ComboBoxComPorts.ValueMember = "PortName"
End Sub
Private Sub GetComPorts()
'this method Is only called from 'UpdateCOM'
'_comPorts' is only modified in this method
Dim portDict As Dictionary(Of String, String) = New Dictionary(Of String, String)
'clear existing data
_comPorts.Clear()
'get port names
For Each pName As String In SerialPort.GetPortNames()
If Not portDict.ContainsKey(pName) Then
portDict.Add(pName, pName) 'add to Dictionary
End If
Next
'get USB COM ports - this may result in a more descriptive name than 'COM1'
Using searcherPnPEntity As ManagementObjectSearcher = New ManagementObjectSearcher("SELECT Name FROM Win32_PnPEntity WHERE PNPClass = 'Ports'")
For Each objPnPEntity As ManagementObject In searcherPnPEntity.Get()
If objPnPEntity Is Nothing Then
Continue For
End If
'get name
Dim name As String = objPnPEntity("Name")?.ToString()
If Not String.IsNullOrEmpty(name) AndAlso name.ToUpper().Contains("COM") Then
Dim portName As String = name.Substring(name.IndexOf("(") + 1, name.IndexOf(")") - name.IndexOf("(") - 1)
If Not portDict.ContainsKey(portName) Then
portDict.Add(portName, name) 'add to Dictionary
Else
portDict(portName) = name 'update value
End If
End If
Next
End Using
'add items from Dictionary to BindingList
For Each kvp As KeyValuePair(Of String, String) In portDict
_comPorts.Add(New ComPortInfo() With {.Caption = kvp.Value, .PortName = kvp.Key}) 'add
Next
End Sub
Private Sub InitializeManagementEventWatcher()
'see https:'learn.microsoft.com/en-us/windows/win32/wmisdk/within-clause
'WITHIN sets the polling interval in seconds
'polling too frequently may reduce performance
Dim query As WqlEventQuery = New WqlEventQuery("SELECT * FROM __InstanceOperationEvent WITHIN 2 WHERE TargetInstance ISA 'Win32_PnPEntity'")
'Dim query As WqlEventQuery = New WqlEventQuery("SELECT * FROM __InstanceOperationEvent WITHIN 1 WHERE TargetInstance ISA 'Win32_PnPEntity'")
'set property
_managementEventWatcher1.Query = query
'subscribe to event
AddHandler _managementEventWatcher1.EventArrived, AddressOf ManagementEventWatcher_EventArrived
'start
_managementEventWatcher1.Start()
End Sub
Private Sub LogMsg(msg As String, Optional includeTimestamp As Boolean = True)
If includeTimestamp Then
msg = $"{DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss.fff")} - {msg}"
End If
Debug.WriteLine(msg)
End Sub
Public Sub UpdateCOM()
If ComboBoxComPorts.InvokeRequired Then
'LogMsg("ComboBoxComPorts.InvokeRequired")
ComboBoxComPorts.Invoke(New MethodInvoker(Sub()
GetComPorts()
End Sub))
Else
GetComPorts()
End If
End Sub
Public Sub ManagementEventWatcher_EventArrived(sender As Object, e As EventArrivedEventArgs)
Dim obj As ManagementBaseObject = DirectCast(e.NewEvent, ManagementBaseObject)
Dim target As ManagementBaseObject = If(obj("TargetInstance") IsNot Nothing, DirectCast(obj("TargetInstance"), ManagementBaseObject), Nothing)
Dim usbEventType As String = String.Empty
Select Case target.ClassPath.ClassName
Case "__InstanceCreationEvent"
usbEventType = "added"
Case "__InstanceDeletionEvent"
usbEventType = "removed"
Case Else
usbEventType = target.ClassPath.ClassName
End Select
If target("PNPClass") IsNot Nothing AndAlso target("PNPClass").ToString() = "Ports" Then
'update COM ports
UpdateCOM()
End If
End Sub
Private Sub Form1_FormClosing(sender As Object, e As FormClosingEventArgs) Handles MyBase.FormClosing
'stop
_managementEventWatcher1.Stop()
'unsubscribe from event
RemoveHandler _managementEventWatcher1.EventArrived, AddressOf ManagementEventWatcher_EventArrived
End Sub
End Class
Option 2 (override WndProc)
Note: The code for detecting the insertion and removal of a USB device, is adapted from here.
Add a Module (name: UsbDeviceNotification.vb)
In VS menu, select Project
Select Add Module... (name: UsbDeviceNotification.vb)
Click Add
UsbDeviceNotification.vb
Imports System.Runtime.InteropServices
Module UsbDeviceNotification
Public Const DbtDeviceArrival As Integer = &H8000 'device added
Public Const DbtDeviceRemoveComplete As Integer = &H8004 'device removed
Public Const WM_DEVICECHANGE As Integer = &H219 'device change event
Public Const DBT_DEVTYP_DEVICEINTERFACE As Integer = 5
Private ReadOnly _guidDevInterfaceUSBDevice As Guid = New Guid("A5DCBF10-6530-11D2-901F-00C04FB951ED") 'USB devices
Private _notificationHandle As IntPtr
Declare Auto Function RegisterDeviceNotification Lib "user32" (recipient As IntPtr, notificationFilter As IntPtr, flags As Integer) As IntPtr
Declare Auto Function UnregisterDeviceNotification Lib "user32" (hwnd As IntPtr) As Boolean
<StructLayout(LayoutKind.Sequential)>
Private Structure DEV_BROADCAST_DEVICEINTERFACE
Dim Size As Integer
Dim DeviceType As Integer
Dim Reserved As Integer
Dim ClassGuid As Guid
Dim Name As Short
End Structure
Public Sub RegisterUsbDeviceNotification(hwnd As IntPtr)
'Registers a window to receive notifications when USB devices are plugged or unplugged.
Dim dbi As DEV_BROADCAST_DEVICEINTERFACE = New DEV_BROADCAST_DEVICEINTERFACE() With
{
.DeviceType = DBT_DEVTYP_DEVICEINTERFACE,
.ClassGuid = _guidDevInterfaceUSBDevice
}
dbi.Size = Marshal.SizeOf(dbi)
Dim buffer As IntPtr = Marshal.AllocHGlobal(dbi.Size)
Marshal.StructureToPtr(dbi, buffer, True)
_notificationHandle = RegisterDeviceNotification(hwnd, buffer, 0)
End Sub
Public Sub UnregisterUsbDeviceNotification()
UnregisterDeviceNotification(_notificationHandle)
End Sub
End Module
Add the code below in your Form (ex: Form1.vb)
Form1.vb
Imports System.ComponentModel
Imports System.Management
Imports System.IO.Ports
Imports System.Threading
Public Class Form1
'create new instance
Private _comPorts As BindingList(Of ComPortInfo) = New BindingList(Of ComPortInfo)
Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
UpdateCOM()
'set properties
ComboBoxComPorts.DataSource = _comPorts
ComboBoxComPorts.DisplayMember = "Caption"
ComboBoxComPorts.ValueMember = "PortName"
End Sub
Private Sub GetComPorts()
'this method Is only called from 'UpdateCOM'
'_comPorts' is only modified in this method
Dim portDict As Dictionary(Of String, String) = New Dictionary(Of String, String)
'clear existing data
_comPorts.Clear()
'get port names
For Each pName As String In SerialPort.GetPortNames()
If Not portDict.ContainsKey(pName) Then
portDict.Add(pName, pName) 'add to Dictionary
End If
Next
'get USB COM ports - this may result in a more descriptive name than 'COM1'
Using searcherPnPEntity As ManagementObjectSearcher = New ManagementObjectSearcher("SELECT Name FROM Win32_PnPEntity WHERE PNPClass = 'Ports'")
If searcherPnPEntity IsNot Nothing Then
For Each objPnPEntity As ManagementBaseObject In searcherPnPEntity.Get()
If objPnPEntity Is Nothing Then
Continue For
End If
'get name
Dim name As String = objPnPEntity("Name")?.ToString()
If Not String.IsNullOrEmpty(name) AndAlso name.ToUpper().Contains("COM") Then
Dim portName As String = name.Substring(name.IndexOf("(") + 1, name.IndexOf(")") - name.IndexOf("(") - 1)
If Not portDict.ContainsKey(portName) Then
portDict.Add(portName, name) 'add to Dictionary
Else
portDict(portName) = name 'update value
End If
End If
Next
End If
End Using
'add items from Dictionary to BindingList
For Each kvp As KeyValuePair(Of String, String) In portDict
_comPorts.Add(New ComPortInfo() With {.Caption = kvp.Value, .PortName = kvp.Key}) 'add
Next
End Sub
Private Sub LogMsg(msg As String, Optional includeTimestamp As Boolean = True)
If includeTimestamp Then
msg = $"{DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss.fff")} - {msg}"
End If
Debug.WriteLine(msg)
End Sub
Public Sub UpdateCOM()
'since this method/Sub is called from WndProc,
'it needs to run on a new thread
Dim threadProc As System.Threading.Thread = New System.Threading.Thread(Sub()
If ComboBoxComPorts.InvokeRequired Then
'LogMsg("ComboBoxComPorts.InvokeRequired")
ComboBoxComPorts.Invoke(New MethodInvoker(Sub()
GetComPorts()
End Sub))
Else
GetComPorts()
End If
End Sub)
threadProc.SetApartmentState(System.Threading.ApartmentState.STA)
threadProc.Start()
End Sub
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
If m.Msg = UsbDeviceNotification.WM_DEVICECHANGE Then
Select Case CInt(m.WParam)
Case UsbDeviceNotification.DbtDeviceRemoveComplete
UpdateCOM()
Case UsbDeviceNotification.DbtDeviceArrival
UpdateCOM()
End Select
End If
MyBase.WndProc(m)
End Sub
Private Sub Form1_FormClosing(sender As Object, e As FormClosingEventArgs) Handles MyBase.FormClosing
End Sub
End Class
The following PowerShell commands may also provide useful information.
PowerShell:
Get-CimInstance -Namespace Root\Cimv2 -Query "Select * From Win32_SerialPort Where Name like '%COM%'"
Get-CimInstance -Namespace Root\Cimv2 -Query "Select * From Win32_SerialPortConfiguration"
Get-CimInstance -Namespace Root\Cimv2 -Query "Select * From Win32_PnPEntity where PnPClass = 'Ports' and Name like '%COM%'"
mode
Resources:
System.IO.Ports Namespace
SerialPort Class
BindingList Class
ManagementEventWatcher Class
WITHIN Clause
Detecting USB drive insertion and removal using windows service and c#
Check for device change (add/remove) events
ComboBox Class
Dictionary<TKey,TValue> Class
ManagementObjectSearcher Class
ManagementObject Class
Win32_PnPEntity class
For...Next Statement (Visual Basic)
If Operator (Visual Basic)

store setting in relative path to executable aplication

I am developing an application to run from USB, is it like a dock/launcher application but I have a problem.
I want to use My.Settings class to save my app settings, but it saves the setting file in AppData folder e.g. C:\Users\<user_name>\AppData\Local\...\...\user.config
I don't want that. I want to save in a path and name of my defined, e.g. My.Application.Info.DirectoryPath & "\Settings.xml"
How can I achieve this?
Update Example of final XML:
<?xml version="1.0" encoding="utf-8"?>
<conf>
<pos>1</pos>
<btn index="1" value="D:\League of Legends\" perm="true">LeagueClient.exe</btn>
<btn index="2" value="D:\RuneLite\" perm="false">RuneLite.exe</btn>
<btn index="3" value="" perm="false"></btn>
<btn index="4" value="" perm="false"></btn>
</conf>
Full project in Github coming soon!!!
Work way for me :
Imports System.IO
Imports System.Xml
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
ValConfFile()
End Sub
Public Sub ValConfFile()
If File.Exists("config.xml") = False Then : CreateConfXML() : End If
End Sub
Public Sub CreateConfXML()
Dim obj As Object
Dim archivo As Object
Dim x As Integer = 1
obj = CreateObject("Scripting.FileSystemObject")
archivo = obj.CreateTextFile("config.xml", True)
archivo.WriteLine("<?xml version='1.0' encoding='utf-8'?>")
archivo.WriteLine("<conf>")
archivo.WriteLine("<pos>1</pos>")
For x = 1 To 4
archivo.WriteLine("<btn index='" & CStr(x) & "' value='' perm='false'></btn>")
Next
archivo.WriteLine("</conf>")
archivo.Close()
End Sub
End Class
XML Serialization can be used for this, and is actually fairly straightforward. All you need to do is design one or more classes for your data, then apply the appropriate attributes (their name are in the form Xml...Attribute) in order to serialize them the way you want.
In this setup I've used four different attributes:
XmlElement - Usually the most common one. Specifies that a property will be serialized as an element of its own. The resulting name can be customized by setting the ElementName parameter in the constructor.
If used on lists or arrays, it applies to each item in the collection.
XmlRoot - Pretty much the same as XmlElement, but used for the root element (the class itself).
XmlAttribute - Specifies that a property will be serialized as an attribute (name="value") applied to the parent object, instead of as an element inside it.
XmlText - Specifies that a property's value will be serialized as the contents between the tags of the parent object (i.e. <object>property value</object>).
Imports System.IO
Imports System.Xml
Imports System.Xml.Serialization
<XmlRoot(ElementName:="conf")>
Public Class Config
<XmlElement(ElementName:="pos")>
Public Property Position As Integer
<XmlElement(ElementName:="btn")>
Public Property Buttons As New List(Of ConfigButton)
Public Sub New()
End Sub
Public Sub New(ByVal Position As Integer)
Me.Position = Position
End Sub
Public Shared Function Load(ByVal File As String) As Config
Using FStream As New FileStream(File, FileMode.Open, FileAccess.Read, FileShare.Read)
Dim Serializer As New XmlSerializer(GetType(Config))
Return Serializer.Deserialize(FStream)
End Using
End Function
Public Sub Save(ByVal File As String)
Using FStream As New FileStream(File, FileMode.Create, FileAccess.Write, FileShare.None)
Dim Serializer As New XmlSerializer(GetType(Config))
Serializer.Serialize(FStream)
End Using
End Sub
End Class
Public Class ConfigButton
<XmlText()>
Public Property DisplayName As String
<XmlAttribute("index")>
Public Property Index As Integer
<XmlAttribute("perm")>
Public Property Perm As Boolean
<XmlAttribute("value")>
Public Property Value As String
Public Sub New()
End Sub
Public Sub New(ByVal DisplayName As String, ByVal Value As String, ByVal Index As Integer, ByVal Perm As Boolean)
Me.DisplayName = DisplayName
Me.Value = Value
Me.Index = Index
Me.Perm = Perm
End Sub
End Class
Usage example:
Private cfg As Config
'
'Loading the config.
'
Private Sub Form1_Load(sender As Object, e As EventArgs) Handled MyBase.Load
If File.Exists("config.xml") Then
cfg = Config.Load("config.xml")
Else
cfg = New Config()
End If
End Sub
'
'Saving the config.
'
Private Sub Form1_FormClosed(sender As Object, e As EventArgs) Handles Me.FormClosed
cfg.Save("config.xml")
End Sub
Adding a button:
cfg.Buttons.Add(New ConfigButton("RuneLite.exe", "D:\RuneLite\", 2, False))
Iterating buttons:
For Each btn As ConfigButton In cfg.Buttons
MessageBox.Show(btn.DisplayName)
Next
Removing a button at a specific index:
'Removes the fourth button.
cfg.Buttons.RemoveAt(3)

VB.net - How can a definition at module level throw an exception

I was beginning to think that I was getting good at VB.net, but not this one has me stumped.
Code looks something like this
Public Class MyServer
.....
Public myMQTTclient = New MqttClient("www.myserv.com")
.....
Private Sub Ruptela_Server(sender As Object, e As EventArgs) Handles
MyBase.Load
<some code>
StartMQTT()
<some more code>
MQTT_Publish(.....)
End Sub
Public Function StartMQTT()
' Establish a connection
Dim code As Byte
Try
code = myMQTTclient.Connect(MQTT_ClientID)
Catch ex As Exception
<error handling code>
End Try
Return code
End Function
Public Sub MQTT_Publish(ByVal DeviceID As String, ByVal Channel As String, ByVal ChannelType As String, ByVal Value As String, ByVal Unit As String)
Dim myTopic As String = "MyTopic"
Dim myPayload As String = "My Payload"
Dim msgId As UShort = myMQTTclient.Publish(myTopic, Encoding.UTF8.GetBytes(myPayload), MqttMsgBase.QOS_LEVEL_EXACTLY_ONCE, False)
End Sub
As this stands it works 100% OK. The coding may seem a bit odd, but the intent is as follows :
a) create an object 'myMQTTclient' at module level so it has scope throughout the module
b) run StartMQTT() - It can still see the object.
c) within main program call MQTT_Publish many times - I can still see the object
Now the issue is this... it all goes well until "www.myserv.com" fails DNS, then the underlying winsock code throws an exception.
So ... I'm thinking - no problem - just wrap the declaration in a try block or check that www.myserv.com exists before launching the declaration.
Ah, but you can't put code at module level, it has to be in a sub or function.
Hmmm... now I'm stumped. There has to be a 'proper' way to do this, but I'll be darned if I can figure it out.
Anyone able to help ?
I'd follow the advice from #djv about declaring it just as you need it. To wrap that in a Try... Catch block you can do that in an Init method.
Public Class MyServer
Implements IDisposable ' As per djv recommendation which I second...
Private myMQQTclient As MqttClient
Public Sub Init()
Try
myMQQTClient = New MqttClient("<your url>")
Catch ex As Exception
' Do whatever
End Try
End Sub
' more code and implement the Dispose method...
End Class
You can then go on and implement the IDisposble interface to ensure that you release the resources.
Ok, I am not sure if I have the right library. But I found this Nuget package: OpenNETCF.MQTT which seems to have the class you are using.
I would do it this way
Public Class MyServerClass
Implements IDisposable
Public myMQTTclient As MQTTClient
'Private Sub Ruptela_Server(sender As Object, e As EventArgs) Handles MyBase.Load
' ' <some code>
' StartMQTT()
' ' <some more code>
' ' MQTT_Publish(.....)
'End Sub
Public Sub New(brokerHostName As String)
myMQTTclient = New MQTTClient(brokerHostName)
End Sub
Public Function StartMQTT()
' Establish a connection
Dim code As Byte
Try
code = myMQTTclient.Connect(MQTT_ClientID)
Catch ex As Exception
'<error handling code>
End Try
Return code
End Function
Public Sub MQTT_Publish(ByVal DeviceID As String, ByVal Channel As String, ByVal ChannelType As String, ByVal Value As String, ByVal Unit As String)
Dim myTopic As String = "MyTopic"
Dim myPayload As String = "My Payload"
Dim msgId As UShort = myMQTTclient.Publish(myTopic, Encoding.UTF8.GetBytes(myPayload), MqttMsgBase.QOS_LEVEL_EXACTLY_ONCE, False)
End Sub
#Region "IDisposable Support"
Private disposedValue As Boolean
Protected Overridable Sub Dispose(disposing As Boolean)
If Not disposedValue Then
If disposing Then
myMQTTclient.Dispose()
End If
End If
disposedValue = True
End Sub
Public Sub Dispose() Implements IDisposable.Dispose
Dispose(True)
End Sub
#End Region
End Class
And now you can see the usage when IDisposable is implemented, in a Using block:
Module Module1
Sub Main()
Using myserver As New MyServerClass("www.myserv.com")
myserver.StartMQTT()
myserver.MQTT_Publish(...)
End Using
End Sub
End Module
This makes it so your object is only in scope in the Using, and the object's Dispose method will automatically be called on End Using
I don't know what the base class was originally and why this was declared Private Sub Ruptela_Server(sender As Object, e As EventArgs) Handles MyBase.Load. It seems like it was possibly a form? You should keep your server code separate from Form code if that was the case. I suppose you could paste the Using into your form load, but then you would be blocking your UI thread. The referenced library has Async support so it might be a good idea to leverage that if coming from a UI.
I've made many assumptions, so I'll stop to let you comment and see how close relevant my answer is.

Using a datagridview to add records

I am using VS2008/.net fw 3.5sp1 and back into the coding life - and a little rusty to say the least :) Any help on the below would be great please.
I need to gather a list of input from a user, that I will work with later (pass to a teradata DWH with some other values). The input list involves two parts, a BSB ID and an Account ID. After some research it looks like the best option would be to create a class for the accounts, a list of accounts and bind that to a datagridview - of which I have done - but it looks like I can't add/edit. I have added a new button/add button to alter the data grid and get an error that I cannot programmatically add.
When I use accountList.AllowNew() = TRUE -- Error -- constructor on type bankaccount not found - but - I thought the constructor is the "new" sub in the class?
When I try accountsBindingSource.IsFixedSize = False it advises the property is read only.
For this - I've cut all the other code out to just this section, which requires one form (frmAccountLoad), with a datagridview dgvAccounts and a button btnNewLine.
Imports System
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.Data
Imports System.Data.Common
Imports System.Diagnostics
Imports System.Drawing
Imports System.Data.SqlClient
Imports System.Windows.Forms
'--------------------------------------------------------------------
Public Class frmAccountLoad
' This BindingSource binds the list to the DataGridView control.
Private accountsBindingSource As New BindingSource()
Private Sub frmAccountLoad_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
'Create list to hold accounts
Dim accountList As New BindingList(Of BankAccount)
accountList.AllowNew() = True
'accountList.AllowEdit = True
accountsBindingSource.DataSource = accountList
dgvAccounts.DataSource = accountsBindingSource
'dgvAccounts.Columns(0).HeaderText = "BSB"
'dgvAccounts.Columns(1).HeaderText = "Account"
End Sub
Private Sub btnNewLine_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnNewLine.Click
'accountsBindingSource.IsFixedSize = False
accountsBindingSource.AddNew()
End Sub
End Class
'--------------------------------------------------------------------
Public Class BankAccount
'----------------------------------------------------------
'a bank account has both a BSB and an account number
Private m_BSB As String
Private m_Account As String
'----------------------------------------------------------
'Public Property
Public Property BSB() As String
Get
Return m_BSB
End Get
Set(ByVal value As String)
m_BSB = value
End Set
End Property
Public Property Account() As String
Get
Return m_Account
End Get
Set(ByVal value As String)
m_Account = value
End Set
End Property
'----------------------------------------------------------
Public Sub New(ByVal new_Bsb As String, ByVal new_Account As String)
m_BSB = new_Bsb
m_Account = new_Account
End Sub
End Class
To be able to call AddNew on your BindingList the BankAccount should have a parameter-less constructor.
You need to have a public parameter-less constructor if you need some initialization, or just remove any constructor if you don't need initialization, then the default parameter-less constructor will be used.
Public Class BankAccount
Public Property BSB As String
Public Property Account As String
Public Sub New()
'Do initialization here if you need
'Or Remove the constructor if you don't need any initialization.
End Sub
End Class
Also you don't need to set accountList.AllowNew = True. It's enough to use a BindingList(Of T) as DataSource.
Private accountList As BindingList(Of BankAccount)
Private Sub frmAccountLoad_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
accountList = New BindingList(Of BankAccount)
dgvAccounts.DataSource = BS
End Sub
Then you can call accountList.AddNew() wherever you need.

VB.NET Class with no constructor (no new instance can be declared)

I'm making my own message box class (called MessageBoxC, whatever), and like System.Windows.Forms.MessageBox, I want to make my class with no constructors and no possibility to declare a new instance of it.
E.g.:
Public Class MessageBoxC
Public Overloads Sub Show(ByVal message As String)
Me.Message = message
ProcessData() '(*)
Me.ShowDialog()
End Sub
End Class
Public Class Form1
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
System.Windows.Forms.MessageBox.Show("Hello World!") 'works fine
MessageBoxC.Show("Hello World!") 'works fine
Dim msgBox As New System.Windows.Forms.MessageBox 'and you'll get an error message here (**)
Dim msgBoxC As New MessageBoxC 'no error message
End Sub
End Class
(*) Not important. It just calculates text size (width and height in pixels) to correct form size if needed and the corresponding label gets value of Me.Message property.
(**) This one is what I mean. You cannot make a new instance of a MessageBox class, you'll get following error-message: "Type System.Windows.Forms.MessageBox has no constructors."
Well, my class has also no constructors, but it's possible to declare an instance of it. What's the trick here?
Thanks a lot!
Solved. Thanks to OneFineDay.
Public Class MessageBoxC
Private Sub New()
'Empty
End Sub
Public Overloads Shared Function Show(ByVal message As String) As System.Windows.Forms.DialogResult
Return Show(message, Constants.MyAppName, Constants.messageTitle, MessageBoxCButtons.OK, MessageBoxCIcon.Undefined)
End Function
Public Overloads Shared Function Show(ByVal message As String, _
ByVal caption As String, _
ByVal title As String, _
ByVal buttons As Library.MessageBoxCButtons, _
ByVal icon As Library.MessageBoxCIcon) As System.Windows.Forms.DialogResult
Dim msgBoxC As New CBox(message, caption, title, buttons, icon)
msgBoxC.ShowDialog()
Return msgBoxC.DialogResult
End Function
Private Class CBox
Inherits System.Windows.Forms.Form
Sub New(ByVal message As String, _
ByVal caption As String, _
ByVal title As String, _
ByVal buttons As Library.MessageBoxCButtons, _
ByVal icon As Library.MessageBoxCIcon)
MyBase.New()
InitializeComponent()
Me.Message = message
Me.Text = caption
Me.Title = title
Me.Buttons = buttons
Me.Icon64 = icon
Me.OptimizeMe()
End Sub
End Class
End Class
Public Class Form1
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
Dim dialogResult As New DialogResult
dialogResult = MessageBoxC.Show("This is a simple message.")
MessageBox.Show(dialogResult.ToString)
End Sub
End Class
If you don't declare any constructors, a default constructor is automatically created (this is a public constructor with no parameters).
To prevent anyone creating an instance of your class, you can create a private constructor, like so:
Public Class MessageBoxC
Private Sub New()
' Prevents anyone creating an instance of this class.
End Sub
End Class
Note that your Show method will need to be declared Shared, otherwise you won't be able to call it. In fact, it would need to be Shared, even with the code you provided.
Here is one way to hide the constructor - mainly because the class in question is not accessible.
Public Class Form1
Private Sub meLoad() Handles Me.Load
'Usage
FooBar.Show("Hi")
End Sub
'...
End Class
Public Class FooBar
Private Sub New()
End Sub
Public Shared Sub Show(message As String)
Dim mbc As New MessageBoxC(message)
mbc.ShowDialog()
End Sub
'MessageBoxC is not exposed outside of Foobar which is the entry point
Private Class MessageBoxC : Inherits Form
'define cTor's as needed
Public Sub New(message As String)
Me.Text = message
End Sub
'define content
End Class
End Class