Can't delete .xlsx file - Next Step? - vb.net

I'm getting an IOException (file in use by another process) error when trying to delete an .xlsx file. I moved the delete code to the front of Form_Load() just to make absolutely certain that nothing else I was doing was trying to open or read it.
Process Explorer can't find any references to the file to see what else might be trying to use it.
The file properties indicate that the user and system have full control.
I don't know what to look at next.
Private Sub PreEdit2_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
My.Computer.FileSystem.DeleteFile("\\HOSTNAME\Folder\Import Data\Other Import Files\" & "9710.xlsx")
I tried a local reference to the file just for good measure.
My.Computer.FileSystem.DeleteFile("C:\Folder\Import Data\Other Import Files\" & "9710.xlsx")
Really stumped here. Any suggestions sincerely appreciated.
EDIT:
Modified my program to delete all kinds of other files in the same directory. They delete with no problem.
Created an empty test program with one line that tries to delete the file
and it gets the same IOException.
So, my program isn't doing it. The error says something else is using the file, no monitoring program I have used shows the any process involved with the file, and File Explorer can delete it? Strange things are afoot at the Circle K.
EDIT 2:
I have moved the file and tried deleting it in lots of different directories. I can delete it everywhere else I try it. The only place I don't seem to be able to delete it (with my new single purpose test program) is in the directory it was originally copied to. It should be remembered that all of the other files in that directory I can use the program to delete with no problem.

Related

Toggle Renaming a File without checking if it exists in VB.Net

Non programmer trying to toggle renaming a file from a vb.net form without checking if it exists. Have done this with simple batch file. Would like to to know if it is possible in vb.net without needing to check if file exists. Also do not want to use toggle control, want to use button control as UI preference.
Code used in batch file:
set ADDON_PATH="P:\MyPath\MySubFolder\"
set ADDON_NAME="myfile.dll"
set DISABLE_NAME="myfile.bak"
cd /d %ADDON_PATH%
Ren %ADDON_NAME% %DISABLE_NAME% 2> nul || ren %DISABLE_NAME% %ADDON_NAME% 2> nul
Partial code here for vb.net using button, not toggle button
Private Sub PlayVanilla(sender As Object, e As EventArgs) Handles Button11.Click
If Button11.Text = "Vanilla Mode" Then
Button11.Text = "Modded Game"
Button11.ForeColor = Color.Green
My.Computer.FileSystem.RenameFile("P:\MyPath\MySubFolder\myfile.dll", "myfile.bak")
Else
Button11.Text = "Vanilla Mode"
Button11.ForeColor = Color.Red
My.Computer.FileSystem.RenameFile("P:\MyPath\MySubFolder\myfile.bak", "myfile.dll")
End If
End Sub
I haven't tried the code above because obviously the file could be in either state, myfile.bak or myfile.dll. So the question is, do i need to check if file exists or can I use a construct as I did in the batch file. One final note, this file always exists and I'm the only user so 0% risk of it not being there. The batch file works simply and perfectly but I don't want to run the batch file from VB form, looking for VB solution. Thank you.
Unable to find solution matching the batch file example, so will test for file exists. In passing, this isn't an enterprise solution -probability of the file being locked by another process is exactly zero. Additionally, there is 100% probability the file exists in one of two name states. However I understand and appreciate the robustness comments and accept them. Thanks.
Imports System.IO
If Directory.Exists("P:\MyPath\Myfolder\Myfile.dll") Then ...

Problem handling errors with FileSystemWatcher

To start with it has been many years since I have done much programming, probably about 15 years, in fact VB 6 was still being taught then so I'm not up to date on anything and can get lost in what I'm reading but I am trying. I'm using Visual Studio 2019 and trying to create a VB Windows Forms App that uses the FileSystemWatcher. Unfortunately the only solutions to my problem that I could find are in C#. I tried to transfer them to my app but couldn't get them to work. Actually Visual Studio wasn't happy with what I put in and wouldn't run at all, probably due to incorrect syntax.
This part of my little app is supposed to copy a file that another program creates, while the other program is running, and place the copy in another folder. It seemed simple, detect that the file had been changed and then copy the changed file. Well I came across a few problems.
The first problem is that if I create an empty file the code works most times with no problems but occassionally 2 copies of the file are created. I could live with that but.
If I replace the empty file with a larger file, the file that it is meant to copy, then it can make 3 or 4 copies and most times produces a messagebox telling me that it can't access the file because it is in use. The main program is also minimised to display the error message, which I don't want.
Even if my app is the only program running and I replace the watched file manually with the larger file I still get the file in use error, so I am assuming that the event has been triggered twice and one of them is the process that is using the file and causing the error.
If I tell the error message to cancel then my program continues and produces only 1 copy of the file. Which is what I do want.
The second problem is that the file being copied is also accessed by another program for a short period imediately after it has been changed and this also causes an extra few copies of it to be made and sometimes a file in use error message box appears, and again the main program is minimised to display the error message. I originally had other IO.NotifyFilters in place that weren't really necassary and thought that they may have been triggering the errors so I removed them, but it made no difference.
The most common error is that the file is in use but there has also been the odd "Unhandled exception has occured in your application. could not find file.". The only reason that I can think of for this error is that the file may have been renamed to a backup file and a new version created by the main program at the exact time my program tried to access it.
From what I have read the FileSystemWatcher can trigger multiple times and I presume that this is what is causing the duplicate copies from both problems.
I need my app to make only 1 copy without the error messagebox appearing as this program needs to run in the background with no user input. Essentially this part of my app is an external program to backup a file when the file changes because the main program changes this file often but only seems to back up the file every few hours.
The following code is what I have used but nothing that I have tried has caught the error so I removed the error event handler. This code was copied from something else that was similar and in C# then modified for my purpose. I thought that the {} were used for C# not VB but it seems to work and if I take them out it won't.
My code for the FileSystemwatcher is:-
WatchFile = New System.IO.FileSystemWatcher With {
.Path = Path.GetDirectoryName(strArkMapFileNamePath),
.Filter = Path.GetFileName(strArkMapFileNamePath),
.NotifyFilter = IO.NotifyFilters.LastWrite
}
' add the handler to each event
AddHandler WatchFile.Changed, New FileSystemEventHandler(AddressOf OnLastWrite)
'Set this property to true to start watching
WatchFile.EnableRaisingEvents = True
The event handler is:-
Private Sub OnLastWrite(sender As Object, e As FileSystemEventArgs)
'Copy the Save file to a new folder and rename it.
My.Computer.FileSystem.CopyFile(
strArkMapFileNamePath,
strBackupPath & "\" & strArkMapFileName & "_" &
DateTime.Now.ToString("dd.MM.yyyy_hh.mm.ss") & ".ark",
Microsoft.VisualBasic.FileIO.UIOption.OnlyErrorDialogs,
Microsoft.VisualBasic.FileIO.UICancelOption.DoNothing)
End Sub
I added an error event handler after AddHandler WatchFile.Changed, New FileSystemEventHandler(AddressOf OnLastWrite) but that did nothing.
I tried to add an on error statement before the end sub and that did nothing either, I presume because the Microsoft.VisualBasic.FileIO.UIOption.OnlyErrorDialogs, caught the error first.
I got frustrated and tried to add a statement before the Microsoft.VisualBasic.FileIO.UIOption.OnlyErrorDialogs, but it didn't like that and I didn't expect it to work.
So how do I catch the errors before the FileSystemWatcher acts on the error?
I don't know what I am doing wrong so any help would be appreciated.
Also if anybody could offer code for what I need to do can it please be code for a Windows Forms App because I don't seem to have much luck in converting C# or anything else.
Edit
I have replaced the My.Computer.FileSystem.CopyFile with the File.Copy method as suggested and added a few extra bits..
Private Sub OnLastWrite(sender As Object, e As FileSystemEventArgs)
'Verify that source file exists
If File.Exists(strArkMapFileNamePath) Then
'Copy the Save file to a new folder and rename it.
Dim i As Integer
For i = 0 To 3
Try
' Overwrite the destination file if it already exists.
File.Copy(strArkMapFileNamePath, strBackupPath & "\" & strArkMapFileName & "_" & DateTime.Now.ToString("dd.MM.yyyy_hh.mm.ss") & ".ark", True)
i = 3
' Catch exception if the file was already copied.
Catch copyError As IOException
'If copy failed reset counter
i += 1
End Try
Next
End If
End Sub
Although this shouldn't be required because this is done before the FileSystemWatcher is enabled I have added an If statement to check that the files exists before attempting to copy the file.
I'm not entirely happy with the loop but I know under normal conditions that it's not going to be an endless loop.
Is there a way to just catch the specific errors that I would need to deal with or will it be fine the way it is?
I will probably still need to work out how to stop the FileSystemWatcher from sending more than 1 event or somehow make multiple events appear as 1.
The If statement was the last thing that I added and for some reason the program now seems to only make 1 copy and appears to be faster.
The other external program that accesses the file being copied must be slower to react than my program because now it displays a message that it's waiting until my program has finished copying the file.
My program is now performing as it was intended but I believe that it is just a matter of timing rather than the correct code.

How do I extract from a password protected zip file using VBA?

I have been struggling with this problem for quite some time now, and have trawled through various forums trying to find an answer.
I have a mailbox which received 5 emails each morning which have zipped, password-protected .csv files which require opening and processing in Excel. I am semi-competent in VBA so the Excel side of things is no issue, but it would save me a lot of time if I could automatically unzip these files and save them to a folder.
These emails have the same subjects, attachments and passwords each day, and are from the same sender to the same mailbox. I have code which can automatically process and save the .zip files to a location, but I am still stuck with the problem of having to go into each one, enter the password, open the file, save it, etc.
I have refrained from attaching this code because I would like to see if there are better solutions to my one, and it is the unzipping and password entering that I really need help with. This being said if you would like me to attach my code I will be happy to do so :)
To expand my comment, no input is required - the password is obtained via an event so can be provided in code.
Download the demo project and DLL
In the outlook VBA editor, right click the Project in the tree, Import File and add
cUnzip.cls
mUnzip.bas
Put the DLL in \System32 (or \SysWoW64 on 64bit)
As a naive example, add a new class cWhatever:
Private WithEvents Unzip As cUnzip
Private Sub Class_Initialize()
Set Unzip = New cUnzip
End Sub
Sub RunUnzip()
With Unzip
.ZipFile = "c:\blah\qqq.zip"
.UnzipFolder = "c:\temp"
.Unzip
End With
End Sub
Private Sub Unzip_PasswordRequest(sPassword As String, bCancel As Boolean)
sPassword = "password123"
End Sub
Then to run from elsewhere:
Dim x As New cWhatever
x.RunUnzip
First time you run there is an error highlighting App.EXEName, just delete the App.EXEName &

File.Replace not behaving as expected

The following code should replace the executable and restart the application, which should work because the content should be replaced but not in the current running instance:
Dim tmppath As String = System.IO.Path.GetTempFileName
Private Sub YesBtn_Click(sender As Object, e As EventArgs) Handles YesBtn.Click
Dim client As New WebClient()
AddHandler client.DownloadProgressChanged, AddressOf client_ProgressChanged
AddHandler client.DownloadFileCompleted, AddressOf client_DownloadFileCompleted
client.DownloadFileAsync(New Uri("https://github.com/Yttrium-tYcLief/Scrotter/raw/master/latest/scrotter.exe"), tmppath)
End Sub
Public Sub client_DownloadFileCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.AsyncCompletedEventArgs)
File.Replace(tmppath, Application.ExecutablePath, Nothing)
Application.Restart()
End Sub
According to MSDN,
Pass Nothing to the destinationBackupFileName parameter if you do not want to create a backup of the file being replaced.
However, what really happens is that it does create a backup (if the .exe is scrotter.exe, then the new backup is scrotter.exe~RF729c1fe9.TMP). Additionally, a new empty folder called "False" is created in the root directory.
All I want is to replace the running executable with my file and not have any backups or extra folders. Any ideas?
Pretty hard to explain this with the posted code, this smells like a some kind of 3rd party utility stepping in and avoiding the problem your code has. It will never work when you pass Nothing for the backup file name. It is required if you want to replace an executable file that's also loaded into memory. The CLR creates a memory mapped file object for the assembly so Windows can page-in the data from the assembly into RAM on demand. With the big advantage that this doesn't take any space in the paging file. That MMF also puts a hard lock on the file so nobody can alter the file content. That would be disastrous.
That's a lock on the file data, not the directory entry for the file. So renaming the file still works. Which is what File.Replace() does when you provide a non-null backup file name, it renames the assembly so you can still create a file with the same name and not get in trouble with the lock. You can delete the backup copy afterwards, assuming that your program still has sufficient rights to actually remove the file when it starts back up. That's unusual with UAC these days. Or just not bother, disk space is cheap and having a backup copy around to deal with accidents is something you can call a feature.
So get ahead and use File.Replace() properly, use the 3rd argument. Don't forget to delete that backup file before you call Replace().
I think the .exe is locked so long as your process runs - which instance runs is of no concern.
To avoid this, I would place the updater in a separate .exe and shut down your main apllication while updating.

Strange Error When Using Tesseract in VB.net

I have the current code:
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim Bitmap As New Bitmap("image.png")
Dim ocr As tessnet2.Tesseract = New tessnet2.Tesseract()
ocr.SetVariable("tessedit_char_whitelit", "0123456789")
ocr.Init("c:\", "fra", False)
Dim result As List(Of tessnet2.Word) = ocr.DoOCR(Bitmap, Rectangle.Empty)
For Each word As tessnet2.Word In result
RichTextBox1.Text &= word.Text & "(" & word.Confidence & ") "
Next
End Sub
I just have a normal RichTextBox and a button on the form. I also have an image in the debug directory called "image.png".
Every time I run this, the program just closes. I did a step through and all of a sudden a file locater came up asking for "tessnet2.cpp"
I have a reference to the dll. I also don't know what the ocr.Init(...) line is for.
Any help would be nice!
First of all, thank you very much for your simple but effective code. After 3 days search I found this code for VB (not VC). Of course I copied and pasted it immediately and the same problem occured for me, too. Then:
I uninstalled Tesseract 3.xx
Checked RegEdit for Tesseract 3.xx and deleted them (whoever want to do this step; please be careful not to destroy anything)
Copied tessdll.dll in the same folder.
The main problem is:
ocr.Init("c:\", "fra", False) it should be something like this:
ocr.Init("c:\tessdata", "fra", False) in fact my real line is:
ocr.Init(Application.StartupPath & "\tessdata", "eng", False)
Noticed that in the folder "...\Visual Studio 2008\Projects...." I still had the same problem and then copied all folder in "D:\Test" folder (of course in this folder I have one more folder: tessdata)
It worked!!!
Hope it helps for you or anyone searching for this problem like me :)
Nes
If you put your code inside a Try/Catch block, you should be able to find out what the error is without your program closing. You could also debug the program instead of running it, and instead of the program crashing, the debugger will show you exactly where the error is happening.
The first parameter of Init method specifies the location of tessdata folder. If you have it at the default location, which is the same as that of Tesseract binary, it should be null, or Nothing in VB.NET.