VBA Error 91 - Object or With block Variable not set - vba

Kindly do not mark duplicate as I have properly checked for other related solutions specific to Error 91 but none of those seem to fetch me the solution for the problem I am facing .
Am trying to convert my coreldraw files nested in various folders (about 500 files ) using the following VBA code but its either crashing the application or showing the Error 91 'Object or With Block Variable not set'. The same code absolutely works fine when used with the other Demo Set of files which i created to test.
One case I could presume is the file showing some dialog when processing the script. If yes how should I prevent those dialog boxes. Application.DisplayAlerts = False not working in coreldraw.
But however that case is only an assumption. Can someone help me find the problem. Heres the code
Sub NewFolder()
Dim FileSystem As Object
Dim HostFolder As String
HostFolder = "My folder Path"
Set FileSystem = CreateObject("Scripting.FileSystemObject")
DoFolder FileSystem.GetFolder(HostFolder)
End Sub
Sub DoFolder(folder)
Dim SubFolder
For Each SubFolder In folder.SubFolders
DoFolder SubFolder
Next
Dim File
For Each File In folder.Files
If InStr(File.Name, ".cdr") Then
Application.OpenDocument (File)
End If
Dim filepath As String
filepath = ActiveDocument.FullFileName
Dim doc1 As Document
Dim SaveOptions As StructSaveAsOptions
Set SaveOptions = CreateStructSaveAsOptions
Set doc1 = ActiveDocument
With SaveOptions
.EmbedVBAProject = True
.Filter = cdrCDR
.IncludeCMXData = False
.Range = cdrAllPages
.EmbedICCProfile = True
.Version = cdrVersion17
End With
doc1.SaveAs filepath, SaveOptions
doc1.Close
' Operate on each file
Next
End Sub

I'd say you must check if a valid corel draw file has been found
I don't know CorelDraw VBA but I'd assume you could get the following code as a good start:
Sub DoFolder(folder)
Dim SubFolder
For Each SubFolder In folder.SubFolders
DoFolder SubFolder
Next
Dim file
Dim doc1 As Document
Dim filepath As String
Dim SaveOptions As StructSaveAsOptions
For Each file In folder.Files
If InStr(file.Name, ".cdr") Then
Set doc1 = GetDocument(file) '<--| try and get a valid CorelDraw document with the given file: see 'GetDocument()' function at the bottom
If Not doc1 Is Nothing Then '<--| if you succeed then go on with your code
filepath = ActiveDocument.FullFileName
Set SaveOptions = CreateStructSaveAsOptions
With SaveOptions
.EmbedVBAProject = True
.Filter = cdrCDR
.IncludeCMXData = False
.Range = cdrAllPages
.EmbedICCProfile = True
.Version = cdrVersion17
End With
doc1.SaveAs filepath, SaveOptions
doc1.Close
End If
End If
' Operate on each file
Next
End Sub
Function GetDocument(file As Variant) As Document
On Error Resume Next
Set GetDocument = OpenDocument(file)
End Function
as a side note I collected all Dim statements outside loops not to have them run multiple time uselessly

Related

Searching a File in Directory

I would like to search a file in user-defined directory. My file structure like that xxx__description__myFileName__YYMMDD.txt there'll be multiple versions of this file so I want to list all files in directory which includes myFileName in their filename. Also I don't know is it the efficient way to list files with such type of code.
I tried to use this code but it gives me an error:
Run-time error '445': Object doesn't support this action
Sub findFiles()
Dim i As Integer
Dim myFile As String
myFileName = "ABC123"
With Application.FileSearch
.NewSearch
.LookIn = "C:\myTestDirectory"
.fileName = "*myFileName*.xlsx"
.SearchSubFolders = True
If .Execute() > 0 Then
For i = 1 To .FoundFiles.Count
Debug.Print .FoundFiles(i)
Next i
End If
End With
End Sub

Triple Loop to delete Empty Folders

I'm trying to delete those folders that are empty with a triple loop.
The order is:
1. Enter into the Main Folder.
2. Check the first encountered folder
3. Check the first subFolder of the main folder.
4. If that subFolder contains another folder, enter in this subSubFolder
5. If it is the last folder and doesn't contain anything, the program deletes it.
5.1 If the folder contains something (a file, excel, pdf, doesn't matter) just go to the next subSubFolder.
6. And goes on until there's no empty folders.
Basically the code must leave untouched the folders that contains a File.
But i don't know why the code doesn't continue and just stop without deleting the empty ones.
This is the Folder Structure:
Folder Path
And this is the code i'm using.:
Sub recursiveDeleting()
Dim sFldr As Object
Dim ssFldr As Object
Dim sssFldr As Object
Dim fs
Set fs = CreateObject("Scripting.FileSystemObject")
sFound = False
ssFound = False
sssFound = False
flPath = ActiveWorkbook.Path & "\"
YearPath = flPath & "2017\"
FARFIpath = YearPath & "\FAR_FI\"
For Each sFldr In CreateObject("Scripting.FileSystemobject").GetFolder(FARFIpath).SubFolders
For Each ssFldr In CreateObject("Scripting.FileSystemobject").GetFolder(sFldr).SubFolders
For Each sssFldr In CreateObject("Scripting.FileSystemobject").GetFolder(ssFldr).SubFolders
If Dir(sssFldr & "\*.*") = "" Then
RmDir (sssFldr)
Else
sssFound = True
End If
If sssFound = True Then
Exit For
End If
Next sssFldr
If fs.FolderExists(ssFldr) = "" Then
RmDir (ssFldr)
Else
ssFound = True
End If
If ssFound = True Then
Exit For
End If
Next ssFldr
If Dir(sFldr, vbDirectory) = "" Then
RmDir (sFldr)
sFound = True
End If
If sFound = True Then
Exit For
End If
Next sFldr
End Sub
Thanks for your time and have a good day!
Try below code, tested working (it will delete the root folder as well if it's empty afterwards. It can be mind blogging if you are to trace back the recursive code.
Sample - only a blank text file in highlighted folder (all others has no files).
Option Explicit
Private oFSO As Object
Sub DeleteEmptyFolder()
Dim oRootFDR As Object
Set oFSO = CreateObject("Scripting.FileSystemObject")
Set oRootFDR = oFSO.GetFolder("C:\Test\mount") '<--- Change to your root folder
If DeleteEmptyFolderOnly(oRootFDR) Then
oRootFDR.Delete
End If
Set oRootFDR = Nothing
Set oFSO = Nothing
End Sub
Private Function DeleteEmptyFolderOnly(ByRef oFDR As Object) As Boolean
Dim bDeleteFolder As Boolean, oSubFDR As Object
bDeleteFolder = False
' Recurse into SubFolders
For Each oSubFDR In oFDR.SubFolders
If DeleteEmptyFolderOnly(oSubFDR) Then
Debug.Print "Delete", oSubFDR.Path ' Comment for production use
oSubFDR.Delete
End If
Next
' Mark ok to delete when no files and subfolders
If oFDR.Files.Count = 0 And oFDR.SubFolders.Count = 0 Then
bDeleteFolder = True
End If
DeleteEmptyFolderOnly = bDeleteFolder
End Function
After the code executed, Folders remained are:
And the immediate window shows the folders that are deleted:

VBA Verify File extension as excel file?

I run this vba which goes through folders and pulls data which it compiles together in one big sheet. My issue is I was getting errors for hidden files called thumbs.db and I need to add something so that it verifies that it is only pulling files with xlsx extensions. Below is the code I am using.
Sub DoFolder(Folder)
Dim SubFolder As Folder
Dim i As Integer
Dim CopyR As Range
For Each SubFolder In Folder.SubFolders
DoFolder SubFolder
Next
If Folder.SubFolders.Count = 0 Then
If Folder.Files.Count = 1 Then
If Mid(Folder.Files, Len(Folder.Files) - 3, 4) = "xlsx" Then
Else: MsgBox "2+ files: " & Folder.Path
End If
End If
For Each File In Folder.Files
Hoover File
Next
Else
End If
End Sub
The line I am having issues with figuring out is
If Mid(Folder.Files, Len(Folder.Files) - 3, 4) = "xlsx" Then
Any help on this would be really appreciated
Folder.Files is a collection not a string.
Recursive File Search:
Sub DoFolder(FolderName As String, Optional fso As Object)
Dim f As Object, MySubFolder As Object, RootFolder As Object
Dim cFiles As Collection
If fso Is Nothing Then Set fso = CreateObject("Scripting.FileSystemObject")
Set RootFolder = fso.GetFolder(FolderName)
For Each MySubFolder In RootFolder.SubFolders
DoFolder MySubFolder.Path, fso
Next
Set cFiles = New Collection
For Each f In RootFolder.Files
If f.Name Like "*xls*" Then cFiles.Add f
Next
If cFiles.Count > 0 Then
MsgBox cFiles.Count & " files found in " & RootFolder.Name
For Each f In cFiles
Hoover f
Next
End If
End Sub
A quick solution is simply to check for xlsx being contained in the name of the file. Like this:
If InStr(1,"FileName","xlsx",vbTextCompare)<1 then
Thus, you would be in the safe side, unless someone renames thumbs.db to thumbsxlsx.db.
Assuming you're using the FileSystemObject, which it looks like you are even though we can't see the declarations, and assuming you're only wanting to call Hoover for .xlsx files you can use the following code
If Right(File.Name, 4) = "xlsx" Then
Hoover File
End If
As a further improvement to the answer by user6432984.. FSO does have a function to obtain the file extension, but the function is not part of the File object, but is the fso.GetExtensionName()
You would expect that the File.Type property could be used, but that gives the application name associated with that file extension - not very useful.
If f.Type Like "*xls*" Then cFiles.Add f
However the FSO-based function works as follows:
For Each f In RootFolder.Files
If fso.GetExtensionName(f.Path) Like "*xls*" Then cFiles.Add f
Next

FileSystemObject.CreateFolder to create directory and subdirectories

I would like to create a directory and a subdirectory with the following code:
Public fso As Scripting.FileSystemObject
Set fso = New Scripting.FileSystemObject
fso.CreateFolder ("C:\Users\<my_username>\DataEntry\logs")
I am trying to create nested directories. In this case, the DataEntry directory would not exist, so essentially I would like to create 2 directories, DataEntry\logs under C:\Users\<username>
If I enter command prompt, I can create that directory with mkdir without any issues. However, I simply cannot get VBA to create that folder and I get:
Run-time error '76':
Path not found
I am using Excel VBA 2007/2010
tigeravatar's looping answer might work, but it's a bit hard to read. Instead of micromanaging the string handling yourself, the FileSystemObject has path manipulation functions available, and recursion is slightly easier to read than a loop.
Here is the function I use:
Function CreateFolderRecursive(path As String) As Boolean
Dim FSO As New FileSystemObject
'If the path exists as a file, the function fails.
If FSO.FileExists(path) Then
CreateFolderRecursive = False
Exit Function
End If
'If the path already exists as a folder, don't do anything and return success.
If FSO.FolderExists(path) Then
CreateFolderRecursive = True
Exit Function
End If
'recursively create the parent folder, then if successful create the top folder.
If CreateFolderRecursive(FSO.GetParentFolderName(path)) Then
If FSO.CreateFolder(path) Is Nothing Then
CreateFolderRecursive = False
Else
CreateFolderRecursive = True
End If
Else
CreateFolderRecursive = False
End If
End Function
Need to create each folder one at a time. You can use code like this to do so:
Sub tgr()
Dim strFolderPath As String
Dim strBuildPath As String
Dim varFolder As Variant
strFolderPath = "C:\Users\<my_username>\DataEntry\logs"
If Right(strFolderPath, 1) = "\" Then strFolderPath = Left(strFolderPath, Len(strFolderPath) - 1)
For Each varFolder In Split(strFolderPath, "\")
If Len(strBuildPath) = 0 Then
strBuildPath = varFolder & "\"
Else
strBuildPath = strBuildPath & varFolder & "\"
End If
If Len(Dir(strBuildPath, vbDirectory)) = 0 Then MkDir strBuildPath
Next varFolder
'The full folder path has been created regardless of nested subdirectories
'Continue with your code here
End Sub
Agree with MarkD's suggestion to utilize recursion, it was the code I came here looking to find. In a scenario where the path provided uses a nonexistent root folder it will result in an infinite loop. Adding to MarkD's solution to check for zero length path.
Function CreateFolderRecursive(path As String) As Boolean
Static FSO As FileSystemObject
'Initialize FSO variable if not already setup
If FSO Is Nothing Then Set lFSO = New FileSystemObject
'Is the path paramater populated
If Len(path) = 0 Then
CreateFolderRecursive = False
Exit Function
End If
'If the path exists as a file, the function fails.
If FSO.FileExists(path) Then
CreateFolderRecursive = False
Exit Function
End If
'If the path already exists as a folder, don't do anything and return success.
If FSO.FolderExists(path) Then
CreateFolderRecursive = True
Exit Function
End If
'recursively create the parent folder, then if successful create the top folder.
If CreateFolderRecursive(FSO.GetParentFolderName(path)) Then
If FSO.CreateFolder(path) Is Nothing Then
CreateFolderRecursive = False
Else
CreateFolderRecursive = True
End If
Else
CreateFolderRecursive = False
End If
End Function

using Application.FileDialog to rename a file in VBA

Using VBA. My script moves a file into a directory. If that filename already exists in the target directory, I want the user to be prompted to rename the source file (the one that's being moved) before the move is executed.
Because I want the user to know what other files are in the directory already (so they don't choose the name of another file that's already there), my idea is to open a FileDialog box listing the contents of the directory, so that the user can use the FileDialog box's native renaming capability. Then I'll loop that FileDialog until the source file and target file names are no longer the same.
Here's some sample code:
Sub testMoveFile()
Dim fso As FileSystemObject
Dim file1 As File
Dim file2 As File
Dim dialog As FileDialog
Set fso = New FileSystemObject
fso.CreateFolder "c:\dir1"
fso.CreateFolder "c:\dir2"
fso.CreateTextFile "c:\dir1\test.txt"
fso.CreateTextFile "c:\dir2\test.txt"
Set file1 = fso.GetFile("c:\dir1\test.txt")
Set file2 = fso.GetFile("c:\dir2\test.txt")
Set dialog = Application.FileDialog(msoFileDialogOpen)
While file1.Name = file2.Name
dialog.InitialFileName = fso.GetParentFolderName(file2.Path)
If dialog.Show = 0 Then
Exit Sub
End If
Wend
file1.Move "c:\dir2\" & file1.Name
End Sub
But when I rename file2 and click 'OK', I get an error:
Run-time error '53': File not found
and then going into the debugger shows that the value of file2.name is <File not found>.
I'm not sure what's happening here--is the object reference being lost once the file's renamed? Is there an easier way to let the user rename from a dialog that shows all files in the target directory? I'd also like to provide a default new name for the file, but I can't see how I'd do that using this method.
edit: at this point I'm looking into making a UserForm with a listbox that gets populated w/ the relevant filenames, and an input box with a default value for entering the new name. Still not sure how to hold onto the object reference once the file gets renamed, though.
Here's a sample of using Application.FileDialog to return a filename that the user selected. Maybe it will help, as it demonstrates getting the value the user provided.
EDIT: Modified to be a "Save As" dialog instead of "File Open" dialog.
Sub TestFileDialog()
Dim Dlg As FileDialog
Set Dlg = Application.FileDialog(msoFileDialogSaveAs)
Dlg.InitialFileName = "D:\Temp\Testing.txt" ' Set suggested name for user
' This could be your "File2"
If Dlg.Show = -1 Then
Dim s As String
s = Dlg.SelectedItems.Item(1) ` Note that this is for single-selections!
Else
s = "No selection"
End If
MsgBox s
End Sub
Edit two: Based on comments, I cobbled together a sample that appears to do exactly what you want. You'll need to modify the variable assignments, of course, unless you're wanting to copy the same file from "D:\Temp" to "D:\Temp\Backup" over and over. :)
Sub TestFileMove()
Dim fso As FileSystemObject
Dim SourceFolder As String
Dim DestFolder As String
Dim SourceFile As String
Dim DestFile As String
Set fso = New FileSystemObject
SourceFolder = "D:\Temp\"
DestFolder = "D:\Temp\Backup\"
SourceFile = "test.txt"
Set InFile = fso.GetFile(SourceFolder & SourceFile)
DestFile = DestFolder & SourceFile
If fso.FileExists(DestFile) Then
Dim Dlg As FileDialog
Set Dlg = Application.FileDialog(msoFileDialogSaveAs)
Dlg.InitialFileName = DestFile
Do While True
If Dlg.Show = 0 Then
Exit Sub
End If
DestFile = Dlg.Item
If Not fso.FileExists(DestFile) Then
Exit Do
End If
Loop
End If
InFile.Move DestFile
End Sub
Here's some really quick code that I knocked up but basically looks at it from a different angle. You could put a combobox on a userform and get it to list the items as the user types. Not pretty, but it's a start for you to make more robust. I have hardcoded the directory c:\ here, but this could come from a text box
Private Sub ComboBox1_KeyUp(ByVal KeyCode As MSForms.ReturnInteger,
ByVal Shift As Integer)
Dim varListing() As Variant
Dim strFilename As String
Dim strFilePart As String
Dim intFiles As Integer
ComboBox1.MatchEntry = fmMatchEntryNone
strFilePart = ComboBox1.Value
strFilename = Dir("C:\" & strFilePart & "*.*", vbDirectory)
Do While strFilename <> ""
intFiles = intFiles + 1
ReDim Preserve varListing(1 To intFiles)
varListing(intFiles) = strFilename
strFilename = Dir()
Loop
On Error Resume Next
ComboBox1.List() = varListing
On Error GoTo 0
ComboBox1.DropDown
End Sub
Hope this helps. On error resume next is not the best thing to do but in this example stops it erroring if the variant has no files