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.
Related
Recently, my organization changed the name of our One Drive causing hyperlinks in my documents linking to other files in the One Drive to become obsolete.
I am trying to create a VBA script that will ask the user for a directory, go through each word doc in the folder and subfolder (and subfolder's subfolder, etc...) and replace a section of all the hyperlinks. I am new to VBA so please, don't hesitate to point out anything.
So far, this is what I have but I can't get it to change what's in the file, let alone go through all the subfolders:
Sub getDirectory()
Dim xFd As FileDialog
Dim xFdItem As Variant
Dim xFileName As String
Dim FileSystem As Object
Dim HostFolder As String
Set xFd = Application.FileDialog(msoFileDialogFolderPicker)
'Get the directory from user
If xFd.Show = -1 Then
xFdItem = xFd.SelectedItems(1) & Application.PathSeparator
xFileName = Dir(xFdItem & "*.doc*")
End If
'convert directory into string
With xFd
.Filters.Clear
.AllowMultiSelect = False
.Show
Path = .SelectedItems(1)
End With
Set FileSystem = CreateObject("Scripting.FileSystemObject")
DoFolder FileSystem.GetFolder(Path)
End Sub
Sub DoFolder(Folder)
'loop through folders after calling LoopThroughFiles
Dim SubFolder
Dim File
For Each SubFolder In Folder.SubFolders
DoFolder SubFolder
Next
For Each File In Folder.Files
' Operate on each file
Call LoopThroughFiles
Next
End Sub
Sub LoopThroughFiles()
Dim xFd As FileDialog
Dim xFdItem As Variant
Dim xFileName As String
Dim h As Hyperlink
Dim sOld As String
Dim sNew As String
Set xFd = Application.FileDialog(msoFileDialogFolderPicker)
Do While xFileName <> ""
With Documents.Open(xFdItem & xFileName)
Application.ScreenUpdating = False
'Replace this:
sOld = "AAAA"
'With this:
sNew = "BBBB"
'Example: C:\Users\Me\AAAA\file.doc ---> C:\Users\Me\BBBB\file.doc
'replace hyperlinks
For Each h In ActiveDocument.Hyperlinks
h.Address = Replace(h.Address, sOld, sNew)
Next h
Application.ScreenUpdating = True
End With
xFileName = Dir
Loop
End Sub
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.
I am looking in the Folder for specific file in .docx and want to open it. I put the Name of X into Inputbox, go to Sheet Y, look on the next right cell of X and open this as Word (next cell right is an file in word I want to open). It is working, but the Problem is that the target Word Doc may be in multiples subfolders. Is there any quick way to search in These subfolder?
Private Sub CommandButton1_Click()
On Error GoTo ErrorHandling
Application.ScreenUpdating = False
Dim AppWD As Object
Dim SearchX As String
Dim SearchArea As Range
Dim Y As String
Dim sPath As String
sPath = "C:\Users\VS\Desktop\test"
SearchRule = InputBox("X")
Set SearchArea = Sheets("Look").Range("A:A").Find(what:=SearchX, _
LookIn:=xlFormulas, lookat:=xlWhole)
ActiveWindow.Visible = True
Target = SearchArea.Offset(0, 1).Value
Set AppWD = CreateObject("Word.Application")
AppWD.Visible = True
AppWD.documents.Open (sPath & "\" & Target & "." & "docx")
ErrorHandling: Exit Sub
End Sub
My take on searching throught subfolders
Sub searchSub()
Dim fso As FileSystemObject, fFile As File, fFolder As Folder
Dim fSubFolder As Folder, fPath As String, FileToSearch As String
Set fso = New FileSystemObject
FileToSearch = "SomeDocument.docx"
fPath = ThisWorkbook.Path
Set fFolder = fso.GetFolder(fPath)
For Each fFolder In fFolder.SubFolders
Set fSubFolder = fso.GetFolder(fFolder.Path)
For Each fFile In fSubFolder.Files
If fFile.Name = FileToSearch Then
'do something with file
End If
Next fFile
Next fFolder
End Sub
I'm having an issue that when I try to use multiple instances of file dialogs the information from the first is always overwritten by the selection in the second dialog.
What i need to do is:
Select a template file
Select a destination folder
Save the template file as a .docm file.
What happens is that the second time application.FileDialog is used all the information in fd is lost and is overwritten by the entries into fldr.
Can there only be one dialog object per macro?
Dim fd As FileDialog
Dim FileChosen As Integer
Dim FileName As String
Dim fldr As FileDialog
Dim fldrSelect As String
Dim i As Integer
Set fd = Application.FileDialog(msoFileDialogFilePicker)
'use the standard title and filters, but change the
'initial folder
fd.InitialFileName = "H:\UpdatedSalesTemplates\"
fd.InitialView = msoFileDialogViewList
'allow multiple file selection
fd.AllowMultiSelect = True
FileChosen = fd.Show
If FileChosen = -1 Then
'Select the directory using a file dialog
Set fldr = Application.FileDialog(msoFileDialogFolderPicker)
fldr.InitialView = msoFileDialogViewList
fldr.Title = "Select Destination"
fldr.AllowMultiSelect = False
fldrSelected = fldr.Show
'
Microsoft says that there may be only one: "...Each host application can only create a single instance of the FileDialog object...".
In any case, this shouldn't represent a serious problem as far as you can store all the relevant information (selected path, initial directory, etc.) in (string) variables.
For such scenarios where you need a file/folder picker in one macro/procedure/userform, I use a custom made userform. See if you like it. Place commandbuttons and textboxes as shown below
Screenshot
Code
Note: Both the textboxes .Locked property was set to True in design time so that the user cannot modify the textboxes manually.
Option Explicit
Dim Ret
'~~> Browse File
Private Sub CommandButton1_Click()
Ret = Application.GetOpenFilename("Excel Files (*.xlsx), *.xlsx")
If Ret <> False Then TextBox1.Text = Ret
End Sub
'~~> Browse Folder
Private Sub CommandButton2_Click()
Ret = BrowseForFolder("C:\")
If Ret <> False Then TextBox2.Text = Ret
End Sub
Function BrowseForFolder(Optional OpenAt As Variant) As Variant
Dim ShellApp As Object
Set ShellApp = CreateObject("Shell.Application"). _
BrowseForFolder(0, "Please choose a folder", 0, OpenAt)
On Error Resume Next
BrowseForFolder = ShellApp.self.Path
On Error GoTo 0
Set ShellApp = Nothing
Select Case Mid(BrowseForFolder, 2, 1)
Case Is = ":"
If Left(BrowseForFolder, 1) = ":" Then GoTo Invalid
Case Is = "\"
If Not Left(BrowseForFolder, 1) = "\" Then GoTo Invalid
Case Else
GoTo Invalid
End Select
Exit Function
Invalid:
'~~> If it was determined that the selection was invalid, set to False
BrowseForFolder = False
End Function
I had a large number of doc files that I wanted to convert to docx files.
I discovered that there was not a really good way to automatically do this conversion.
I have submitted the method I used to do this but perhaps there are now other ways.
I found a few thing that might help:
Microsoft Bulk Converter
Simple Microsoft Word macro
However I was not satisfied with macro provided. I needed something recursive to also convert nested files. So I expanded it to do so.
Sub SaveAllAsDOCX()
'Search #EXT to change the extensions to save to docx
Dim strDocName As String
Dim strPath As String
Dim oDoc As Document
Dim fDialog As FileDialog
Dim intPos As Integer
'Create a folder dialog
Set fDialog = Application.FileDialog(msoFileDialogFolderPicker)
With fDialog
.Title = "Select root folder and click OK"
.AllowMultiSelect = False
.InitialView = msoFileDialogViewList
If .Show <> -1 Then
MsgBox "Cancelled By User", , "List Folder Contents"
Exit Sub
End If
'Select root folder
strPath = fDialog.SelectedItems.Item(1)
'Ensure the Folder Name ends with a "\"
If Right(strPath, 1) <> "\" Then strPath = strPath + "\"
End With
'Close any open documents
If Documents.Count > 0 Then
Documents.Close SaveChanges:=wdPromptToSaveChanges
End If
'remove any quotes from the folder string
If Left(strPath, 1) = Chr(34) Then
strPath = Mid(strPath, 2, Len(strPath) - 2)
End If
'begin recusion
recurse (strPath)
End Sub
'This method controls the recusion
Function recurse(folder As String)
'save all the files in the current folder
SaveFilesInFolder (folder)
'get all the subfolders of the current folder
Dim folderArray
folderArray = GetSubFolders(folder)
'Loop through all the non-empty elements for folders
For j = 1 To UBound(folderArray)
If folderArray(j) <> "" Then
'begin recusion on subfolder
recurse (folder & folderArray(j) & "\")
End If
Next
End Function
'Saves all files with listed extensions
Function SaveFilesInFolder(folder As String)
'List of extensions to look for #EXT
Dim strFilename As String
extsArray = Array("*.rtf", "*.doc")
'Loop through extensions
For i = 0 To (UBound(extsArray))
'select the 1st file with the current extension
strFilename = Dir(folder & extsArray(i), vbNormal)
'double check the current extension (don't to resave docx files)
Dim ext As String
ext = ""
On Error Resume Next
ext = Right(strFilename, 5)
If ext = ".docx" Or ext = "" Then
'Don't need to resave files in docx format
Else
'Save the current file in docx format
While Len(strFilename) <> 0
Set oDoc = Documents.Open(folder & strFilename)
strDocName = ActiveDocument.FullName
intPos = InStrRev(strDocName, ".")
strDocName = Left(strDocName, intPos - 1)
strDocName = strDocName & ".docx"
oDoc.SaveAs FileName:=strDocName, _
FileFormat:=wdFormatDocumentDefault
oDoc.Close SaveChanges:=wdDoNotSaveChanges
strFilename = Dir
Wend
End If
Next
strFilename = ""
End Function
'List all the subfolders in the current folder
Function GetSubFolders(RootPath As String)
Dim FS As New FileSystemObject
Dim FSfolder As folder
Dim subfolder As Variant
Set FSfolder = FS.GetFolder(RootPath)
'subfolders is variable length
Dim subfolders() As String
ReDim subfolders(1 To 10)
Dim i As Integer
i = LBound(subfolders)
For Each subfolder In FSfolder.subfolders
subfolders(i) = subfolder.Name
'increase the size of subfolders if it's needed
i = i + 1
If (i >= UBound(subfolders)) Then
ReDim subfolders(1 To (i + 10))
End If
Next subfolder
Set FSfolder = Nothing
GetSubFolders = subfolders
End Function
Yeah I know it's a lot of code. :)