Trying to get clarification on an older post. Is there a way to call the choosefolder function in several different subroutines and not have the pop up window each time it is called. Basically trying to reuse the folder path selected initially to run different subroutines using that path.
Here is a sample of the code of found. I was able to get the base to work, but can't pass it into the 3 different subroutines that would call on the choose folder.
VBA - selecting a folder and referencing it as the path for a separate code
Make ChooseFolder() into a function and then reference it:
Public Function ChooseFolder()
Dim fldr As FileDialog
Dim sItem As String
Set fldr = Application.FileDialog(msoFileDialogFolderPicker)
With fldr
.Title = "Select a Folder"
.AllowMultiSelect = False
.InitialFileName = strPath
If .Show <> -1 Then GoTo NextCode
sItem = .SelectedItems(1)
End With
NextCode:
ChooseFolder = sItem
Set fldr = Nothing
End Function
Private Sub btn_LeaveReport()
Dim objFSO As Object
Dim objFolder As Object
Dim objFile As Object
Dim i As Integer
Dim sFldr As String
'Create an instance of the FileSystemObject
Set objFSO = CreateObject("Scripting.FileSystemObject")
sFldr = ChooseFolder()
Set objFolder = objFSO.GetFolder(sFldr)
i = 3
'loops through each file in the directory and prints their names and path
For Each objFile In objFolder.Files
'print file name
Cells(i + 1, 2) = objFile.Name
'print file path
Cells(i + 1, 3) = objFile.Path
i = i + 1
Next objFile
End Sub
Like this:
Sub Main()
Dim fldr As String
fldr = ChooseFolder()
If Len(fldr) > 0 Then
PartOne fldr
PartTwo fldr
PartThree fldr
Else
MsgBox "No folder selected"
End If
End Sub
Sub PartOne(fldr as String)
'use fldr
End Sub
Sub PartTwo(fldr as String)
'use fldr
End Sub
Sub PartThree(fldr as String)
'use fldr
End Sub
Related
I'm trying to add in a folder selection dialog into my code and I keep getting the run-time error "Object variable or With block variable not set". Honestly, I suspect that the problem is just me being dumb and might be as simple as a typo or me not understanding something simple about this function, but I just can't seem to figure it out.
Dim ofso As Scripting.FileSystemObject
Dim oFolder As Object
Dim oFile As Object
Dim i As Long, colFolders As New Collection, ws As Worksheet
Set ws = Sheets.Add(Type:=xlWorksheet, After:=ActiveSheet)
Set ofso = CreateObject("Scripting.FileSystemObject")
'Set oFolder = ofso.GetFolder("F:\") This is the line to be replaced with the folder picker and what was being used before.
'Start folder picker
Set FldrPicker = Application.FileDialog(msoFileDialogFolderPicker)
With FldrPicker
.Title = "Select A Target Folder"
.AllowMultiSelect = False
If .Show <> -1 Then Exit Sub 'Check if user clicked cancel button
oFolder = .SelectedItems(1) & "\"
End With
Then the code resumes with everything else that works fine when not using the folder picker thing.
Stepping through the code, it gives the error when it gets to the line
oFolder = .SelectedItems(1) & "\"
Maybe I just need another set of eyes to point out what I'm missing? Or maybe I'm just not understanding something fundamental here (I'm still learning). Either way, I need help.
I also tried playing with my object names
Set oFolder = Application.FileDialog(msoFileDialogFolderPicker)
With oFolder
.Title = "Select A Target Folder"
.AllowMultiSelect = False
If .Show <> -1 Then Exit Sub 'Check if user clicked cancel button
oFolder = .SelectedItems(1) & "\"
End With
And it still isn't working
Edit: Here is my full code without the folder picker, to show what I'm trying to do.
Sub GetFilesColFunc()
Application.ScreenUpdating = False
Dim ofso As Scripting.FileSystemObject
Dim FldrPicker As FileDialog
Dim oFolder As Object
Dim oFile As Object
Dim i As Long, colFolders As New Collection, ws As Worksheet
Set ws = Sheets.Add(Type:=xlWorksheet, After:=ActiveSheet)
Set ofso = CreateObject("Scripting.FileSystemObject")
Set oFolder = ofso.GetFolder("F:\")
On Error Resume Next
ws.Cells(1, 1) = "File Name"
ws.Cells(1, 2) = "File Type"
ws.Cells(1, 3) = "Date Created"
ws.Cells(1, 4) = "Date Last Modified"
ws.Cells(1, 5) = "Date Last Accessed"
ws.Cells(1, 6) = "File Path"
Rows(1).Font.Bold = True
Rows(1).Font.Size = 11
Rows(1).Borders(xlEdgeBottom).LineStyle = XlLineStyle.xlContinuous
Range("C:E").Columns.AutoFit
colFolders.Add oFolder 'start with this folder
Do While colFolders.Count > 0 'process all folders
Set oFolder = colFolders(1) 'get a folder to process
colFolders.Remove 1 'remove item at index 1
For Each oFile In oFolder.Files
ws.Cells(i + 2, 1) = oFile.Name
ws.Cells(i + 2, 2) = oFile.Type
ws.Cells(i + 2, 3) = oFile.DateCreated
ws.Cells(i + 2, 4) = oFile.DateLastModified
ws.Cells(i + 2, 5) = oFile.DateLastAccessed
ws.Cells(i + 2, 6) = oFolder.Path
i = i + 1
Next oFile
'add any subfolders to the collection for processing
For Each sf In oFolder.SubFolders
If Not SkipFolder(sf.Name) Then colFolders.Add sf 'Skips folders listed within the referenced function
Next sf
Loop
Application.ScreenUpdating = True
End Sub
You are confusing things, probably because you stared at your code for too long :)
I botched together an example for you that hopefully illustrates some of the confusing stuff. Please note: I haven't done VBA in ages
I divided up your problem into a few subsections.
A FileDialog (aka the folderpicker built-in in Office) returns strings. So I put that into its own function.
You cannot simply create an FSO Folder object by assigning a string to it. That is not how objects work, you have to bring them to live with the Set keyword. When you are new to VBS/VBA that is hard to understand at first. The GetFolder method from the Windows Scripting Host's FileSystemObject returns a Folder object. I put the output of that in the GetFSOFolder function. The GetFSOFolder returns an object, so you have to Set the variable (oFolder) that captures it
Without the fluff that you decorated your OP with, here is an example of how you could approach this to just get the oFolder in your OP.
It is probably longer than you want it to be, the reason being that I hope to clarify some things by being elaborate about it.
Sub Main()
Dim sFolder As String
sFolder = FolderPicker() 'get the string representation from FileDialog
If sFolder = "" Then
Debug.Print "No folder was selected"
Exit Sub
End If
'create a Folder object from the string
Dim oFolder As Object
Set oFolder = GetFSOFolder(sFolder)
'what do we have?
Debug.Print "Selected folder was: " & oFolder.path
End Sub
Function GetFSOFolder(path As String) As Object 'returns a Folder object if path is valid
Dim ofso As Scripting.FileSystemObject
Set ofso = CreateObject("Scripting.FileSystemObject")
Set GetFSOFolder = ofso.GetFolder(path) 'note the Set, we are returning an object
End Function
Function FolderPicker() As String 'takes care of the folder picking dialog stuff
Dim FldrPicker As FileDialog
'Start folder picker
Set FldrPicker = Application.FileDialog(msoFileDialogFolderPicker)
With FldrPicker
.Title = "Select A Target Folder"
.AllowMultiSelect = False
If .Show <> -1 Then Exit Function 'Check if user clicked cancel button
FolderPicker = .SelectedItems(1) '.SelectedItems(1) returns a string!
End With
End Function
I am trying to set up an excel sheet with a list of folders in a main folder (not including sub folders within the folders). I've succeeded in running a VBA to create the list and then I have used the list to add on the different information needed for each folder (see image of visual setup).
But I would like to be able to update the list, so whenever new folders are added to the main folder it will appear on the list in the sheet.
Is it possible to update the list to the format I have created either by macro, or button or automatically ?
Option Explicit
Sub ListFoldersInDirectory()
Dim objFSO As Object
Dim objFolders As Object
Dim objFolder As Object
Dim strDirectory As String
Dim arrFolders() As String
Dim FolderCount As Long
Dim FolderIndex As Long
With Application.FileDialog(msoFileDialogFolderPicker)
.InitialFileName = Application.DefaultFilePath & "\"
.Title = "Select Folder"
.Show
If .SelectedItems.Count = 0 Then
Exit Sub
End If
strDirectory = .SelectedItems(1)
End With
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFolders = objFSO.GetFolder(strDirectory).SubFolders
FolderCount = objFolders.Count
If FolderCount > 0 Then
ReDim arrFolders(1 To FolderCount)
FolderIndex = 0
For Each objFolder In objFolders
FolderIndex = FolderIndex + 1
arrFolders(FolderIndex) = objFolder.Name
Next objFolder
Worksheets.Add
Range("A1").Resize(FolderCount).Value = Application.Transpose(arrFolders)
Else
MsgBox "No folders found!", vbExclamation
End If
Set objFSO = Nothing
Set objFolders = Nothing
Set objFolder = Nothing
End Sub
My code should loop through Folders/Subs and determine if there is any file there.
I have 2 questions:
I am not getting any feedback if there are NO Folders/Subs in certain Folders. A specific case: If it detects files (not Folders), assume there are some files (Excel for instance) in it the program says "Empty Folder"?
On the Open Window dialog to select a Folder, if I click Cancel it gives me a Popup window stating: "Folder not empty..blabla..."
Sub Button1_click()
Dim FileSystem As Object
Dim HostFolder As String
Dim Answer As String
Dim fs, strFolderPath, oFolder
' *** Folder with Files to perform an action ***
HostFolder = GetSourceFolder()
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
' *** This is your folder to define ***
Set fs = CreateObject("Scripting.FileSystemObject")
strFolderPath = Application.ActiveWorkbook.Path
Set oFolder = fs.getfolder(strFolderPath)
If (oFolder.SubFolders.Count = 0) Then
' *** If folder is empty/full message ***
' * Folder is Empty *
MsgBox "Folder is empty!", vbOKOnly + vbInformation, "Information!"
Else
' * Folder isn't empty *
Answer = MsgBox("Folder not empty! Proceed with Macro?", vbYesNo + vbInformation + vbDefaultButton1, "Information!")
If Answer = vbNo Then Exit Sub
End If
Set fs = Nothing
Set FileSystem = CreateObject("Scripting.FileSystemObject")
Dim targetFolder As String
targetFolder = GetTargetFolder()
DoFolder FileSystem.getfolder(HostFolder)
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
End Sub
Function GetSourceFolder() As String
Dim fldr As FileDialog
Dim sItem As String
Set fldr = Application.FileDialog(msoFileDialogFolderPicker)
With fldr
.Title = "Select Source Folder"
.AllowMultiSelect = False
.InitialFileName = Application.DefaultFilePath
If .Show <> -1 Then GoTo NextCode
sItem = .SelectedItems(1)
End With
NextCode:
GetSourceFolder = sItem
Set fldr = Nothing
End Function
Function GetTargetFolder() As String
Dim fldr As FileDialog
Dim sItem As String
Set fldr = Application.FileDialog(msoFileDialogFolderPicker)
With fldr
.Title = "Select Output Folder"
.AllowMultiSelect = False
.InitialFileName = Application.DefaultFilePath
If .Show <> -1 Then GoTo NextCode
sItem = .SelectedItems(1)
End With
NextCode:
GetTargetFolder = sItem
Set fldr = Nothing
End Function
If you want to make separate procedure for selecting folder, you need to determine whether user selected anything. You can use Boolean return type of the function as a result of action and string for source folder which is passed by reference, which will be filled if user selected folder. Here's the basic code:
Sub Test()
Dim sourceFolder As String
'// Usage
If Not GetSourceFolder(sourceFolder) Then
MsgBox "No folder selected", vbExclamation
Exit Sub
End If
'// Go on with your code
End Sub
Function GetSourceFolder(ByRef sourceFolder As String) As Boolean
'// By default function will return False
With Application.FileDialog(msoFileDialogFolderPicker)
If .Show Then
sourceFolder = .SelectedItems(1)
GetSourceFolder = True
End If
End With
End Function
I have a folder with many sub-folders and inside of them more then 1000 Excel files.
There are two problems with the following code.
This will require me to click continue for each Excel file that needs compatibility
I need to apply that macro inside those files.
I mean that I want that macro to be available after the code runs on the files for reuse in other computer after sending those excel files to other computer
Sub ProcessFiles()
Dim objFolder As Object
Dim objFile As Object
Dim objFSO As Object
Dim MyPath As String
Dim myExtension As String
Dim FldrPicker As FileDialog
Set FldrPicker = Application.FileDialog(msoFileDialogFolderPicker)
With FldrPicker
.Title = "Select A Target Folder"
.AllowMultiSelect = False
If .Show <> -1 Then GoTo EmptyEnd
MyPath = .SelectedItems(1)
End With
Application.ScreenUpdating = False
Set objFSO = CreateObject("Scripting.FileSystemObject")
Call GetAllFiles(MyPath, objFSO)
Call GetAllFolders(MyPath, objFSO)
Application.ScreenUpdating = True
MsgBox "Complete."
EmptyEnd:
End Sub
Sub GetAllFiles(ByVal strPath As String, ByRef objFSO As Object)
Dim objFolder As Object
Dim objFile As Object
Set objFolder = objFSO.GetFolder(strPath)
For Each objFile In objFolder.Files
DoWork objFile.Path
Next objFile
End Sub
Sub GetAllFolders(ByVal strFolder As String, ByRef objFSO As Object)
Dim objFolder As Object
Dim objSubFolder As Object
Set objFolder = objFSO.GetFolder(strFolder)
For Each objSubFolder In objFolder.subfolders
Call GetAllFiles(objSubFolder.Path, objFSO)
Call GetAllFolders(objSubFolder.Path, objFSO)
Next objSubFolder
End Sub
Sub DoWork(strFile As String)
Dim wb As Workbook
If Right(strFile, 4) = "xlsx" Then
Set wb = Workbooks.Open(Filename:=strFile)
With wb
'Do your work here
......
.Close True
End With
End If
End Sub
Try the minor modifications in the code below (instead of your Sub ProcessFiles code)
Sub ProcessFiles()
Dim objFolder As Object
Dim objFile As Object
Dim objFSO As Object
Dim MyPath As String
Dim myExtension As String
Dim FldrPicker As FileDialog
Set FldrPicker = Application.FileDialog(msoFileDialogFolderPicker)
With FldrPicker
.Title = "Select A Target Folder"
.AllowMultiSelect = False
If .Show <> -1 Then Exit Sub ' < can use Exit Sub instead of GoTo
MyPath = .SelectedItems(1)
End With
Application.DisplayAlerts = False ' <-- add this line
Application.ScreenUpdating = False
Set objFSO = CreateObject("Scripting.FileSystemObject")
Call GetAllFiles(MyPath, objFSO)
Call GetAllFolders(MyPath, objFSO)
' restore default settings
Application.ScreenUpdating = True
Application.DisplayAlerts = True
MsgBox "Complete."
End Sub
So my code works before I put in the end if, but once I try to implement the condition for if cancel is selected, I get a "else without if " compile error or something like that. I'm basically trying to do this:
This is the portion of my code that I'm talking about:
Public Function ChooseFolder()
'Declaring variables
Dim fldr As FileDialog
Dim sItem As String
'Folder selection
Set fldr = Application.FileDialog(msoFileDialogFolderPicker)
With fldr
.Title = "Select a Folder"
.AllowMultiSelect = False
.InitialFileName = strPath
If .Show <> -1 Then GoTo NextCode
sItem = .SelectedItems(1)
NextCode:
ChooseFolder = sItem
Set fldr = Nothing
Else
MsgBox ("You did not select any folders")
End If
End With
End Function
Ok so the above has been fixed thanks to your help. What error I'm getting now (although it doesn't prevent the code from working is in this segment:
Private Sub btn_LeaveReport()
'Declaring variables
Dim objFSO As Object
Dim objFolder As Object
Dim objFile As Object
Dim i As Integer
Dim sFldr As String
'Create an instance of the FileSystemObject
Set objFSO = CreateObject("Scripting.FileSystemObject")
'Added this bc of stack overflow advice. Basically how to reference path via string
sFldr = ChooseFolder()
Set objFolder = objFSO.GetFolder(sFldr)
'Hardcoded version commented out since the above choose folder option is available
'Set objFolder = objFSO.GetFolder("D:\Administration\Time Sheets")
i = 3
'loops through each file in the directory and prints their names and path
For Each objFile In objFolder.Files
'print file name
Cells(i + 1, 2) = objFile.Name
'print file path
Cells(i + 1, 3) = objFile.Path
i = i + 1
Next objFile
End Sub
For some reason the Set objFolder is creating a runtime error regarding an invalid procedure call. However, the program still works so I'm confused what the issue is.
The problemis the line
If .Show <> -1 Then GoTo NextCode
In VBA this is already a complete IF clause, so the later ELSE and End If are missing the starting IF clause.
Is this what you are trying?
Public Function ChooseFolder()
'Declaring variables
Dim fldr As FileDialog
Dim sItem As String
'Folder selection
Set fldr = Application.FileDialog(msoFileDialogFolderPicker)
With fldr
.Title = "Select a Folder"
.AllowMultiSelect = False
.InitialFileName = strPath
If .Show = -1 Then
sItem = .SelectedItems(1)
ChooseFolder = sItem
Else
MsgBox ("You did not select any folders")
End If
End With
Set fldr = Nothing
End Function