ErrorMeldung -> Screenshot und SystemEnviroment wird mitgeschickt.

This commit is contained in:
2023-11-23 15:40:46 +01:00
parent 59add26515
commit a6f262304e
4 changed files with 204 additions and 24 deletions

View File

@@ -1,15 +1,30 @@
Imports System.Net.Mail Imports System.Drawing
Imports System.Drawing.Imaging
Imports System.Net.Mail
Imports System.Windows.Forms
Public Class cErrorHandler Public Class cErrorHandler
Public Shared Sub ERR(message As String, stack As String, functionName As String, Optional OP As String = "", Optional title As String = "", Optional mailadess As String = "al@verag.ag", Optional recieverMailAdress As String = "", Optional zusatz As String = "", Optional errCode As String = Nothing) Public Shared Sub ERR(message As String, stack As String, functionName As String, Optional OP As String = "", Optional title As String = "", Optional mailadess As String = "al@verag.ag", Optional recieverMailAdress As String = "", Optional zusatz As String = "", Optional errCode As String = Nothing)
If OP = "" Then OP = VERAG_PROG_ALLGEMEIN.cAllgemein.ERR_OP_GLOBAL ' GLobal gesetzes Errorhandling! (Standart=SHOW) If OP = "" Then OP = VERAG_PROG_ALLGEMEIN.cAllgemein.ERR_OP_GLOBAL ' GLobal gesetzes Errorhandling! (Standart=SHOW)
'If Form.ActiveForm IsNot Nothing Then
' Dim bm As New Bitmap(Form.ActiveForm.Width, Form.ActiveForm.Height)
' Dim g As Graphics = Graphics.FromImage(bm)
' g.CopyFromScreen(Form.ActiveForm.Location, New Point(0, 0), New Size(Form.ActiveForm.Width, Form.ActiveForm.Height))
' bm.Save("C:\formgrab.bmp", Drawing.Imaging.ImageFormat.Bmp)
'End If
Select Case OP Select Case OP
Case ERROR_OP.MAIL Case ERROR_OP.MAIL
sendERRORperMail(title & " | " & My.Application.Info.AssemblyName, message, stack, mailadess, zusatz, functionName) sendERRORperMail(title & " | " & My.Application.Info.AssemblyName, message, stack, mailadess, zusatz, functionName)
Case ERROR_OP.SHOW Case ERROR_OP.SHOW
Dim f As New frmErrorMeldung(If(functionName <> "", "Fehler in der Funktion '" & functionName & "'" & vbNewLine & vbNewLine, "") & message & vbNewLine & zusatz, stack, title) Dim c As New cProgramFunctions
Dim url = c.MakeScreenshot()
Dim f As New frmErrorMeldung(If(functionName <> "", "Fehler in der Funktion '" & functionName & "'" & vbNewLine & vbNewLine, "") & message & vbNewLine & zusatz, stack, title, url)
f.ShowDialog() f.ShowDialog()
Case ERROR_OP.SHOW_MSGBOX Case ERROR_OP.SHOW_MSGBOX
MsgBox(If(functionName <> "", "Fehler in der Funktion '" & functionName & "'" & vbNewLine & vbNewLine, "") & message & vbNewLine & stack & vbNewLine & zusatz, MsgBoxStyle.OkOnly, If(title <> "", title, "Fehler")) MsgBox(If(functionName <> "", "Fehler in der Funktion '" & functionName & "'" & vbNewLine & vbNewLine, "") & message & vbNewLine & stack & vbNewLine & zusatz, MsgBoxStyle.OkOnly, If(title <> "", title, "Fehler"))

View File

@@ -1,4 +1,5 @@
Imports System.IO Imports System.Drawing
Imports System.IO
Imports System.Net.Mail Imports System.Net.Mail
Imports System.Text Imports System.Text
Imports System.Windows.Forms Imports System.Windows.Forms
@@ -534,6 +535,35 @@ Public Class cProgramFunctions
End Function End Function
Public Function MakeScreenshot()
Dim form As New Form
form = Form.ActiveForm
Dim bounds As Rectangle
Dim screenshot As System.Drawing.Bitmap
Dim graph As Graphics
bounds = form.Bounds 'Screen.PrimaryScreen.Bounds
screenshot = New System.Drawing.Bitmap(bounds.Width, bounds.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb)
graph = Graphics.FromImage(screenshot)
graph.CopyFromScreen(bounds.X, bounds.Y, 0, 0, bounds.Size, CopyPixelOperation.SourceCopy)
' PictureBox1.Image = screenshot
If Not My.Computer.FileSystem.DirectoryExists(My.Computer.FileSystem.SpecialDirectories.Desktop & "\Screenshots_" & My.Application.Info.AssemblyName & "\") Then
My.Computer.FileSystem.CreateDirectory(My.Computer.FileSystem.SpecialDirectories.Desktop & "\Screenshots_" & My.Application.Info.AssemblyName & "\")
End If
Dim cnt As Integer = 1
Dim strname As String = My.Computer.FileSystem.SpecialDirectories.Desktop & "\Screenshots_" & My.Application.Info.AssemblyName & "\" & form.Name & "_" & Now.ToString("ddMMyyyy_HHmm_")
While System.IO.File.Exists(strname & cnt & ".bmp") : cnt += 1 : End While
screenshot.Save(strname & cnt & ".bmp")
Return strname & cnt & ".bmp"
End Function
Public Function TakeScreenShot(ByVal Control As Control) As Bitmap
Dim tmpImg As New Bitmap(Control.Width, Control.Height)
Using g As Graphics = Graphics.FromImage(tmpImg)
g.CopyFromScreen(Control.PointToScreen(New Point(0, 0)), New Point(0, 0), New Size(Control.Width, Control.Height))
End Using
Return tmpImg
End Function
End Class End Class

View File

@@ -29,14 +29,16 @@ Partial Class frmErrorMeldung
Me.Label2 = New System.Windows.Forms.Label() Me.Label2 = New System.Windows.Forms.Label()
Me.Panel1 = New System.Windows.Forms.Panel() Me.Panel1 = New System.Windows.Forms.Panel()
Me.Panel2 = New System.Windows.Forms.Panel() Me.Panel2 = New System.Windows.Forms.Panel()
Me.lblErr_Nachricht = New System.Windows.Forms.Label()
Me.Button2 = New System.Windows.Forms.Button() Me.Button2 = New System.Windows.Forms.Button()
Me.txtNachricht = New System.Windows.Forms.TextBox() Me.txtNachricht = New System.Windows.Forms.TextBox()
Me.Label3 = New System.Windows.Forms.Label() Me.Label3 = New System.Windows.Forms.Label()
Me.lblErr_Nachricht = New System.Windows.Forms.Label()
Me.MyPanel2 = New VERAG_PROG_ALLGEMEIN.MyPanel(Me.components) Me.MyPanel2 = New VERAG_PROG_ALLGEMEIN.MyPanel(Me.components)
Me.MyPanel1 = New VERAG_PROG_ALLGEMEIN.MyPanel(Me.components) Me.MyPanel1 = New VERAG_PROG_ALLGEMEIN.MyPanel(Me.components)
Me.btnClose = New System.Windows.Forms.Button() Me.btnClose = New System.Windows.Forms.Button()
Me.TextBox2 = New System.Windows.Forms.TextBox() Me.TextBox2 = New System.Windows.Forms.TextBox()
Me.cbxEnviromentVariables = New System.Windows.Forms.CheckBox()
Me.cbxScreenshot = New System.Windows.Forms.CheckBox()
CType(Me.PictureBox1, System.ComponentModel.ISupportInitialize).BeginInit() CType(Me.PictureBox1, System.ComponentModel.ISupportInitialize).BeginInit()
Me.Panel1.SuspendLayout() Me.Panel1.SuspendLayout()
Me.Panel2.SuspendLayout() Me.Panel2.SuspendLayout()
@@ -85,22 +87,35 @@ Partial Class frmErrorMeldung
Me.Panel1.Dock = System.Windows.Forms.DockStyle.Fill Me.Panel1.Dock = System.Windows.Forms.DockStyle.Fill
Me.Panel1.Location = New System.Drawing.Point(0, 0) Me.Panel1.Location = New System.Drawing.Point(0, 0)
Me.Panel1.Name = "Panel1" Me.Panel1.Name = "Panel1"
Me.Panel1.Size = New System.Drawing.Size(500, 449) Me.Panel1.Size = New System.Drawing.Size(500, 463)
Me.Panel1.TabIndex = 8 Me.Panel1.TabIndex = 8
' '
'Panel2 'Panel2
' '
Me.Panel2.BackColor = System.Drawing.Color.WhiteSmoke Me.Panel2.BackColor = System.Drawing.Color.WhiteSmoke
Me.Panel2.Controls.Add(Me.cbxScreenshot)
Me.Panel2.Controls.Add(Me.cbxEnviromentVariables)
Me.Panel2.Controls.Add(Me.lblErr_Nachricht) Me.Panel2.Controls.Add(Me.lblErr_Nachricht)
Me.Panel2.Controls.Add(Me.Button2) Me.Panel2.Controls.Add(Me.Button2)
Me.Panel2.Controls.Add(Me.txtNachricht) Me.Panel2.Controls.Add(Me.txtNachricht)
Me.Panel2.Controls.Add(Me.Label3) Me.Panel2.Controls.Add(Me.Label3)
Me.Panel2.Dock = System.Windows.Forms.DockStyle.Bottom Me.Panel2.Dock = System.Windows.Forms.DockStyle.Bottom
Me.Panel2.Location = New System.Drawing.Point(0, 114) Me.Panel2.Location = New System.Drawing.Point(0, 128)
Me.Panel2.Name = "Panel2" Me.Panel2.Name = "Panel2"
Me.Panel2.Size = New System.Drawing.Size(498, 138) Me.Panel2.Size = New System.Drawing.Size(498, 138)
Me.Panel2.TabIndex = 8 Me.Panel2.TabIndex = 8
' '
'lblErr_Nachricht
'
Me.lblErr_Nachricht.AutoSize = True
Me.lblErr_Nachricht.ForeColor = System.Drawing.Color.Red
Me.lblErr_Nachricht.Location = New System.Drawing.Point(341, 8)
Me.lblErr_Nachricht.Name = "lblErr_Nachricht"
Me.lblErr_Nachricht.Size = New System.Drawing.Size(151, 13)
Me.lblErr_Nachricht.TabIndex = 10
Me.lblErr_Nachricht.Text = "Bitte Nachricht-Text eingeben!"
Me.lblErr_Nachricht.Visible = False
'
'Button2 'Button2
' '
Me.Button2.Anchor = CType((System.Windows.Forms.AnchorStyles.Top Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles) Me.Button2.Anchor = CType((System.Windows.Forms.AnchorStyles.Top Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles)
@@ -122,7 +137,7 @@ Partial Class frmErrorMeldung
Me.txtNachricht.Location = New System.Drawing.Point(3, 24) Me.txtNachricht.Location = New System.Drawing.Point(3, 24)
Me.txtNachricht.Multiline = True Me.txtNachricht.Multiline = True
Me.txtNachricht.Name = "txtNachricht" Me.txtNachricht.Name = "txtNachricht"
Me.txtNachricht.Size = New System.Drawing.Size(400, 110) Me.txtNachricht.Size = New System.Drawing.Size(400, 86)
Me.txtNachricht.TabIndex = 3 Me.txtNachricht.TabIndex = 3
' '
'Label3 'Label3
@@ -134,17 +149,6 @@ Partial Class frmErrorMeldung
Me.Label3.TabIndex = 7 Me.Label3.TabIndex = 7
Me.Label3.Text = "Nachricht (Bitte um kurze Schilderung, was den Fehler ausgelöst hat):" Me.Label3.Text = "Nachricht (Bitte um kurze Schilderung, was den Fehler ausgelöst hat):"
' '
'lblErr_Nachricht
'
Me.lblErr_Nachricht.AutoSize = True
Me.lblErr_Nachricht.ForeColor = System.Drawing.Color.Red
Me.lblErr_Nachricht.Location = New System.Drawing.Point(341, 8)
Me.lblErr_Nachricht.Name = "lblErr_Nachricht"
Me.lblErr_Nachricht.Size = New System.Drawing.Size(151, 13)
Me.lblErr_Nachricht.TabIndex = 10
Me.lblErr_Nachricht.Text = "Bitte Nachricht-Text eingeben!"
Me.lblErr_Nachricht.Visible = False
'
'MyPanel2 'MyPanel2
' '
Me.MyPanel2.BackColor = System.Drawing.Color.FromArgb(CType(CType(0, Byte), Integer), CType(CType(54, Byte), Integer), CType(CType(128, Byte), Integer)) Me.MyPanel2.BackColor = System.Drawing.Color.FromArgb(CType(CType(0, Byte), Integer), CType(CType(54, Byte), Integer), CType(CType(128, Byte), Integer))
@@ -159,7 +163,7 @@ Partial Class frmErrorMeldung
Me.MyPanel1.Controls.Add(Me.btnClose) Me.MyPanel1.Controls.Add(Me.btnClose)
Me.MyPanel1.Controls.Add(Me.TextBox2) Me.MyPanel1.Controls.Add(Me.TextBox2)
Me.MyPanel1.Dock = System.Windows.Forms.DockStyle.Bottom Me.MyPanel1.Dock = System.Windows.Forms.DockStyle.Bottom
Me.MyPanel1.Location = New System.Drawing.Point(0, 252) Me.MyPanel1.Location = New System.Drawing.Point(0, 266)
Me.MyPanel1.Name = "MyPanel1" Me.MyPanel1.Name = "MyPanel1"
Me.MyPanel1.Size = New System.Drawing.Size(498, 195) Me.MyPanel1.Size = New System.Drawing.Size(498, 195)
Me.MyPanel1.TabIndex = 6 Me.MyPanel1.TabIndex = 6
@@ -191,12 +195,34 @@ Partial Class frmErrorMeldung
Me.TextBox2.Size = New System.Drawing.Size(492, 135) Me.TextBox2.Size = New System.Drawing.Size(492, 135)
Me.TextBox2.TabIndex = 4 Me.TextBox2.TabIndex = 4
' '
'cbxEnviromentVariables
'
Me.cbxEnviromentVariables.AutoSize = True
Me.cbxEnviromentVariables.Enabled = False
Me.cbxEnviromentVariables.Location = New System.Drawing.Point(11, 115)
Me.cbxEnviromentVariables.Name = "cbxEnviromentVariables"
Me.cbxEnviromentVariables.Size = New System.Drawing.Size(133, 17)
Me.cbxEnviromentVariables.TabIndex = 11
Me.cbxEnviromentVariables.Text = "Systemdaten schicken"
Me.cbxEnviromentVariables.UseVisualStyleBackColor = True
'
'cbxScreenshot
'
Me.cbxScreenshot.AutoSize = True
Me.cbxScreenshot.Enabled = False
Me.cbxScreenshot.Location = New System.Drawing.Point(150, 115)
Me.cbxScreenshot.Name = "cbxScreenshot"
Me.cbxScreenshot.Size = New System.Drawing.Size(139, 17)
Me.cbxScreenshot.TabIndex = 12
Me.cbxScreenshot.Text = "Screenshot mitschicken"
Me.cbxScreenshot.UseVisualStyleBackColor = True
'
'frmErrorMeldung 'frmErrorMeldung
' '
Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!) Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
Me.BackColor = System.Drawing.Color.White Me.BackColor = System.Drawing.Color.White
Me.ClientSize = New System.Drawing.Size(500, 449) Me.ClientSize = New System.Drawing.Size(500, 463)
Me.Controls.Add(Me.Panel1) Me.Controls.Add(Me.Panel1)
Me.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None Me.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None
Me.Icon = CType(resources.GetObject("$this.Icon"), System.Drawing.Icon) Me.Icon = CType(resources.GetObject("$this.Icon"), System.Drawing.Icon)
@@ -228,4 +254,6 @@ Partial Class frmErrorMeldung
Friend WithEvents MyPanel1 As MyPanel Friend WithEvents MyPanel1 As MyPanel
Friend WithEvents btnClose As Windows.Forms.Button Friend WithEvents btnClose As Windows.Forms.Button
Friend WithEvents lblErr_Nachricht As Windows.Forms.Label Friend WithEvents lblErr_Nachricht As Windows.Forms.Label
Friend WithEvents cbxScreenshot As Windows.Forms.CheckBox
Friend WithEvents cbxEnviromentVariables As Windows.Forms.CheckBox
End Class End Class

View File

@@ -1,4 +1,13 @@
Imports Microsoft.Office.Interop.Outlook Imports System.Drawing
Imports System.Drawing.Imaging
Imports System.IO
Imports System.Reflection
Imports System.Text
Imports System.Windows.Forms
Imports System.Management
Imports iTextSharp.xmp.impl.xpath
Imports Microsoft.Office.Interop
Imports Microsoft.Office.Interop.Outlook
Public Class frmErrorMeldung Public Class frmErrorMeldung
@@ -6,7 +15,8 @@ Public Class frmErrorMeldung
Dim err_stack Dim err_stack
Dim err_zp As DateTime = Now Dim err_zp As DateTime = Now
Dim err_title Dim err_title
Sub New(err_meldung, err_stack, Optional err_title = "") Dim screenshotUrl
Sub New(err_meldung As String, err_stack As String, Optional err_title As String = "", Optional screenshotUrl As String = "")
' Dieser Aufruf ist für den Designer erforderlich. ' Dieser Aufruf ist für den Designer erforderlich.
InitializeComponent() InitializeComponent()
@@ -14,6 +24,7 @@ Public Class frmErrorMeldung
Me.err_meldung = err_meldung Me.err_meldung = err_meldung
Me.err_stack = err_stack Me.err_stack = err_stack
Me.err_title = err_title Me.err_title = err_title
Me.screenshotUrl = screenshotUrl
' Fügen Sie Initialisierungen nach dem InitializeComponent()-Aufruf hinzu. ' Fügen Sie Initialisierungen nach dem InitializeComponent()-Aufruf hinzu.
End Sub End Sub
@@ -23,6 +34,9 @@ Public Class frmErrorMeldung
End Sub End Sub
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
Cursor = Cursors.WaitCursor
lblErr_Nachricht.Visible = False lblErr_Nachricht.Visible = False
If txtNachricht.Text.Trim = "" Then If txtNachricht.Text.Trim = "" Then
@@ -54,17 +68,110 @@ Public Class frmErrorMeldung
Mail_Text &= "<br>" & "<u>User-Nachricht:</u>" & "<br>" & txtNachricht.Text.Trim & "<br>" Mail_Text &= "<br>" & "<u>User-Nachricht:</u>" & "<br>" & txtNachricht.Text.Trim & "<br>"
Mail_Text &= "<br>" & "<u>Error:</u>" & "<br>" & TextBox2.Text.Trim Mail_Text &= "<br>" & "<u>Error:</u>" & "<br>" & TextBox2.Text.Trim
If VERAG_PROG_ALLGEMEIN.cProgramFunctions.sendMail(Mail_To, ("ERROR-TICKET " & err_title).trim, Mail_Text) Then Dim outl As New Outlook.Application
Me.Close() Dim Mail As Microsoft.Office.Interop.Outlook.MailItem
Mail = outl.CreateItem(0)
Mail.Subject = ("ERROR-TICKET " & err_title).trim
Mail.HTMLBody = Mail_Text
Mail.To = Mail_To
If cbxScreenshot.Checked Then
Mail.Attachments.Add(screenshotUrl, Microsoft.Office.Interop.Outlook.OlAttachmentType.olByValue, , "Screenshot.jpeg")
End If End If
If cbxEnviromentVariables.Checked Then
If Not My.Computer.FileSystem.DirectoryExists(My.Computer.FileSystem.SpecialDirectories.Desktop & "\Screenshots_" & My.Application.Info.AssemblyName & "\") Then
My.Computer.FileSystem.CreateDirectory(My.Computer.FileSystem.SpecialDirectories.Desktop & "\Screenshots_" & My.Application.Info.AssemblyName & "\")
End If
Dim filename = "SystemEnviroment_" & Now.ToFileTime & "_.txt"
Dim strFile As String = My.Computer.FileSystem.SpecialDirectories.Desktop & "\Screenshots_" & My.Application.Info.AssemblyName & "\" & filename
Dim fileExists As Boolean = File.Exists(strFile)
Using sw As New StreamWriter(File.Open(strFile, FileMode.CreateNew))
createSystemInformation(sw)
sw.Close()
Mail.Attachments.Add(strFile, Microsoft.Office.Interop.Outlook.OlAttachmentType.olByValue, , filename)
End Using
End If
Try
Mail.Send()
Me.Close()
Catch ex As System.Exception
Cursor = Cursors.WaitCursor
MsgBox(ex.Message)
End Try
End Sub End Sub
Private Sub frmErrorMeldung_Load(sender As Object, e As EventArgs) Handles Me.Load Private Sub frmErrorMeldung_Load(sender As Object, e As EventArgs) Handles Me.Load
TextBox2.Text = err_meldung & vbNewLine & vbNewLine & err_stack TextBox2.Text = err_meldung & vbNewLine & vbNewLine & err_stack
If screenshotUrl <> "" Then
cbxScreenshot.Enabled = True
cbxScreenshot.Checked = True
Else
cbxScreenshot.Enabled = False
cbxScreenshot.Checked = False
End If
cbxEnviromentVariables.Enabled = True
cbxEnviromentVariables.Checked = True
End Sub End Sub
Private Sub frmErrorMeldung_Shown(sender As Object, e As EventArgs) Handles Me.Shown Private Sub frmErrorMeldung_Shown(sender As Object, e As EventArgs) Handles Me.Shown
txtNachricht.Focus() txtNachricht.Focus()
End Sub End Sub
Private Sub createSystemInformation(ByRef sw As StreamWriter)
Dim str As String
Dim nl As String = Environment.NewLine
sw.WriteLine()
sw.WriteLine("-- Environment members --")
sw.WriteLine("CommandLine: {0}", Environment.CommandLine)
Dim arguments As String() = Environment.GetCommandLineArgs()
sw.WriteLine("GetCommandLineArgs: {0}", String.Join(", ", arguments))
sw.WriteLine("CurrentDirectory: {0}", Environment.CurrentDirectory)
sw.WriteLine("ExitCode: {0}", Environment.ExitCode)
sw.WriteLine("HasShutdownStarted: {0}", Environment.HasShutdownStarted)
sw.WriteLine("MachineName: {0}", Environment.MachineName)
sw.WriteLine("NewLine: {0} first line{0} second line{0} third line", Environment.NewLine)
sw.WriteLine("OSVersion: {0}", Environment.OSVersion.ToString())
sw.WriteLine("StackTrace: '{0}'", Environment.StackTrace)
sw.WriteLine("SystemDirectory: {0}", Environment.SystemDirectory)
sw.WriteLine("TickCount: {0}", Environment.TickCount)
sw.WriteLine("UserDomainName: {0}", Environment.UserDomainName)
sw.WriteLine("UserInteractive: {0}", Environment.UserInteractive)
sw.WriteLine("UserName: {0}", Environment.UserName)
sw.WriteLine("Version: {0}", Environment.Version.ToString())
sw.WriteLine("WorkingSet: {0}", Environment.WorkingSet)
Dim query As String = "My system drive is %SystemDrive% and my system root is %SystemRoot%"
str = Environment.ExpandEnvironmentVariables(query)
sw.WriteLine("ExpandEnvironmentVariables: {0} {1}", nl, str)
sw.WriteLine("GetEnvironmentVariable: {0} My temporary directory is {1}.", nl, Environment.GetEnvironmentVariable("TEMP"))
sw.WriteLine("GetEnvironmentVariables: ")
Dim environmentVariables As IDictionary = Environment.GetEnvironmentVariables()
For Each de As DictionaryEntry In environmentVariables
sw.WriteLine((" {0} = {1}", de.Key, de.Value))
Next
sw.WriteLine("GetFolderPath: {0}", Environment.GetFolderPath(Environment.SpecialFolder.System))
Dim drives As String() = Environment.GetLogicalDrives()
sw.WriteLine("GetLogicalDrives: {0}", String.Join(", ", drives))
End Sub
End Class End Class