Insert multiple Pictures from Folder in descending order - vba

I insert a number of pictures from a Folder. The program is supposed to start at the top of the folder and insert the pictures in a descending order, but it does not.
The very first 3-5 pictures come last in the presentation, while all others are in perfect order.
Sub createTransModel()
Dim oSlide As Slide
Dim oPicture As Shape
Dim myFile As String
Dim myFolder As String
Dim pptLayout As CustomLayout
Dim fileName As String
Dim rotSlide As Slide
Set pptLayout = ActivePresentation.Slides(1).CustomLayout
myFolder = GetFolderPath()
myFile = Dir(myFolder & "*.png")
Do While myFile <> ""
Set oSlide = ActivePresentation.Slides.Add(ActivePresentation.Slides.Count + 1, _
ppLayoutBlank)
Set oPicture = oSlide.Shapes.AddPicture(myFile, _
msoFalse, msoTrue, 1, 1, _
ActivePresentation.PageSetup.SlideWidth, _
ActivePresentation.PageSetup.SlideHeight)
myFile = Dir
Loop
fileName = inputBox("Please enter the filename")
ActivePresentation.SaveAs (fileName & ".pps")
End Sub
Public Function GetFolderPath() As String
Dim myFile As Object
Dim fileSelected As String
Dim path As String
Dim objPPT As Object
Dim i As Integer
Dim folderFromPath As String
Dim directory As String
directory = "M:\tm\public\Conti_Anlage\Voith Proben"
Set myFile = Application.FileDialog(msoFileDialogOpen)
With myFile
.InitialFileName = directory
.Title = "Choose File"
.AllowMultiSelect = False
If .Show <> -1 Then
Exit Function
End If
fileSelected = .SelectedItems(1)
End With
For i = Len(fileSelected) To 1 Step -1
If Mid(fileSelected, i, 1) = "\" Then
folderFromPath = Left(fileSelected, i)
Exit For
End If
Next
GetFolderPath = folderFromPath
End Function

There are a couple of things here
1. To resolve your order issue, you could get all the files in the folder (i.e. use a 'For' loop: For Each oFile in oMyFolder.Files) and then order them the way you want them (maybe in an array). Now you can add them.
2. Your 'GetFolderPath' function: from what I can see, you want the user to select a file and then you are returning the folder of the selected file. You could just use 'Application.FileDialog(msoFileDialogFolderPicker)'. This will ask the user to select a folder. This way you don't have to worry about extracting the folder. If you still want to get the folder of the selected file, have a look at 'File System' object. You could use that to get the folder (i.e. filesystemobject.GetParentFolderName(MyFile))

The order of files that you see in a Windows file explorer window depends on your file explorer settings. Files might be displayed alphabetically by name, in size order or sorted in various other ways. That's file explorer's doing and has nothing to do with the actual order in which the files appear on the disk.
Dir$ when called repeatedly gives you the files in the order in which they appear on the disk. If you want them in a particular order, you'll have to sort them or perhaps copy them into a folder in the order you want them to be returned by Dir.

Related

Looping through directory and taking files with highest revision number

I'll preface this by saying I don't have much experience in Excel and VBA code, but I've gone through countless sources looking for this.
I'm attempting to store all files in the current working directory in an array and then looping through that array to find the file with the highest number at the end for each base name.
Example: file1.xlsx, file2.xlsx, anotherfile1.xlsx, anotherfile2.xlsx
would only return file2.xlsx and anotherfile2.xlsx.
This is what I currently have as a starting point:
Dim directory As String, fileName As String, sheet As Worksheet
Dim fileArray() As String
Dim count As Integer
Set count = 0
Application.ScreenUpdating = False
directory = ActiveWorkbook.Path
fileName = Dir(directory & "*.xlsm")
Do Until fileName = ""
count = count + 1
ReDim Preserve fileArray(1 To count)
fileArray(count) = fileName
fileName = Dir
Loop
'Find unique entries
For Each element In fileArray
'do stuff here...
Next element
The file names are formatted oddly so I'm not sure how to approach this. The file names are like: GENERICNAME-[field I need to compare]-[number].xlsx
strPath in the below is the most recent file with the name you're looking for.
Dim fsoFile As New FileSystemObject
Dim fldFile As Folder: Set fldFile = fsoFile.GetFolder(ActiveWorkbook.Path)
Dim objFile As File
Dim dtFile As Date: dtFile = DateSerial(1900, 1, 1)
Dim strPath As String
For Each objFile In fldFile.Files
If Not objFile.Name Like "*~$*" Then
If objFile.Name Like "*[file I need to compare]*" _
And objFile.DateLastModified > dtFile Then
dtFile = objFile.DateLastModified
strPath = objFile.Path
End If
End If
Next objFile
Set fsoFile = Nothing
Set fldFile = Nothing

VBA Excel: for each results into cells? counter not working?

I´m creating a macro that crawls into subfolders and retrieve the name of some files. I used code from this answer to another question and works fine to get the results into the immediate window, but I want to get them into cells, as a list. What I get is just the result of the first iteration.
What I´m trying to do might be obvious, but I swear I tried and couldn´t find the answer by myself. For the record, I´m just starting to code.
My code here. The important part comes at the end, in Sub ListFiles(fld As Object, Mask As String).
Option Explicit
Sub Retrieve_Info()
Dim strPath As Variant
Dim pasta_destino As Range
Dim fle As String
Dim fso As Object 'FileSystemObject
Dim fldStart As Object 'Folder
Dim fld As Object 'Folder
Dim fl As Object 'File
Dim Mask As String
Set pasta_destino = ThisWorkbook.Worksheets("VINCULATOR").Range("pasta_destino")
strPath = Application.GetOpenFilename _
(Title:="Selecione o arquivo.xlsx", _
FileFilter:="Excel Files *.xlsx* (*.xlsx*),")
If Not strPath = False Then
pasta_destino = strPath
fle = Dir(strPath)
Set fso = CreateObject("scripting.FileSystemObject") ' late binding
'Set fso = New FileSystemObject 'or use early binding (also replace Object types)
Set fldStart = fso.GetFolder(Replace(strPath, fle, ""))
Mask = "*.xlsx"
For Each fld In fldStart.SubFolders
ListFiles fld, Mask
Next
End If
End Sub
Sub ListFiles(fld As Object, Mask As String)
Dim fl As Object 'File
Dim vrow As Integer
Dim vinculadas As Range
Dim n_vinc As Range
Set vinculadas = ThisWorkbook.Worksheets("VINCULATOR").Range("vinculadas")
Set n_vinc = ThisWorkbook.Worksheets("VINCULATOR").Range("n_vinc")
vrow = 0
For Each fl In fld.Files
If fl.Name Like Mask And InStr(fl.Name, "completo") = 0 Then
vrow = vrow + 1
vinculadas.Cells(vrow, 1) = fld.Path & "\" & fl.Name
End If
Next
n_vinc = vrow
End Sub
Please, help!
I have taken a slightly different approach which might be easier for you to follow in addition to executing faster. Please try this.
Sub SpecifyFolder()
' 10 Dec 2017
Dim Fd As FileDialog
Dim PathName As String
Dim Fso As Object
Dim Fold As Object, SubFold As Object
Dim i As Long
Set Fd = Application.FileDialog(msoFileDialogFolderPicker)
With Fd
.ButtonName = "Select"
.InitialView = msoFileDialogViewList
.InitialFileName = "C:\My Documents\" ' set as required
.Show
If .SelectedItems.Count Then
PathName = .SelectedItems(1)
Else
Exit Sub ' user cancelled
End If
End With
Set Fd = Nothing
Set Fso = CreateObject("Scripting.FileSystemObject")
Set Fold = Fso.GetFolder(PathName)
ListFiles Fold, "*.xlsx"
For Each SubFold In Fold.SubFolders
ListFiles SubFold, "*.xlsx"
Next SubFold
Set Fso = Nothing
End Sub
Sub ListFiles(Fold As Object, _
Mask As String)
' 10 Dec 2017
Dim Fun() As String ' file list
Dim Rng As Range
Dim Fn As String ' file name
Dim i As Long ' array index
ReDim Fun(1 To 1000) ' maximum number of expected files in one folder
Fn = Dir(Fold.Path & "\")
Do While Len(Fn)
If Fn Like Mask And InStr(Fn, "completo") = 0 Then
i = i + 1
Fun(i) = Fold.Path & "\" & Fn
End If
Fn = Dir
Loop
If i Then
ReDim Preserve Fun(1 To i)
With ThisWorkbook.Worksheets("VINCULATOR")
' specify the column in which to write (here "C")
i = .Cells(.Rows.Count, "C").End(xlUp).Row
Set Rng = .Cells(i + 1, "C").Resize(UBound(Fun), 1)
Application.ScreenUpdating = False
Rng.Value = Application.Transpose(Fun)
Application.ScreenUpdating = True
End With
End If
End Sub
As you see, I have dispensed with specifying a target range, just the sheet and the column (I chose column C; please change as required in the ListFiles sub). Note that the code appends new lists to the existing content of the indicated column.
There are two things the code doesn't do to my entire satisfaction. One, it doesn't write to the first row of an empty column C. Instead, it leaves the first row blank. You might actually like that. Two, It doesn't do sub-subfolders. File names are extracted only from the selected folder and its immediate subfolders. Additional programming would be required for either additional feature, if required.
Finally, I admit that I didn't test for correct transfer of the lists to the worksheet. I think it works correctly but you should check that the first and last names are listed in your worksheet column. They are extracted from the folder but perhaps their omission when writing to the sheet would be a typical error to occur in this particular method.

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

Calling Shell - explorer search in VBA - Workaround

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

Word VBA save files in new folder

I have VBA in Word that opens multiple files from a folder that I select, replaces the logo in the header with a new file that I direct it to, and then saves the files in a different folder.
I have the files saving in a different folder not because I want to, but because they are opening as read-only and I can't figure out how to make that not happen. I have tried everything I can find on here. I'm fine with them saving to a new folder. That's not the issue for me right now.
Right now, this code works, but I have to click "Save" for each document. I would like that to be automated. The code right here is the saveas
End With
With Dialogs(wdDialogFileSaveAs)
.Name = "\\i-worx-san-07.i-worx.ca\wardell$\Redirection\billy.bones\Desktop\Test 3\" & ActiveDocument.Name
.Show
End With
End With
objDocument.SaveAs
objDocument.Close (True)
The following is the complete VBA code. I'm an absolute novice, so go easy. I want to know how to go about making the saveas include the original filename, a new specified folder (can be specified in the code, doesn't have to be specified by the user) and do it without the user having to press "save" a brazillion times. I appreciate your help.
Sub Example1()
'Declaring the required variables
Dim intResult As Integer
Dim strPath As String
Dim arrFiles() As String
Dim i As Integer
'the dialog is displayed to the user
intResult = Application.FileDialog(msoFileDialogFolderPicker).Show
'checks if user has cancled the dialog
If intResult <> 0 Then
'dispaly message box
strPath = Application.FileDialog( _
msoFileDialogFolderPicker).SelectedItems(1)
'Get all the files paths and store it in an array
arrFiles() = GetAllFilePaths(strPath)
'Modifying all the files in the array path
For i = LBound(arrFiles) To UBound(arrFiles)
Call ModifyFile(arrFiles(i))
Next i
End If
End Sub
Private Sub ModifyFile(ByVal strPath As String)
Dim objDocument As Document
Set objDocument = Documents.Open(strPath)
With ActiveDocument.Sections(1)
With ActiveDocument.Sections(1)
.Headers(WdHeaderFooterIndex.wdHeaderFooterPrimary).Range.Delete
End With
Dim imagePath As String
'Please enter the relative path of the image here
imagePath = "C://FILEPATH\FILENAME.jpg"
Set oLogo = .Headers(wdHeaderFooterPrimary).Range.InlineShapes.AddPicture(FileName:=imagePath, LinkToFile:=False, SaveWithDocument:=True)
With oLogo.Range
.ParagraphFormat.Alignment = wdAlignParagraphRight
'Right alignment for logo image
.ParagraphFormat.RightIndent = InchesToPoints(-0.6)
End With
End With
With oLogo
.Height = 320
.Width = 277
With Selection.PageSetup
'Header from Top value
.HeaderDistance = InchesToPoints(0.5)
End With
With Dialogs(wdDialogFileSaveAs)
.Name = "\\i-worx-san-07.i-worx.ca\wardell$\Redirection\billy.bones\Desktop\Test 3\" & ActiveDocument.Name
.Show
End With
End With
objDocument.SaveAs
objDocument.Close (True)
End Sub
Private Function GetAllFilePaths(ByVal strPath As String) _
As String()
Dim objFSO As Object
Dim objFolder As Object
Dim objFile As Object
Dim i As Integer
Dim arrOutput() As String
ReDim arrOutput(1 To 1)
'Create an instance of the FileSystemObject
Set objFSO = CreateObject("Scripting.FileSystemObject")
'Get the folder object
Set objFolder = objFSO.GetFolder(strPath)
i = 1
'loops through each file in the directory and
'prints their names and path
For Each objFile In objFolder.Files
ReDim Preserve arrOutput(1 To i)
'print file path
arrOutput(i) = objFile.Path
i = i + 1
Next objFile
GetAllFilePaths = arrOutput
End Function
Remove this line which calls the FileSaveAs dialogue.
With Dialogs(wdDialogFileSaveAs)
.Name = "\\i-worx-san-07.i-worx.ca\wardell$\Redirection\billy.bones\Desktop\Test 3\" & ActiveDocument.Name
.Show
End With
Then modify this line:
objDocument.SaveAs
and include the filepath like this:
objDocument.SaveAs "\\i-worx-san-07.i-worx.ca\wardell$\Redirection\" _
& "billy.bones\Desktop\Test 3\" & ActiveDocument.Name
In newer version of Word, it was change to SaveAs2 but SaveAs still works.
That method takes the file path where you want the file saved as first argument.