Goal: Use open function to allow user to run commands on whichever file they choose to open across multiple functions(path is in a public function).
This is the initial function that prompts the user to select a file. That file path is saved in the variable "path". I made the function public with the intention of using "path" in multiple areas(globalization).
Public Function OpenFile1() As String
On Error GoTo Trap
Dim fd As FileDialog
Set fd = Application.FileDialog(msoFileDialogFilePicker)
With fd
.Title = "Open Sterling Shipment History" 'Name for file
.Filters.Clear
.ButtonName = " Open "
.AllowMultiSelect = False
End With
If fd.Show <> 0 Then OpenFile1 = fd.SelectedItems(1)
Leave:
Set fd = Nothing
On Error GoTo 0
Exit Function
Trap:
MsgBox Err.Description, vbCritical
Resume Leave
Dim path As String
path = OpenFile1() 'Calls in file
If path <> vbNullString Then Debug.Print path
Workbooks.Open (path)
'rename the path variable for each function
'so that I can call in different files with that name
End Function
This is an excerpt of the second function that attempts to call the file path from the variable "path", use it to open the workbook and alter the workbook.
Sub Shipment_History()
Call OpenFile1
Dim sshist As Workbook
Set sshist = Workbooks.Open(path)
Columns("E:E").Select
Selection.Insert Shift:=xlToRight, CopyOrigin:=xlFormatFromLeftOrAbove
I also tried:
Sub Shipment_History()
Call OpenFile1
Workbooks.Open(path)
My issue is it isn't allowing me to open "path".
The error states
"Run-time error '1004': Sorry, we couldn't find. Is it possible it was
moved, renamed or deleted?"
Since the function returns a string (path) and it is publicly available, you dont need a public variable to store the path.
Declare the path variable locally and set it's value to the value (path) returned from the function:
Sub Shipment_History()
Dim path as string
path = OpenFile1()
If path <> vbNullString Then Workbooks.Open(path)
End Sub
p.s. Remove everything after Resume Leave except the End Function statement.
path must be declared outside any Function or Subscript as a public String, the function doesnt need to be public, its the variable.
Try this on a module:
Public path As String
Function setPathValue(ByVal dataPassed As String)
path = dataPassed
End Function
Sub givePathVal()
setPathValue ("This is path value")
End Sub
Sub showPathVal()
MsgBox path
End Sub
Related
i am trying to access variables across several modules, sheets and workbooks.
i'm not even able to share them across modules in same workbook...
i wonder what's missing. In this case, i want to open a file and then share its name across modules in order to manipulate it through other functions.
When running this procedure "Sub get_workbook_and_sheets_names_S", it asks to run a macro (I chose Sub myMain), but then I only got the macro output.
Sub myMain()
Dim i As Integer
Static v_sheet_name_S As Variant
Static v_workbook_name_S As Variant
'Call f_FSOGetFileName_S
With Application.Workbooks(f_FSOGetFileName_S)
v_workbook_name_S = .Name
Debug.Print "this is WORKBOOK : " & v_workbook_name_S
For i = 1 To .Sheets.Count
v_sheet_name_S = .Sheets(i).Name
Debug.Print "this is workbook SHEET : " & v_sheet_name_S
Next
End With
'Call f_FSOGetFileName_T
End Sub
Function f_FSOGetFileName_S() 'OPEN SOURCE FILE
Dim v_strFile_S As String
Dim v_FileName_S As String
Dim v_FSO_S As New FileSystemObject
Dim v_FileNameWOExt_S As Variant
Set v_FSO_S = CreateObject("Scripting.FileSystemObject")
'get file full path
v_strFile_S = Application.GetOpenFilename(filefilter:="Excel files,*.x*", Title:="select SOURCE file")
Workbooks.Open Filename:=v_strFile_S
'Get File Name
v_FileName_S = v_FSO_S.GetFileName(v_strFile_S)
'Get File Name no Extension
v_FileNameWOExt_S = Left(v_FileName_S, InStr(v_FileName_S, ".") - 1)
f_FSOGetFileName_S = v_FileName_S 'FUNCTION RESULT
End Function
Sub get_workbook_and_sheets_names_S(v_workbook_name_S, v_sheet_name_S)
Debug.Print "Source workbook name : " & v_workbook_name_S
Debug.Print "Source sheet name : " & v_sheet_name_S
End Sub
In order to create a Global variable, please proceed in the next way:
Create a Public variable on top of a standard module (in the declarations area):
Public v_workbook_name_S As String
This variable can be accessed/used from all modules of the workbook where it has been declared. You should simple use:
Debug.print v_workbook_name_S
Of course, the variable must previously receive a value...
In order to be accessible from other workbooks, you should also create a function (**not Private) in the workbook where the global variable has been declared. In a standard module, too:
Sub setGobVarStr()
v_workbook_name_S = "myString"
End Sub
The global variable value can be accessed colling the above function, using:
Sub testReadGlobalVar()
Dim wbName As String, myName As String
wbName = "Teste Forum StackOverflow Last.xlsm"
myName = Application.Run("'" & wbName & "'!getWbName")
Debug.Print myName
End Sub
Of course, the global variable should previously received a value. If not, the code will return a VBNullString, anyhow...
Note:
You must not declare the same variable inside the colling Sub/Function! In such a case, the code will not raise any error, but it will rewrite the global variable and return a VBnullString, too...
I'm facing a problem that I really don't understand.
I created a macro that opens a workbooks, reads some information in it, and closes it.
To open the workbook, I use these lines:
Path = Func_Use_File_DialogOpen()
If Path <> "" Then
Set wb_chosen = Application.Workbooks.Open(Path, UpdateLinks:=0)
ElseIf Path = "" Then
MsgBox ("Error, start again")
Exit Sub
End If
For your information, the variable Path contains the whole path of the file, with the extension.
Example: Path= C:\Users\alex\Desktop\file.xlsm
On my computer, the macro works perfectly, it opens the worbook, and I can use it with my variable called wb_chosen
But when I send my macro to a coworker, he gets the error
"RUNTIME ERROR 91: Object variable or With Block variable not set"
How is that possible? when I try to debug the macro on his computer, I see that the variable path is perfectly fine (like on my computer), but the variable wb_chosen is nothing
so the problem is on the line :
Set wb_chosen = Application.Workbooks.Open(Path, UpdateLinks:=0)
Could it be the Application.Workbooks that doesn't work?
I really need this macro to work on every computer, is there a parameter to change on Excel? should I just put this instead?
Workbooks.Open(Path)
FYI, here are some other details about the code
The workbook is declared like this
Public wb_chosen As Workbook
the function Func_Use_File_DialogOpen() is as follow:
Public Function Func_Use_File_DialogOpen() As String
On Error GoTo lblErr
With Application.FileDialog(msoFileDialogFilePicker)
.AllowMultiSelect = False
.Show
Func_Use_File_DialogOpen = .SelectedItems(1)
End With
Exit Function
lblErr:
MsgBox Err.Description, vbCritical, "Error"
Func_Use_File_DialogOpen = vbNullString
End Function
The variable Path is a string that store the full path of the file. When I run the code on my computer, i have
Path=\\cm\TA\PNL\10 - octobre\pnl_Octobre.xlsm
My existing userform requires a folder path to be selected, to save to. If not, then the output functionality is disabled.
Note that the select folder and output functions work.
I've set the system up to save the folder that the user has last used to the registry. I can recall it as a string from the registry. When I try to set the path string (Line: Set WorkFolder) to the returned folder string value as an object(?), it crashes as a 424 object required error.
I found how to get things in and out of the registry. It's getting the Set WorkFolder to accept what is being pulled from the registry that is causing me grief.
The text box is disabled and is updated once a valid file dialog selection is complete so the user knows what path is being used.
I want to populate it with registry recall value (which works) and then set the WorkFolder to the path string value removing the "nothing".
When debugging and hovering over sResult, I have the proper string in the tooltip, I just need to plug that into Set WorkFolder.
Private Sub BtnSelectFolder_Click()
' ===== FOLDER SELECTION BY USER (MANDATORY) =====
Dim fd As FileDialog
Dim result As Long, errNum As Long
'-------------------------------
'Trouble section
Dim oWSH As Object
Dim sResult
Dim KeyId, Rootkey
Rootkey = "HKCU"
KeyId = "Software\VB and VBA Program Settings\MyApplication\WorkbookPath\SaveFolder"
If oWSH Is Nothing Then
Set oWSH = CreateObject("WScript.Shell")
End If
sResult = oWSH.RegRead(Rootkey & "\" & KeyId)
Set WorkFolder = sResult '<<<<<<<<< Why won't this work? Error 424 Object required, but path is pulled from Registry successfully
'Trouble section
'-------------------------------
'All works below
Set fd = Application.FileDialog(msoFileDialogFolderPicker)
With fd
.AllowMultiSelect = False
.ButtonName = "Select"
.Title = "Choose Output Folder"
If InStr(UCase(.InitialFileName), "SYSTEM32") Then
.InitialFileName = Environ("USERPROFILE") & "\Documents"
End If
result = .Show
End With
' Drop if box cancelled
If result = 0 Then Exit Sub
' Made it here; try updating the linked folder, with error handling
On Error Resume Next
Set WorkFolder = fs.GetFolder(fd.SelectedItems(1))
errNum = Err.Number: Err.Clear: On Error GoTo 0
If errNum <> 0 Then
MsgBox "Invalid folder selection", _
vbOKOnly + vbCritical, _
"Error"
Exit Sub
End If
' Update display textbox
TxBxFolder.Value = WorkFolder.Path
'Save path to registry
SaveSetting "MyApplication", "WorkbookPath", "SaveFolder", WorkFolder.Path
' Update the Export button
setExportEnabled
Call CheckExportIsEnabled
End Sub
Assuming WorkFolder is declared (somewhere?) as a String, then a String is not an object in VBA - you can't Set it.
Set WorkFolder = sResult
I doubt WScript.Shell returns an Object you can Set. If it's a String, then you want a simple Let assignment here:
WorkFolder = sResult '<~ implicit: Let WorkFolder = sResult
Different story here:
Set WorkFolder = fs.GetFolder(fd.SelectedItems(1))
Where if I had to guess I'd think fs is a Scripting.FileSystemObject (where is that declared & assigned, and why is it not in sight where it's used?), whose GetFolder method does return a Scrpiting.Folder object reference.
You are reusing variables, giving them different meanings and responsibilities: that's how bugs happen.
One variable, one purpose.
I have a activex button trying to get it to check folder for a specific set of .txt files. I would like to compare all files names against a list of files names to see what is not listed inside the folder. Also within this check for files module is a publicvariable call to list the folder path (that the user picked with folderpicker) but haven't got it to work. This same publicvariable should be in the next line down in the Msgbox listing the folder path that was selected. I can place a list of files anywhere in the workbook. Currently, I have working a check file module that returns a message whether or not file exist.
I was just able to get my public variable to work. This is not what i do so learning by reading and learning how to asks questions. By moving lines /words around I have been able to get a few things working. Although, I sure it is not the most efficient way.
'Working but only checks one file at a time. and hard coded
Sub CheckFolderForFiles()
'
' CheckFolderForFiles Macro
'
'Check if file exist
If Dir$("C:\txtdata\cf_preferences.txt") = "" Then
MsgBox "C:\txtdata\cf_preferences.txt - File not found"
Exit Sub
End If
____________________________________
' Not working - Just testing public variable call for Dir$ and figure out MsgBox areas.
Sub CheckFolderForFiles()
'
' CheckFolderForFiles Macro
'
'Check if file exist
If Dir$(Module33.fle + "\alerts.txt") = "" Then
MsgBox & fle & "alerts.txt - File not found"
Exit Sub
End If
'
'
End Sub
__________________________________
'Folder Picker FileDialog user select folder.
'After some guidence by one our your users I was able to get this module work.
'Now have a public variable I wish to use throughtout the workbook to
'call the path.
Public fle As String
Sub FolderPicker()
Dim diaFolder As FileDialog
Set diaFolder = Application.FileDialog(msoFileDialogFolderPicker)
diaFolder.AllowMultiSelect = False
diaFolder.Show
fle = diaFolder.SelectedItems(1)
Range("M11") = fle
Set diaFolder = Nothing
End Sub
-------------------------------
Sub CheckFolderForFiles()
'
' CheckFolderForFiles Macro
'
'Check if file exist
'
'
If Dir$(Module33.fle + "\alerts.txt") = "" Then
MsgBox Module33.fle + "\alerts.txt - File not found"
End If
'
If Dir$(Module33.fle + "\cf_messages.txt") = "" Then
MsgBox Module33.fle + "\cf_messages.txt - File not found"
End If
End Sub
----------------------------
I'm trying to learn this to help with my wife's work project. so please be patient with my descriptions and lack of terminology. But if someone could guide me to a script that compares files within a folder that came from the publicvariable and tell me all files missing from the list. (15 files in all) this would help a bunch. Also, anyone know how or if you can clear a publicvariable of it's stored data? googling is saying just put an ( End ) in the module. not working.
Thank You in Advance. I do appreciate the guidance.
Try this. I use ArrayList to filter out nonexisting files. If you want to print out a list of non existing files, just print out the remaining element of the arraylist FileList, you could google the syntax.
Sub TestFileExist()
Dim fd As FileDialog
Dim mFiles As Variant, Item As Variant
Dim FileList As Object, mRange As Range, strFile As String
Dim FilesInFolder() As String
Dim i As Long
Set fd = Application.FileDialog(msoFileDialogFolderPicker)
With fd
.Title = "Select a folder"
.AllowMultiSelect = False
End With
If fd.Show = -1 Then
Set FileList = CreateObject("System.Collections.ArrayList")
Set mRange = Range("A1:A5") 'Range contains files' names
ReDim FilesInFolder(0) As String
strFile = Dir(fd.SelectedItems(1) & "\*.txt")
Do While Len(strFile) > 0
FilesInFolder(UBound(FilesInFolder)) = strFile
strFile = Dir
ReDim Preserve FilesInFolder(UBound(FilesInFolder) + 1) As String
Loop
For Each Item In mRange
If Not FileList.contains(Item.Value) Then
FileList.Add Item.Value
End If
Next Item
For i = 0 To UBound(FilesInFolder) - 1
If FileList.contains(FilesInFolder(i)) Then
FileList.Remove FilesInFolder(i)
End If
Next i
MsgBox FileList.Count 'Nbr of files not found
End If
End Sub
I have this code. It is supposed to check if a file exists and open it if it does. It does work if the file exists, and if it doesn't, however, whenever I leave the textbox blank and click the submit button, it fails. What I want, if the textbox is blank is to display the error message just like if the file didn't exist.
Runtime-error "1004"
Dim File As String
File = TextBox1.Value
Dim DirFile As String
DirFile = "C:\Documents and Settings\Administrator\Desktop\" & File
If Dir(DirFile) = "" Then
MsgBox "File does not exist"
Else
Workbooks.Open Filename:=DirFile
End If
something like this
best to use a workbook variable to provide further control (if needed) of the opened workbook
updated to test that file name was an actual workbook - which also makes the initial check redundant, other than to message the user than the Textbox is blank
Dim strFile As String
Dim WB As Workbook
strFile = Trim(TextBox1.Value)
Dim DirFile As String
If Len(strFile) = 0 Then Exit Sub
DirFile = "C:\Documents and Settings\Administrator\Desktop\" & strFile
If Len(Dir(DirFile)) = 0 Then
MsgBox "File does not exist"
Else
On Error Resume Next
Set WB = Workbooks.Open(DirFile)
On Error GoTo 0
If WB Is Nothing Then MsgBox DirFile & " is invalid", vbCritical
End If
I use this function to check for file existence:
Function IsFile(ByVal fName As String) As Boolean
'Returns TRUE if the provided name points to an existing file.
'Returns FALSE if not existing, or if it's a folder
On Error Resume Next
IsFile = ((GetAttr(fName) And vbDirectory) <> vbDirectory)
End Function
For checking existence one can also use (works for both, files and folders):
Not Dir(DirFile, vbDirectory) = vbNullString
The result is True if a file or a directory exists.
Example:
If Not Dir("C:\Temp\test.xlsx", vbDirectory) = vbNullString Then
MsgBox "exists"
Else
MsgBox "does not exist"
End If
A way that is clean and short:
Public Function IsFile(s)
IsFile = CreateObject("Scripting.FileSystemObject").FileExists(s)
End Function
Function FileExists(ByRef strFileName As String) As Boolean
' TRUE if the argument is an existing file
' works with Unicode file names
On Error Resume Next
Dim objFSO As Object
Set objFSO = CreateObject("Scripting.FileSystemObject")
FileExists = objFSO.FileExists(strFileName)
On Error GoTo 0
End Function
To make the function run faster, objFSO can be made a global variable and the code can be modified and saved in a module like this:
Option Explicit
Dim objFSO As Object
Function FileExists(ByRef strFileName As String) As Boolean
' TRUE if the argument is an existing file
' works with Unicode file names
On Error Resume Next
If objFSO Is Nothing Then Set objFSO = CreateObject("Scripting.FileSystemObject")
FileExists = objFSO.FileExists(strFileName)
On Error GoTo 0
End Function
For strFileName to be a unicode string, you can, for example, either get it from a cell value or define it in a special way, as Excel's VBE doesn't save string constants in Unicode. VBE does support Unicode strings already saved in string variables. You're gonna have to look this up for further details.
Hope this helps somebody ^_^
Maybe it caused by Filename variable
File = TextBox1.Value
It should be
Filename = TextBox1.Value
Speed of Various FileExists Methods
I needed to check file existence for many of my projects, so I wanted to determine the fastest option. I used the micro timer code (see Benchmarking VBA Code) to run the File Exist functions below the table against a local folder with 2865 files to see which was faster. Winner used GetAttr. Using FSO method for Test 2 was a bit faster with the object defined as a global than not, but not as fast as the GetAttr method.
------------------------------------------------------
% of Fastest Seconds Name
------------------------------------------------------
100.00000000000% 0.0237387 Test 1 - GetAttr
7628.42784145720% 1.8108896 Test 2 - FSO (Obj Global)
8360.93687615602% 2.0522254 Test 2 - FSO (Obj in Function)
911.27399562739% 0.2163246 Test 3 - Dir
969.96844814586% 0.2302579 Test 4 - Dir$
969.75108156723% 0.2302063 Test 5 - VBA.Dir
933.82240813524% 0.2216773 Test 6 - VBA.Dir$
7810.66612746275% 1.8541506 Test 7 - Script.FSO
Function FileExistsGA(ByVal FileSpec As String) As Boolean
' Karl Peterson MS VB MVP
Dim Attr As Long
' Guard against bad FileSpec by ignoring errors
' retrieving its attributes.
On Error Resume Next
Attr = GetAttr(FileSpec)
If Err.Number = 0 Then
' No error, so something was found.
' If Directory attribute set, then not a file.
FileExistsGA = Not ((Attr And vbDirectory) = vbDirectory)
End If
End Function
Function FSOFileExists(sFilePathNameExt As String) As Boolean
Dim fso As Object
Set fso = CreateObject("Scripting.FileSystemObject")
FSOFileExists = fso.FileExists(sFilePathNameExt)
Set fso = Nothing
End Function
Function FileExistsDir(sFilePathNameExt As String) As Boolean
If Len(Dir(sFilePathNameExt)) > 0 Then FileExistsDir = True
End Function
Function FileExistsDirDollar(sFilePathNameExt As String) As Boolean
If Len(Dir$(sFilePathNameExt)) > 0 Then FileExistsDirDollar = True
End Function
Function FileExistsVBADirDollar(sFilePathNameExt As String) As Boolean
If Len(VBA.Dir$(sFilePathNameExt)) > 0 Then FileExistsVBADirDollar = True
End Function
Function FileExistsVBADir(sFilePathNameExt As String) As Boolean
If Len(VBA.Dir(sFilePathNameExt)) > 0 Then FileExistsVBADir = True
End Function
Public Function IsFileSFSO(s)
IsFileSFSO = CreateObject("Scripting.FileSystemObject").FileExists(s)
End Function
I realize that this does not fully answer the OP, but is provides information on which of the answers provided seems to be most efficient.
I'll throw this out there and then duck.
The usual reason to check if a file exists is to avoid an error when attempting to open it. How about using the error handler to deal with that:
Function openFileTest(filePathName As String, ByRef wkBook As Workbook, _
errorHandlingMethod As Long) As Boolean
'Returns True if filePathName is successfully opened,
' False otherwise.
Dim errorNum As Long
'***************************************************************************
' Open the file or determine that it doesn't exist.
On Error Resume Next:
Set wkBook = Workbooks.Open(fileName:=filePathName)
If Err.Number <> 0 Then
errorNum = Err.Number
'Error while attempting to open the file. Maybe it doesn't exist?
If Err.Number = 1004 Then
'***************************************************************************
'File doesn't exist.
'Better clear the error and point to the error handler before moving on.
Err.Clear
On Error GoTo OPENFILETEST_FAIL:
'[Clever code here to cope with non-existant file]
'...
'If the problem could not be resolved, invoke the error handler.
Err.Raise errorNum
Else
'No idea what the error is, but it's not due to a non-existant file
'Invoke the error handler.
Err.Clear
On Error GoTo OPENFILETEST_FAIL:
Err.Raise errorNum
End If
End If
'Either the file was successfully opened or the problem was resolved.
openFileTest = True
Exit Function
OPENFILETEST_FAIL:
errorNum = Err.Number
'Presumabley the problem is not a non-existant file, so it's
'some other error. Not sure what this would be, so...
If errorHandlingMethod < 2 Then
'The easy out is to clear the error, reset to the default error handler,
'and raise the error number again.
'This will immediately cause the code to terminate with VBA's standard
'run time error Message box:
errorNum = Err.Number
Err.Clear
On Error GoTo 0
Err.Raise errorNum
Exit Function
ElseIf errorHandlingMethod = 2 Then
'Easier debugging, generate a more informative message box, then terminate:
MsgBox "" _
& "Error while opening workbook." _
& "PathName: " & filePathName & vbCrLf _
& "Error " & errorNum & ": " & Err.Description & vbCrLf _
, vbExclamation _
, "Failure in function OpenFile(), IO Module"
End
Else
'The calling function is ok with a false result. That is the point
'of returning a boolean, after all.
openFileTest = False
Exit Function
End If
End Function 'openFileTest()
Here is my updated code. Checks to see if version exists before saving and saves as the next available version number.
Sub SaveNewVersion()
Dim fileName As String, index As Long, ext As String
arr = Split(ActiveWorkbook.Name, ".")
ext = arr(UBound(arr))
fileName = ActiveWorkbook.FullName
If InStr(ActiveWorkbook.Name, "_v") = 0 Then
fileName = ActiveWorkbook.Path & "\" & Left(ActiveWorkbook.Name, InStr(ActiveWorkbook.Name, ".") - 1) & "_v1." & ext
End If
Do Until Len(Dir(fileName)) = 0
index = CInt(Split(Right(fileName, Len(fileName) - InStr(fileName, "_v") - 1), ".")(0))
index = index + 1
fileName = Left(fileName, InStr(fileName, "_v") - 1) & "_v" & index & "." & ext
'Debug.Print fileName
Loop
ActiveWorkbook.SaveAs (fileName)
End Sub
You should set a condition loop to check the TextBox1 value.
If TextBox1.value = "" then
MsgBox "The file not exist"
Exit sub 'exit the macro
End If
Hope it help you.