Folder handle not released after Dir checks for existence - vba

The following code checks to see if a folder exists and, if not, creates it. The code works, but a handle that points to the folder is left open if it already exists, which prevents the folder from being deleted or renamed until Outlook.exe closes. I do not understand why this is happening or what to do about it, but a handle should not be open after the folder is checked and potentially created.
Sub Test()
Folder = Environ("USERPROFILE") & "\Desktop\NewFolder\"
Result = Dir(Folder, vbDirectory)
If Result = vbNullString Then
MkDir Folder
End If
End Sub
The first time through the code, the folder is successfully created and no file handles are open:
However, the second time through the code, the folder already exists. MkDir does not execute, but a file handle is left open presumably after Dir executes:
I have tried everything I could find to close all open file handles, but nothing has worked. Any help would be greatly appreciated.

Based on the comments from braX, I was able to prove that the Dir call was somehow responsible for the leftover handle. Calling Dir again on a non-existent folder caused the handle to be released, which solved my problem.
A better solution, which was also suggested by braX, is to use a File System Object. Here is a working solution:
Sub Test()
Dim FSO As FileSystemObject
Set FSO = CreateObject("Scripting.FileSystemObject")
Folder = Environ("USERPROFILE") & "\Desktop\NewFolder\"
If Not FSO.FolderExists(Folder) Then
MkDir Folder
End If
End Sub
Thanks, braX!

Related

Changing working directory from Excel vba shell

For work, I'm trying to run a Python script from an Excel VBA macro.
The macro is as follows -
Sub Plot()
Shell "C:\Users\maheshda\AppData\Local\Continuum\Anaconda3\python.exe C:\Users\maheshda\Tool\Tool\Main.py", vbNormalFocus
End Sub
The script runs just fine when run from the command line, but unfortunately, because I'm using relative filepaths in the Python script (at one point, I call files from '../Input/') the script crashes because the current working directory isn't C:\Users\maheshda\Tool\Tool.
How can I change the working directory from within the macro? Thank you!
This is a trivial task in VBA, use ChDir:
ChDir Statement
Changes the current directory or folder.
Syntax
ChDir path
The required path argument is a string expression that identifies which directory or folder becomes the new default directory or folder. The path may include the drive. If no drive is specified, ChDir changes the default directory or folder on the current drive.
Since your main.py resides in C:\Users\maheshda\Tool\Tool\, use the following right before calling the Python script:
ChDir "C:\Users\maheshda\Tool\Tool"
Or (since it is on drive C):
ChDir "\Users\maheshda\Tool\Tool"
Extending on Wiktor Stribiżew's answer and comments, the sub below can be used to change the Current Directory in any case.
Public Sub Change_Current_Directory(NewDirectoryPath as string)
Dim CurrentDirectoryPath as string
CurrentDirectoryPath = curdir
if Strings.StrComp(Strings.Left(CurrentDirectoryPath,2), Strings.Left(NewDirectoryPath,2), vbTextCompare) then
ChDrive Strings.Left(NewDirectoryPath,1)
end if
ChDir NewDirectoryPath
End Function
Happy coding!
FCastro, why did you bother with that StrComp line? And, for that matter, why bother with the Strings object?
I suppose if the drive were external and hadn't been accessed yet it might take a moment, but as long as the path is not expected to be a USB/CD/DVD/etc..., then:
Public Sub Change_Current_Directory(NewDirectoryPath as string)
ChDrive Left(NewDirectoryPath,1)
ChDir NewDirectoryPath
End Function
If your behavior is to open an excel window and then open your recent file, please note that you should not forget to add change Drive and then change Directory into your VBA code.
Cause the Excel always start with the default Directory even it's just open your recent file !
Dim ThisWorkbookPath As String
Dim ThisWorkbookPathParts As Variant
ThisWorkbookPath = ThisWorkbook.Path
ThisWorkbookPathParts = Split(ThisWorkbookPath, _
Application.PathSeparator)
ChDrive ThisWorkbookPathParts(LBound(ThisWorkbookPathParts))
ChDir ThisWorkbookPath

Kill Command Deleting Wrong File(s)i

In Access VBA, I have a procedure I've put together to do this:
Allow the user to select zip file(s)
Extract any files from the zip files to the same directory (In this
specific use-case instance, it is ALWAYS extracting Excel files from
Zip files, never any change, and always using the same password)
Then I want the code to Delete the Zip file after extracting the
.xls file.
Everything works beautifully except the delete file portion. The issue is that when I tell it to delete "FileName.Zip", it is deleting "FileName.Zip" AND "FileName.xls"
Is there any way to make sure that he kill command ONLY deletes what I want it to delete? I've used it before on various occasions, and never had this happen before.
Here is the code I am using:
Dim fd As FileDialog
Dim db As DAO.Database
Dim rs As DAO.Recordset
Dim i As Variant
Set db = CurrentDb
Set rs = db.OpenRecordset("tblProjectPath")
Set fd = FileDialog(msoFileDialogFilePicker)
fd.AllowMultiSelect = True
fd.Title = "Select TOC Return File(s) to process"
fd.InitialFileName = rs.Fields("ProjectPath") & "\FilingReports\*.zip"
fd.Show
For Each i In fd.SelectedItems
'Debug.Print i
Debug.Print '------------------------'
Debug.Print i
Unzip (i) 'The bit calling the command line unzip utility to unzip the file - just telling it to extract all files to the current folder.
Debug.Print i
'Kill i
'had to take out the kill bit, b/c it was deleting both the .zip and .xls files which is not desired nor expected
If InStr(i, ".zip") Then
Kill i 'Tried to specify only .zip files even though think I shouldn't need to, but it's still deleting .xls files
End If
Next i
Edit: Add Unzip code to post:
Unzip code:
Sub Unzip(Path As String)
Dim strUnzip As String
Dim QU As String 'quotation mark
QU = Chr(34)
strUnzip = QU & "c:\program files (x86)\winzip\wzunzip" & QU & " -s" & _
"ZipPassword " & _
Path & " " '& _
Call Shell(strUnzip)
End Sub
At this point, I don't really think a "real" answer will come about. However, I'll post what I've decided to do with the particular process I'm writing this code for anyway.
I'm going to use a folder structure to divide up the files:
1. Place zip file(s)
2. Unzip files to a 2nd folder
3. After processing Excel files in 2nd folder, move to a 3rd "complete" folder.
This will get around the deleting wrong files bit.
Also, it appears that the cause for the issue is related to something to do with the call to the WinZip Command Line Unzip utility (wzunzip) in the Unzip code above, or else something with the tool itself. I thought that maybe it was b/c the tool was asking me if I wanted to overwrite existing files, but that wasn't the case, b/c I had the same issue when there were no files to overwrite.
Anyway, I'm attempting to close this one up at this point. Thanks to Wayne G. Dunn for his assistance on this.

Delete all files and folder

I want to delete all files and folders inside one folder.
Code
If Not Directory.Exists(txtTXT.Text) Then
Return
End If
Dim files() As String
files = Directory.GetFileSystemEntries(txtTXT.Text)
For Each element As String In files
If (Not Directory.Exists(element)) Then
File.Delete(Path.Combine(txtTXT.Text, Path.GetFileName(element)))
End If
Next
My code only deletes the files, but not the folders... How can I delete all?
I revised my program, so I used this code..
My.Computer.FileSystem.DeleteDirectory( _
My.Computer.FileSystem.SpecialDirectories.Desktop + "\epubcount", _
FileIO.DeleteDirectoryOption.DeleteAllContents)
Turn this code into a function. Make a recursive call to the function when you encounter a directory, passing the directory name to it. The function should also delete the directory that was passed in.

VBScript cannot delete folder

I have a VBScript program that creates a folder in the user's temp folder:
set fso = CreateObject("scripting.FileSystemObject")
temp = fso.GetSpecialFolder(2)
dropzone = temp & "\{d450c76c-2ad8-4f73-af8a-ccc5ba28036a}\"
If Not fso.FolderExists(dropzone) Then
set NewFolder = fso.CreateFolder(dropzone)
End If
set NewFolder = Nothing
At the end of the program, I would like to delete that folder. I tried this but it gives me a permission denied error:
set deletefolder = fso.GetFolder(dropzone)
deletefolder.Delete(True)
set fso = Nothing
No, not a problem with timing
No, not a problem with dispose
No, not a problem solved by MsgBox
No, not a problem with attributes
No, not a problem with current directory path
No, can't use Kill
No, it's not access denied
No, you don't have to shell out
No, MSDN documentation won't tell you
YOU JUST HAVE TO DELETE THE TRAILING BACKSLASH IN THE PATH BECAUSE DELETEFOLDER DOESN'T LIKE IT.
Now, feel free to shoot the messenger ...
#giodamelio Weirdly enough, I put the line msgBox dropzone before your code and it worked. When I comment out the msgbox it wont work?
Your code or pc is too fast! :D
You probably don't dispose/close files you use or store in that folder (or not closed correctly)
Check the attributes of the file and set to 0 if it's not already set.
set deletefolder = fso.GetFolder(dropzone)
if deletefolder.Attributes=0 then
deletefolder.Delete(True)
else
deletefolder.Attributes=0
deletefolder.Delete(True)
end if
set fso = Nothing
It's very, very probably not an actual "access denied". More likely it's an "can't delete while files are open". Close any open references to that folder (text streams, processes you might have started, look carefully) and do
fso.DeleteFolder(dropzone)
See MSDN documentation on DeleteFolder().
try to use Kill("folder path")
for DeleteFolder to work, the current directory for the script should not be a part of the path of the folder to be deleted.
Use Shell.CurrentDirectory to change the current directory to some system path and then call DeleteFolder.
I have verified that this works.
Check this.
If your folder path has a backslash, the method will throw an error! Most of my scripts have a backslash at the end of paths purposely using another function, so I removed the last character of my path (backslash) and viola!

How do I create a folder in VB if it doesn't exist?

I wrote myself a little downloading application so that I could easily grab a set of files from my server and put them all onto a new pc with a clean install of Windows, without actually going on the net. Unfortunately I'm having problems creating the folder I want to put them in and am unsure how to go about it.
I want my program to download the apps to program files\any name here\
So basically I need a function that checks if a folder exists, and if it doesn't it creates it.
If Not System.IO.Directory.Exists(YourPath) Then
System.IO.Directory.CreateDirectory(YourPath)
End If
Under System.IO, there is a class called Directory.
Do the following:
If Not Directory.Exists(path) Then
Directory.CreateDirectory(path)
End If
It will ensure that the directory is there.
Try the System.IO.DirectoryInfo class.
The sample from MSDN:
Imports System
Imports System.IO
Public Class Test
Public Shared Sub Main()
' Specify the directories you want to manipulate.
Dim di As DirectoryInfo = New DirectoryInfo("c:\MyDir")
Try
' Determine whether the directory exists.
If di.Exists Then
' Indicate that it already exists.
Console.WriteLine("That path exists already.")
Return
End If
' Try to create the directory.
di.Create()
Console.WriteLine("The directory was created successfully.")
' Delete the directory.
di.Delete()
Console.WriteLine("The directory was deleted successfully.")
Catch e As Exception
Console.WriteLine("The process failed: {0}", e.ToString())
End Try
End Sub
End Class
Since the question didn't specify .NET, this should work in VBScript or VB6.
Dim objFSO, strFolder
strFolder = "C:\Temp"
Set objFSO = CreateObject("Scripting.FileSystemObject")
If Not objFSO.FolderExists(strFolder) Then
objFSO.CreateFolder strFolder
End If
Try this: Directory.Exists(TheFolderName) and Directory.CreateDirectory(TheFolderName)
(You may need: Imports System.IO)
VB.NET? System.IO.Directory.Exists(string path)
Directory.CreateDirectory() should do it.
http://msdn.microsoft.com/en-us/library/system.io.directory.createdirectory(VS.71).aspx
Also, in Vista, you probably cannot write into C: directly unless you run it as an admin, so you might just want to bypass that and create the dir you want in a sub-dir of C: (which i'd say is a good practice to be followed anyways. -- its unbelievable how many people just dump crap onto C:
Hope that helps.
(imports System.IO)
if Not Directory.Exists(Path) then
Directory.CreateDirectory(Path)
end if
If Not Directory.Exists(somePath) then
Directory.CreateDirectory(somePath)
End If
You should try using the File System Object or FSO. There are many methods belonging to this object that check if folders exist as well as creating new folders.
I see how this would work, what would be the process to create a dialog box that allows the user name the folder and place it where you want to.
Cheers
Just do this:
Dim sPath As String = "Folder path here"
If (My.Computer.FileSystem.DirectoryExists(sPath) = False) Then
My.Computer.FileSystem.CreateDirectory(sPath + "/<Folder name>")
Else
'Something else happens, because the folder exists
End If
I declared the folder path as a String (sPath) so that way if you do use it multiple times it can be changed easily but also it can be changed through the program itself.
Hope it helps!
-nfell2009