Calling Shell - explorer search in VBA - Workaround - vba

I have a code in VBA that will call explorer with a given search parameter and will find and list files with a given name in explorer on a specific location.
code:
RetVal = Shell( _
"c:\Windows\explorer.exe ""search-ms:displayname=Search%20Results&crumb=System.Generic.String%3A~%3D" _
& filename & "%20kind%3A%3Dfolder&crumb=location:" _
& location, vbNormalFocus)
It works nicely while I was using it on English windows.
Is there any way to improve this code so it would work on other language platforms or at least a workaround for it to make it work on German Windows?
Edit:
To clarify what I need to happen:
There are hyperlinks in a workbook with different names (ex. "banana"), when a user opens a hyperlink named "banana", the script calls the shell, opens an explorer window and lists all the files (these files are not excel files like .xls) containing the word "banana" in an already defined folder.
Since other language Windows explorers use different search commands, it only works on English Windows.
A search on German Windows would look like something this:
search-ms:displayname=Suchergebnisse%20in%20"SYS%20(C%3A)"&crumb=System.Generic.String%3A & filename & &crumb=location: & location
If you want to try it yourselves note that the location should also look something like this: C%3A%5C for C:\ in order to make it work.
Edit2:
So I have figured out what the problem was. The part %20kind%3A%3Dfolder is different in German Windows, so as I got rid of that, it started working on both platforms.
Here is the working version:
RetVal = Shell("c:\Windows\explorer.exe ""search-ms:displayname=backup%20for:%20" & _
backup & "&crumb=System.Generic.String%3A~%3D" & backup & _
"%20&crumb=location:" & location, vbNormalFocus)
I am still looking for a way to get the same results without using Shell.

2nd Answer demonstrating FSO
Sub GetFiles()
Dim FSO as Object 'Late binding <- Prefered method
'or As New FileSystemObject for Early Binding
'but don't forget to add a reference to Scripting Runtime!
Dim oFile as Object
Dim oFolder as Object
Dim sFileSpec as String
Dim r As Integer
r = 1
sFileSpec = "banana"
Set FSO = CreateObject("Scripting.FileSystemObject")
Set oFolder = FSO.GetFolder("C:\path\to\Predefined\Folder\")
'Or use the folder picker method already used
For Each oFile In oFolder.Files
If Instr(1, oFile.Name, sFileSpec, vbTextCompare) Then
With Worksheets("Sheet1")
.Cells(r, 1) = "File Name:"
.Cells(r, 3) = "File Size:"
.Cells(r, 5) = "Date:"
.Cells(r, 2) = oFile.Name
.Cells(r, 4) = oFile.Size
.Cells(r, 5) = oFile.DateLastModified
End With
r = r + 1
End If
Next oFile
End Sub

#Jeanno nailed one method of getting all the files that matched "banana". This just tweaks his/her code to get all Word documents (but you can see that it will find.txt, .html, or . too). Another method would be to use a FileSystemObject (FSO) to do exactly this same thing. You could also use wscript (Windows Script Host) to get the information even though it would over complicate things. There are many ways to skin this cat. :)
Dim myFolder As String
Dim myFile As String
Dim wb As Workbook
Dim i As Long, tempLimit As Long
Dim r As Integer
r = 1
Application.FileDialog(msoFileDialogFolderPicker).Title = "Select Folder Containing .doc Files"
myFolder = Application.FileDialog(msoFileDialogFolderPicker)
With Application.FileDialog(msoFileDialogFolderPicker)
.AllowMultiSelect = False
.Show
If .SelectedItems.Count > 0 Then
myFolder = .SelectedItems(1)
End If
End With
myFile = Dir(myFolder & "\*.doc*")
Do While myFile <> ""
'Do what you need to do with the found files
Sheet1.Cells(r, 1).Value = myFile
'Call Dir again without arguments to loop through all files that matched our criteria
myFile = Dir
r = r + 1
Loop

Why not avoid using shell all together and use something like this,
Dim myFolder As String
Dim myFile As String
Dim wb as Workbook
Dim i As Long, tempLimit As Long
Application.FileDialog(msoFileDialogFolderPicker).Title = "Select Folder Containing Excel Files"
myFolder = Application.FileDialog(msoFileDialogFolderPicker)
With Application.FileDialog(msoFileDialogFolderPicker)
.AllowMultiSelect = False
.Show
If .SelectedItems.Count > 0 Then
myFolder = .SelectedItems(1)
End If
End With
myFile = Dir(myFolder & "\*.xls*")
Do While myFile <> ""
Set wb = Application.Workbooks.Open(myFolder & "\" & myFile)
...
Loop

Related

Move File into specified Parent Folder, if format of files are different make child folders as well

Respected Experts,
Today I have received a wonderful code which matches the folders name and move the files in them accordingly. However, i have forgotten to mention that it also requires to create a child folders within the folder if the files which moved are of different formats. there are 4 different formats of files (XML, PDF, RAR ZIP) i.e. If 100 files been moved into a Folder Name "Robert Davidson" and if out of 100 the 50 files are of XML and 50 files are PDF format then it automatically create 2 more child folders named XML and PDF within Robert Davidson and moved the files in them accordingly. I just have a request if anyone can amend the code. I hope I have clarified the question :)
Sub moveFilesToFolder()
Dim lRow As Long
Dim wb As Workbook
Dim ws As Worksheet
Dim ccell As Range
Dim fsO As Object, oFolder As Object, oFile As Object
Dim pathFiles As String, sFolderPath As String, sSource As String, sDestination As String
Set wb = ActiveWorkbook
lRow = Range("A" & Rows.Count).End(xlUp).Row
pathFiles = "E:\Archiving system\" 'could be gotten from wb technically
Set fsO = CreateObject("Scripting.FileSystemObject")
Set oFolder = fsO.GetFolder(pathFiles)
For Each oFile In oFolder.Files 'go through all the files
For Each ccell In Range("A2:A" & lRow).Cells 'go through all the folder-names
'Debug.Print ccell.Value2
'Debug.Print oFile.Name
If InStr(oFile.Name, ccell.Value2) > 0 Then 'if folder name is in file name
sFolderPath = wb.Path & "\" & ccell.Value2 & "\"
If Dir(sFolderPath, vbDirectory) <> "" Then 'if Folder exists
sDestination = sFolderPath & oFile.Name
If Dir(sDestination) = "" Then 'file doesn't exist yet
sSource = pathFiles & oFile.Name
'Debug.Print sSource
'Debug.Print sDestination
Call fsO.MoveFile(pathFiles & oFile.Name, sFolderPath & oFile.Name)
GoTo Skip
End If
Else
MsgBox ("Folder " & ccell.Value2 & " doesn't exist yet")
End If
End If
Next ccell
Skip:
Next oFile
End Sub
Thanks in Advance

VBA finds workbook, then gives an error saying it is missing

I'm using some code in VBA to open a workbook from a directory:
Application.ScreenUpdating = False
Dim StrFile As String
Dim src As Workbook
Dim books As Object
Set today = CreateObject("scripting.dictionary")
Set books = CreateObject("scripting.dictionary")
StrFile = Dir("C:\Users\userA\Documents\XXX\scripts" & "\*" & ".xlsm")
Do While Len(StrFile) > 0
MsgBox (StrFile)
Set src = Workbooks.Open(StrFile, True, True)
Call createInput
src.Close SaveChanges:=False
StrFile = Dir
Loop
Now this will find my workbook and print out the name in a MsgBox, but then when the below line is called, I get a Runtime 1004 error (not found, "Is it possible it was moved, renamed or deleted?"
Set src = Workbooks.Open(StrFile, True, True)
I don't understand how this is possible, as it is clearly demonstrating that the file exists. Can anyone guide me as to where I'm going wrong?
Any help is appreciated.
You are missing the path. Dir only returns the filename so unless "C:\Users\userA\Documents\XXX\scripts\" just happened to be the default path, the workbook will appear missing.
dim fp as string
fp = "C:\Users\userA\Documents\XXX\scripts\"
StrFile = Dir(fp & "*.xlsm")
Do While Len(StrFile) > 0
MsgBox (StrFile)
Set src = Workbooks.Open(fp & StrFile, True, True)
Call createInput
src.Close SaveChanges:=False
StrFile = Dir
Loop
You might want to look into using environ("USERPROFILE") to construct the string containing your path. e.g.:
fp = environ("USERPROFILE") & "\Documents\XXX\scripts\"

Using VBA to unzip file without prompting me once (choose "Yes to All" for any dialog box)

There is an unzipping code I'd like to adjust 4 my needs.
Sub Unzip()
Dim FSO As Object
Dim oApp As Object
Dim Fname As Variant
Dim FileNameFolder As Variant
Dim DefinePath As String
' Fname = Application.GetOpenFilename(filefilter:="Zip Files (*.zip), *.zip", MultiSelect:=False)
Fname = "C:\Users\michal\SkyDrive\csv\bossa\mstcgl.zip"
If Fname = False Then
'Do nothing
Else
'Destination folder
DefinePath = "C:\Users\michal\SkyDrive\csv\bossa\mstcgl_mst\" ' Change to your path / variable
If Right(DefinePath, 1) <> "\" Then
DefinePath = DefinePath & "\"
End If
FileNameFolder = DefinePath
' Delete all the files in the folder DefPath first if you want.
' On Error Resume Next
' Kill DefPath & "*.*"
' On Error GoTo 0
'Extract the files into the Destination folder
Set oApp = CreateObject("Shell.Application")
oApp.Namespace(FileNameFolder).CopyHere oApp.Namespace(Fname).items
' MsgBox "You find the files here: " & FileNameFolder
On Error Resume Next
Set FSO = CreateObject("scripting.filesystemobject")
FSO.deletefolder Environ("Temp") & "\Temporary Directory*", True
End If
End Sub
Somewhere here:
`Set oApp = CreateObject("Shell.Application")
oApp.Namespace(FileNameFolder).CopyHere`
a dialog box appears asking me if I want to overwrite the file that have the same names - and Yes I do want to overwrite them, but without answering the dialog box - I would like to hardcode it into the code, please.
I've found this page https://msdn.microsoft.com/en-us/library/windows/desktop/bb787866(v=vs.85).aspx but I just don't know how to add this parameter #16 which is "Respond with "Yes to All" for any dialog box that is displayed."
Can U help me with that?
And the last thing:
can You explain oApp.Namespace(Fname).items line for me.
I've really tried to guess it myself, but I thing I'm to short 4 this.
the code that results in no questions or no prompting of any kind is as follows:
Option Explicit
Sub Bossa_Unzip()
Dim FSO As Object
Dim oApp As Object ' oApp is the object which has the methods you're using in your code to unzip the zip file:
'you need to create that object before you can use it.
Dim Fname As Variant
Dim FileNameFolder As Variant ' previously Dim FileNameFolder As Variant
Dim DefinePath As String
' Fname = Application.GetOpenFilename(filefilter:="Zip Files (*.zip), *.zip", MultiSelect:=False)
Fname = "C:\Users\michal\SkyDrive\csv\bossa\mstcgl.zip"
If Fname = False Then
'Do nothing
Else
'Destination folder
DefinePath = "C:\Users\michal\SkyDrive\csv\bossa\mstcgl_mst\" ' Change to your path / variable
If Right(DefinePath, 1) <> "\" Then
DefinePath = DefinePath & "\"
End If
FileNameFolder = DefinePath
' Delete all the files in the folder DefPath first if you want.
' On Error Resume Next
' Kill DefPath & "*.*"
' On Error GoTo 0
'Extract the files into the Destination folder
Set oApp = CreateObject("Shell.Application") ' you need to create oApp object before you can use it.
oApp.Namespace(FileNameFolder).CopyHere oApp.Namespace(Fname).items, 16
'MsgBox "You'll find the files here: " & DefinePath
On Error Resume Next
Set FSO = CreateObject("scripting.filesystemobject")
FSO.deletefolder Environ("Temp") & "\Temporary Directory*", True
End If
End Sub
Of course this site helped me a lot - its CpyHere explanation site.
One thing I don't understand is why Fname and FileNumberFolder need to be declared as variant. In my opinion, they should be declared as String. Just look at this screenshot.
But when I declare them that way, the code gives me error.
Just look here, when the variables already have their values (first picture). The FileNameVariable and DefinePath variable have the exact same value, and it looks like a string 4 me. How is that necessary, that I need to declare another variable - FileNameVariable in that case (in 17th line) with the same value, but variant type.
please explain that to me, someone.

VBA Open file with wildcard knowing only extension

I am trying to get Excel to open any file in the a given folder
(ThisWorkbook.Path\Peach\Apple) that has .xlsm extension (there is always only 1 file). Is it possible to open it with wildcard character? I do not know the name of the file, just the extension.
If not, is there a way to do it?
Just ask the file system for the first matching file:
Dim path As String: path = ThisWorkbook.path & "\Peach\Apple\"
FindFirstFile = Dir$(path & "*.xlsm")
If (FindFirstFile <> "") Then
Workbooks.Open path & FindFirstFile
Else
'// not found
End If
(This will not search sub-directories)
You mentioned that it would be nice addition to open last modified file or file with shortest name, so let's start - there's a code example how you can grab all three files (first finded, last modified, with shortest name). You can modify this as you wish (add some parameters, add error handling, return only specified, etc).
Sub Test()
'declarations
Dim fso As Object
Dim folder As Object
Dim file As Object
Dim path As String
Dim first_finded As Object
Dim recently_modified As Object
Dim shortest_name As Object
Dim recently As Date
Dim shortest As Long
Dim firstFinded As Boolean
'setting default recently date(24 hours from now) and path
recently = DateAdd("h", -24, Now)
path = ThisWorkbook.path & "\Peach\Apple\"
Set fso = CreateObject("Scripting.FileSystemObject")
Set folder = fso.GetFolder(path)
'iteration over folder
For Each file In folder.Files
If file.Name Like "*.xlsm" Then
'grab first finded .xlsm
If Not firstFinded Then
firstFinded = Not firstFinded
Set first_finded = file
End If
'grab lastmodified .xlsm
If file.DateLastModified > recently Then
recently = file.DateLastModified
Set recently_modified = file
End If
'grab short named .xlsm
If shortest = 0 Or shortest > Len(file.Name) Then
shortest = Len(file.Name)
Set shortest_name = file
End If
End If
Next
'debug-print names
Debug.Print first_finded.Name
Debug.Print recently_modified.Name
Debug.Print shortest_name.Name
'so now you can uncomment this and open what you want
'Call Workbooks.Open(path & recently_modified.Name)
End Sub
Try the code below, it will open your "*.xlsm" file, in the path you've requested.
Sub OpenXLSMWildcardfile()
Dim Path As String
Path = ThisWorkbook.Path & "\Peach\Apple\"
Workbooks.Open (Path & "*.xlsm")
End Sub
PFB for the code required for opening the macro file with extension(.xlsm).
Sub OpeningFile()
'Declaring variables
Dim FileName, FolderPath As String
'Initializing folder path
FolderPath = ThisWorkbook.Path & "\Peach\Apple\"
'Finding the file name using wildcard
FileName = Dir(FolderPath & "*.xlsm")
'Looping through the workbook which are saved as macro enabled workbooks
While FileName <> ""
Workbooks.Open FolderPath & FileName
FileName = Dir()
Wend
End Sub

Excel VBA - PDF file properties

first-time poster but long-time fan for finding VBA and SQL solutions on this site. I have a VBA subroutine that is designed to find all PDF files within a directory that the user designates. The program does recursions through all subfolders and generates a spreadsheet as follows:
Column A: complete file path ("C:\Users\Records\NumberOne.pdf")
Column B: folder path containing the file ("C:\Users\Records\")
Column C: the file name itself ("NumberOne.pdf")
Up to this point, the program (code below) works flawlessly. I've used it to search a directory with over 50,000 PDF files, and it successfully generates the spreadsheet every time (total elapsed time for the program is usually 5-10 minutes in large directories).
The problem is that I want to add Column D to capture the date that the PDF file was created. I have Googled this and labored over it for hours, trying techniques like FSO.DateCreated and so forth, and nothing has worked. If FSO.DateCreated is what I need, I'm not sure where to insert it in my subroutine to make it work. Usually I get an error that the object does not support that property or method. Does anybody happen to know where I can insert the proper code for my program to find the date each PDF was created and drop it into Column D on my output spreadsheet?
Sub GetFiles()
'-- RUNS AN UNLIMITED RECURSION SEARCH THROUGH A TARGETED FOLDER AND FINDS ALL PDF FILES WITHIN
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Dim j As Long
Dim ThisEntry As String
Dim strDir As String
Dim FSO As Object
Dim strFolder As String
Dim strName As String
Dim DateCreated As Date '--(Possibly String?)
Dim strArr(1 To 1048576, 1 To 1) As String, i As Long
Dim fldr As FileDialog
'-- OPEN DIALOG BOX TO SELECT DIRECTORY THE USER WISHES TO SEARCH
Set fldr = Application.FileDialog(msoFileDialogFolderPicker)
With fldr
.Title = "Select the directory you wish to search"
.AllowMultiSelect = False
If .Show <> -1 Then
Exit Sub
Set fldr = Nothing
Else
strDir = .SelectedItems(1) & "\"
End If
End With
'-- LOOK FOR RECORDS WORKSHEET; IF IT DOES NOT EXIST, CREATE IT; IF IT DOES EXIST, CLEAR CONTENTS
If Not (wsExists("records")) Then
Worksheets.Add
With ActiveSheet
.Name = "records"
End With
Set ws = ActiveSheet
Else
Sheets("records").Activate
Range("A1:IV1").EntireColumn.Delete
Set ws = ActiveSheet
End If
'-- SET SEARCH PARAMETERS
Let strName = Dir$(strDir & "\" & "*.pdf")
Do While strName <> vbNullString
Let i = i + 1
Let strArr(i, 1) = strDir & strName
Let strName = Dir$()
Loop
'-- UNLIMITED RECURSIONS THROUGH SUBFOLDERS
Set FSO = CreateObject("Scripting.FileSystemObject")
Call recurseSubFolders(FSO.GetFolder(strDir), strArr(), i)
Set FSO = Nothing
'-- CREATE COLUMN HEADERS ON OUTPUT WORKSHEET
With ws
Range("A1").Value = "AbsolutePath"
Range("B1").Value = "FolderPath"
Range("C1").Value = "FileName"
Range("D1").Value = "DateCreated"
End With
If i > 0 Then
ws.Range("A2").Resize(i).Value = strArr
End If
lr = Cells(Rows.Count, 1).End(xlUp).Row
For i = 1 To lr
ThisEntry = Cells(i, 1)
'-- EXTRACT FOLDER PATH AND FILE NAME FROM STRING
For j = Len(ThisEntry) To 1 Step -1
If Mid(ThisEntry, j, 1) = Application.PathSeparator Then
Cells(i, 2) = Left(ThisEntry, j)
Cells(i, 3) = Mid(ThisEntry, j + 1)
Exit For
End If
Next j
Next i
Application.ScreenUpdating = True
Application.DisplayAlerts = True
End Sub
----------
Private Sub recurseSubFolders(ByRef Folder As Object, _
ByRef strArr() As String, _
ByRef i As Long)
Dim SubFolder As Object
Dim strName As String
For Each SubFolder In Folder.SubFolders
Let strName = Dir$(SubFolder.Path & "\" & "*.pdf")
Do While strName <> vbNullString
Let i = i + 1
Let strArr(i, 1) = SubFolder.Path & "\" & strName
Let strName = Dir$()
Loop
Call recurseSubFolders(SubFolder, strArr(), i)
Next
End Sub
You need to get the file with GetFile before you can access the DateCreated.
Set fs = CreateObject("Scripting.FileSystemObject")
Set f = fs.GetFile(myFileName)
str = f.DateCreated
MsgBox (str)
Your code is fine (beside some issues with indentation). I just added the instruction to get the creation date from the file system, as you can see below:
Set FSO = CreateObject("Scripting.FileSystemObject")
For i = 1 To lr
ThisEntry = Cells(i, 1)
'-- EXTRACT FOLDER PATH AND FILE NAME FROM STRING
For j = Len(ThisEntry) To 1 Step -1
If Mid(ThisEntry, j, 1) = Application.PathSeparator Then
Cells(i, 2) = Left(ThisEntry, j)
Cells(i, 3) = Mid(ThisEntry, j + 1)
Cells(i, 4) = FSO.GetFile(ThisEntry).DateCreated
Exit For
End If
Next j
Next i
I don't know why you weren't able to use the FSO object, but I believe it can be because few lines below you set it to nothing, so I instantiated it again before the first For cycle:
Set FSO = CreateObject("Scripting.FileSystemObject")
Hope this helps,
The Macro Guru
FileSystem.FileDateTime(inputfilepath) returns a variant or date of when the file was last created or modified.