What is wrong with my code? Getting a 'Process cannot access the file because it is being used by another process' error msg Is there a way around this. My google-fu was not giving me much luck. I was not able to Move or Copy, and I will take either.
Private Sub frmFiberTransMain_DragEnter(sender As Object, e As DragEventArgs) Handles MyBase.DragEnter
If e.Data.GetDataPresent(DataFormats.FileDrop, False) = True Then
e.Effect = DragDropEffects.All
End If
End Sub
Private Sub frmFiberTransMain_DragDrop(sender As Object, e As DragEventArgs) Handles MyBase.DragDrop
If e.Data.GetDataPresent(DataFormats.FileDrop) Then
Dim filePaths As String() = CType(e.Data.GetData(DataFormats.FileDrop), String())
Call CopyFileDrop(filePaths)
End If
End Sub
Private Sub CopyFileDrop(filePaths As String())
For Each fileLoc As String In filePaths
Dim fileName As String = fileLoc
Dim fi As New IO.FileInfo(fileName)
File.Create(fileName)
Dim justFileName As String = fi.Name
Dim newPathName As String = gProgDir & "\" & justFileName
Directory.Move(fileLoc, newPathName)
Next fileLoc
End Sub
File.Create(fileName) returns an open handle and you're not closing it. It doesn't look like you need that line. –
#LarsTech 50 mins ago
Related
I am executing a PowerShell script from a Visual Basic WinForms UI, and I managed to code it so it executes on a BackgroundWorker thread so that the UI doesn't lock up while the script is running. What it does is imports a .printerExport file to add printers and drivers to a target host, and it runs great. The only issue is that I set the output of the PSObjects to a TextBox and they all get output at the end once the script is completed, rather than output in real time like it would in a PowerShell console window.
I have tried multiple things to get it to output in real-time, but I am out of ideas, and even ReportProgress doesn't manage to get the real-time output as well.
How can I get this done? Below are the three involved Sub functions I am currently using:
Private Sub BackgroundWorker1_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
Dim HostName As String
Dim PrintName As String
Dim SourceFilePath As String
Dim DestinationPath As String
Dim FileName As String
HostName = txtHostName.Text
PrintName = "\\" & txtHostName.Text
SourceFilePath = txtFilePath.Text
DestinationPath = PrintName & "\c$\Temp\"
If String.IsNullOrEmpty(HostName) Or String.IsNullOrEmpty(SourceFilePath) Then
MessageBox.Show("Please enter the target host name and choose a file path.")
Return
End If
FileName = Path.GetFileName(SourceFilePath)
File.Copy(SourceFilePath, Path.Combine(DestinationPath, Path.GetFileName(SourceFilePath)), True)
Dim PsEnv As New RunspaceInvoke
Dim App As String = $"Invoke-Command -ComputerName {HostName} {{C:\Windows\System32\spool\tools\Printbrm.exe -r -s {PrintName} -f ""C:\Temp\{FileName}""}}"
Dim AppObjects As Collection(Of PSObject) = PsEnv.Invoke(App)
Dim Output As New StringBuilder()
Dim id As Integer = 0
For Each psobj2 As PSObject In AppObjects
id += 1
BackgroundWorker1.ReportProgress(id, psobj2.ToString() & vbCrLf & vbCrLf)
Next
End Sub
Private Sub BackgroundWorker1_ProgressChanged(sender As Object, e As System.ComponentModel.ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
Dim userState As String = CType(e.UserState, String)
TextBox3.AppendText(userState)
End Sub
Private Sub buttonInstall_Click(sender As Object, e As EventArgs) Handles buttonInstall.Click
BackgroundWorker1.WorkerReportsProgress = True
BackgroundWorker1.RunWorkerAsync()
End Sub
As the title implies, I am trying to create a progress bar that updates with a file transfer. I am currently using Visual Studio 2019. I have been through dozens of articles and videos all claiming to do just this. After many days of testing, I have gotten close, but the progress bar will still only update after the file transfer is complete. I am using multi threading techniques to accomplish just this much. I would very much appreciate if someone could just lay it down for me on how to do this. Here is my code so far. It doesn't really help for making it but you can at least see what I am trying to achieve. I also left out some large chunks of commented out test script.
Summary of what I need to is: Create a script that will copy the specified directory and all sub directories. While doing this I would like the progress bar to move with the file transfer.
Imports System.ComponentModel
Imports System.Threading
Imports System
Imports System.IO
Public Class Form1
Private Sub BtnStartTransfer_Click(sender As Object, e As EventArgs) Handles btnStartTransfer.Click
BackgroundWorker1.RunWorkerAsync()
End Sub
Private Delegate Sub DelegateProgressBarMax(ByVal check As Integer)
Private Sub ProgressBarUpdate(ByVal check As Integer)
If pBar1.InvokeRequired = True Then
Invoke(Sub() pBar1.Value = check)
Else
pBar1.Value = check
End If
End Sub
Private Delegate Sub DelegateUpdateOutput(ByVal check2 As String)
Private Sub OutputUpdate(ByVal check2 As String)
If txtOutput.InvokeRequired = True Then
Invoke(Sub() txtOutput.Text = txtOutput.Text & check2 & Environment.NewLine)
Else
txtOutput.Text = txtOutput.Text & check2
End If
End Sub
Private Sub BackgroundWorker1_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
Dim getCopyFrom As String = txtCopyFrom.Text
Dim getCopyTo As String = txtCopyTo.Text
Dim splitUser() As String = getCopyFrom.Split("\")
Dim finalValue As String = splitUser.Length - 1
Dim stringValue As String = CStr(splitUser(finalValue))
Dim getUser As String
'If MsgBox("Is this the correct user?: " & stringValue, vbYesNo + vbQuestion) = vbYes Then
' getUser = stringValue
'Else
' getUser = InputBox("Enter in the correct Username")
'End If
Dim checkCopyFrom As New IO.DirectoryInfo(getCopyFrom)
Dim checkCopyTo As New IO.DirectoryInfo(getCopyTo)
If checkCopyFrom.Exists Then
Else
MsgBox("The location you are trying to copy from does not exist.")
Exit Sub
End If
If checkCopyTo.Exists Then
Else
MsgBox("The location you are trying to copy to does not exist.")
Exit Sub
End If
'Copying the Desktop folder
Dim dirDesktop = getCopyFrom & "\Desktop"
Dim getDir = IO.Directory.GetFiles(dirDesktop, "*", IO.SearchOption.AllDirectories)
Dim fileTotal As Integer = getDir.Length
Dim filesTransferred As Integer = 0
Dim di As New DirectoryInfo(dirDesktop)
Dim fiArr As FileInfo() = di.GetFiles("*", SearchOption.AllDirectories)
Dim diArr As DirectoryInfo() = di.GetDirectories("*", IO.SearchOption.AllDirectories)
Dim fri As FileInfo
Dim fol As DirectoryInfo
For Each fri In fiArr
filesTransferred += 1
BackgroundWorker1.ReportProgress(CInt(filesTransferred * 100 \ fiArr.Length), True)
OutputUpdate(fri.Name)
'File.Copy(dirDesktop & "\" & fri.Name, getCopyTo & "\" & fri.Name, True)
'My.Computer.FileSystem.CopyDirectory(getCopyFrom & "\Desktop", getCopyTo & "\Users\" & getUser & "\Desktop", False)
Next fri
End Sub
Private Sub BackgroundWorker1_ProgressChanged(sender As Object, e As ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
pBar1.Value = e.ProgressPercentage
End Sub
I am very new to VB and I have an assignment which requires me to have search code in the program.The search code works but it shows the path of the file and I just want it to show the name of the txt file.
Private Sub SearchOrdersToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles SearchOrdersToolStripMenuItem.Click
txtSearch.Visible = True
Lblsearch.Visible = True
Dim backslash As String() = FrmLogIn.FolderDirectory.Split("\")
Dim filename As String = backslash(6)
ListOfAllFileNames = System.IO.Directory.GetFiles(FrmLogIn.FolderDirectory)
TxtShoworders.Lines = ListOfAllFileNames
End Sub
Private Sub txtSearch_TextChanged(sender As Object, e As EventArgs) Handles txtSearch.TextChanged
If txtSearch.Text = "" Then
TxtShoworders.Lines = ListOfAllFileNames
Return
Else
Dim SearchResults As New List(Of String)
For Each currentFileName In ListOfAllFileNames
If currentFileName.Contains(txtSearch.Text) Then
SearchResults.Add(currentFileName)
End If
Next
TxtShoworders.Lines = SearchResults.ToArray()
End If
End Sub
Link to what the program looks like and the directory showing
If anyone could help me with this that would be great, thanks.
You'll have to use Path.GetFileName for this, example:
SearchResults.Add(Path.GetFileName(currentFileName))
To keep your list of paths but only show the filenames, try this:
Private Sub SearchOrdersToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles SearchOrdersToolStripMenuItem.Click
txtSearch.Visible = True
Lblsearch.Visible = True
Dim backslash As String() = FrmLogIn.FolderDirectory.Split("\")
Dim filename As String = backslash(6)
ListOfAllFileNames = System.IO.Directory.GetFiles(FrmLogIn.FolderDirectory)
TxtShoworders.Lines = GetFileNames(ListOfAllFileNames)
End Sub
Private Sub txtSearch_TextChanged(sender As Object, e As EventArgs) Handles txtSearch.TextChanged
If txtSearch.Text = "" Then
TxtShoworders.Lines = GetFileNames(ListOfAllFileNames)
Return
Else
Dim SearchResults As New List(Of String)
For Each currentFileName In ListOfAllFileNames
If currentFileName.Contains(txtSearch.Text) Then
SearchResults.Add(currentFileName)
End If
Next
TxtShoworders.Lines = GetFileNames(SearchResults.ToArray())
End If
End Sub
Private Function GetFileNames(Byval paths as String()) As String()
Return paths.Select(Function(p) Path.GetFileName(p)).ToArray()
End Function
This will keep your ListOfAllFileNames containing the paths while only showing the file names using GetFileNames.
I'm copying all the .avi and .png files from one folder into another:
Private Sub CopierSend_Button_Click(sender As Object, e As EventArgs) Handles CopierSend_Button.Click
If MessageBox.Show("Click OK to send media or just Cancel.", "Media Copier", MessageBoxButtons.OKCancel, MessageBoxIcon.Question) = DialogResult.OK Then
For Each foundFile As String In My.Computer.FileSystem.GetFiles(FrapsFolder_, Microsoft.VisualBasic.FileIO.SearchOption.SearchTopLevelOnly, "*.avi", "*.png")
Dim foundFileInfo As New System.IO.FileInfo(foundFile)
My.Computer.FileSystem.CopyFile(foundFile, DestFolder_ & foundFileInfo.Name, Microsoft.VisualBasic.FileIO.UIOption.OnlyErrorDialogs, Microsoft.VisualBasic.FileIO.UICancelOption.DoNothing)
Next
Else
'Nothing Yet
End If
End Sub
I want to add a ProgressBar which will count every time a file is copied, so I added this code before the For Each loop:
Dim file1() As String = IO.Directory.GetFiles(FrapsFolder_, "*.avi")
Dim file2() As String = IO.Directory.GetFiles(FrapsFolder_, "*.png")
Dim files = file1.Length + file2.Length
Copier_ProgressBar.Step = 1
Copier_ProgressBar.Maximum = files
And added this code inside the For Each loop:
Copier_ProgressBar.Value += 1
Here is all of my code:
Private Sub CopierSend_Button_Click(sender As Object, e As EventArgs) Handles CopierSend_Button.Click
If MessageBox.Show("Click OK to send media or just Cancel.", "Media Copier", MessageBoxButtons.OKCancel, MessageBoxIcon.Question) = DialogResult.OK Then
Dim file1() As String = IO.Directory.GetFiles(FrapsFolder_, "*.avi")
Dim file2() As String = IO.Directory.GetFiles(FrapsFolder_, "*.png")
Dim files = file1.Length + file2.Length
Copier_ProgressBar.Step = 1
Copier_ProgressBar.Maximum = files
For Each foundFile As String In My.Computer.FileSystem.GetFiles(FrapsFolder_, Microsoft.VisualBasic.FileIO.SearchOption.SearchTopLevelOnly, "*.avi", "*.png")
Dim foundFileInfo As New System.IO.FileInfo(foundFile)
My.Computer.FileSystem.CopyFile(foundFile, DestFolder_ & foundFileInfo.Name, Microsoft.VisualBasic.FileIO.UIOption.OnlyErrorDialogs, Microsoft.VisualBasic.FileIO.UICancelOption.DoNothing)
Copier_ProgressBar.Value += 1
Next
Else
'Nothing Yet
End If
End Sub
The ProgressBar updates, but only after all the files have been copied instead of updating in real time. Any idea?
As it stands it looks like the ProgressBar doesn't do anything until after all the files have copied. That isn't strictly true. Instead your UI is not updating.
Instead you should look into using a BackgroundWoker to report progress. Something like this should do the trick:
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'This can also be set using the Designer
BackgroundWorker1.WorkerReportsProgress = True
End Sub
Private Sub CopierSend_Button_Click(sender As Object, e As EventArgs) Handles CopierSend_Button.Click
If MessageBox.Show("Click OK to send media or just Cancel.", "Media Copier", MessageBoxButtons.OKCancel, MessageBoxIcon.Question) = DialogResult.OK Then
Dim file1() As String = IO.Directory.GetFiles(FrapsFolder_, "*.avi")
Dim file2() As String = IO.Directory.GetFiles(FrapsFolder_, "*.png")
Dim files As Integer = file1.Length + file2.Length
Copier_ProgressBar.Step = 1
Copier_ProgressBar.Maximum = files
BackgroundWorker1.RunWorkerAsync()
End If
End Sub
Private Sub BackgroundWorker1_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
For Each foundFile As String In My.Computer.FileSystem.GetFiles(FrapsFolder_, Microsoft.VisualBasic.FileIO.SearchOption.SearchTopLevelOnly, "*.avi", "*.png")
Dim foundFileInfo As New System.IO.FileInfo(foundFile)
My.Computer.FileSystem.CopyFile(foundFile, DestFolder_ & foundFileInfo.Name, Microsoft.VisualBasic.FileIO.UIOption.OnlyErrorDialogs, Microsoft.VisualBasic.FileIO.UICancelOption.DoNothing)
BackgroundWorker1.ReportProgress(Copier_ProgressBar.Value + 1)
Next
End Sub
Private Sub BackgroundWorker1_ProgressChanged(sender As Object, e As System.ComponentModel.ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
Copier_ProgressBar.Value = e.ProgressPercentage
End Sub
As an additional note, for best practice, I would consider using Path.Combine instead of concatenating strings together:
My.Computer.FileSystem.CopyFile(foundFile, Path.Combine(DestFolder_, foundFileInfo.Name), Microsoft.VisualBasic.FileIO.UIOption.OnlyErrorDialogs, Microsoft.VisualBasic.FileIO.UICancelOption.DoNothing)
I have a form that allows you to click a button, which triggers an OpenFileDialog. From there, you are suppose to select a specific file within that folder, and then the program is supposed to go through from the folder you were in the the /subjects folder and list those directories.
At the moment, I have 3 directories within /subjects: english, mathematics, and cte.
My issue is that when the program is ran, it will only list the English directory in the combo-box, and will not list any of the others.
Private Sub btnDocumentChoice_Click(sender As Object, e As EventArgs) Handles btnDocumentChoice.Click
Dim ofd As New OpenFileDialog
Dim DirList As New ArrayList
If ofd.ShowDialog = Windows.Forms.DialogResult.OK AndAlso ofd.FileName <> "" Then
strRootLocation = (Path.GetDirectoryName(ofd.FileName))
GetDirectories(strRootLocation + "/subject/", DirList)
'MessageBox.Show(Path.GetDirectoryName(ofd.FileName))
End If
End Sub
Private Sub OpenFileDialog1_FileOk(ByVal sender As System.Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles OpenFileDialog1.FileOk
strRootLocation = OpenFileDialog1.FileName
cmbSubject.Items.Add(strRootLocation)
End Sub
Sub GetDirectories(ByVal StartPath As String, ByRef DirectoryList As ArrayList)
Dim Dirs() As String = Directory.GetDirectories(StartPath)
DirectoryList.AddRange(Dirs)
For Each Dir As String In Dirs
GetDirectories(Dir, DirectoryList)
cmbSubject.Items.Add(Replace(Path.GetDirectoryName(Dir), strRootLocation + "\subject", ""))
cmbSubject.Items.Remove("")
Next
End Sub
I managed to fix my own issue by removing the For Each loop in the question, and replacing it with this:
Dim directories As String
For Each directories In Directory.GetDirectories(strRootLocation + "\subject")
cmbSubject.Items.Add(Replace(directories, strRootLocation + "\subject\", ""))
Next