I have several directories of files (shell, Perl, and SQL) that I use for building books and doing healthchecks of databases. What I am trying to do is take the directory and produce a Word document which should hopefully look like:
(Heading-2) file-name (no spacing) the filecontents (page break).
Repeat until done.
What I'm getting with the code that I mostly reused below is
(Heading 2) file name (Heading 2) next file name (until end of directory)
followed by the contents of the files. What would I need to do to make this work like I want?
Sub DirLoop()
Dim MyFile As String, Sep As String, OFolder As String
Dim wdDoc As Document
Dim txtFiles As Document
' Sets up the variable "MyFile" to be each file in the directory
' This example looks for all the files that have an .xls extension.
' This can be changed to whatever extension is needed. Also, this
' macro searches the current directory. This can be changed to any
' directory.
Sep = Application.PathSeparator
OFolder = openFolder
Sep = "\"
' Look for the right type of file.....
MyFile = Dir(OFolder & Sep & "*.sh")
Set wdDoc = ActiveDocument
' Starts the loop, which will continue until there are no more files
' found.
Do While MyFile <> ""
' Get the directory
Set txtFiles = Documents.Open(FileName:=OFolder & "\" & MyFile, AddToRecentFiles:=False, Visible:=False, ConfirmConversions:=False)
Selection.InsertBreak (wdPageBreak)
Selection.Style = ActiveDocument.Styles("Heading 2")
Selection.TypeText Text:=MyFile & vbCr
Selection.Style = ActiveDocument.Styles("No Spacing")
wdDoc.Range.InsertAfter txtFiles.Range.Text & vbCr
txtFiles.Close SaveChanges:=False
MyFile = Dir()
Loop
End Sub
The problem comes from the way you're mixing the Selection and Range objects. When you open a document the Selection will be at the beginning of the document. Everything you add to the document using Selection will be at the beginning.
wdDocRange.InsertAfter, on the other hand, will insert at the end of the document.
Generlly, accepted practise is to use the Range object rather than the Selection object whenever possible. There's more than one way to write code to do what you intend, my approach would look more like this (untested since I'm on a mobile device):
Sub DirLoop()
Dim MyFile As String, Sep As String, OFolder As String
Dim txtFiles As Word.Document, wdDoc as Word.Document
Dim rngNewEntry as Word.Range
' Sets up the variable "MyFile" to be each file in the directory
' This example looks for all the files that have an .xls extension.
' This can be changed to whatever extension is needed. Also, this
' macro searches the current directory. This can be changed to any
' directory.
Sep = Application.PathSeparator
OFolder = openFolder
Sep = "\"
' Look for the right type of file.....
MyFile = Dir(OFolder & Sep & "*.sh")
Set wdDoc = ActiveDocument
' Starts the loop, which will continue until there are no more files
' found.
Do While MyFile <> ""
' Get the directory
Set txtFiles = Documents.Open(FileName:=OFolder & "\" & MyFile, AddToRecentFiles:=False, Visible:=False, ConfirmConversions:=False)
'Content is a property, so more "correct" for use than Range
Set rngNewEntry = wdDoc.Content
rngNewEntry.Collapse wdCollapseEnd 'Puts focus at end of doc
rngNewEntry.InsertBreak wdPageBreak
rngEntry.Text = My File & vbCr
'Format Range after adding text
rngEntry.Style = wdDoc.Styles("Heading 2")
rngEntry.Collapse wdCollapseEnd
rngEntry.Range.Text = txtFiles.Content.Text & vbCr
rngEntry.Style = wdDoc.Styles("No Spacing")
txtFiles.Close SaveChanges:=False
MyFile = Dir()
Loop
End Sub
Related
I have a question about bookmarks. I made a macro that deletes all the bookmarks in a Word document and adds a new bookmark:
Sub AddBookmarkInCurrentFile()
'
' Deletes all the bookmarks in an already opened file
' and add one new bookmark in the file
'
' Deletes al current bookmarks
For Each bkm In ActiveDocument.Bookmarks
bkm.Delete
Next bkm
' Put Cursor add the beginning of the file and adds the bookmark
Selection.HomeKey Unit:=wdStory
ActiveDocument.Bookmarks.Add Name:="testBookmarkAdd"
MsgBox "Finished"
End Sub
When I run this it works fine.
Because I have to do this for more then 100 documents and save the *.doc as .docx I made a new version of the macro. Everything works accept the adding of the new bookmark. What is wrong in the code below?
Sub AddBookmarkInAllOpenedFiles()
' Opens all word files in a directory and deletes current bookmarks
' and adds one bookmark and saves the file to a docx file
Dim sSourcePath As String
Dim sTargetPath As String
Dim sDocName As String
Dim docCurDoc As Document
Dim sNewDocName As String
Dim sOrigName As String
Dim intPos As Integer
' Looking in this path
sSourcePath = "H:\Mijn Documenten\test\"
sTargetPath = "H:\Mijn Documenten\test\Converted\"
' Look for first DOC file
sDocName = Dir(sSourcePath & "*.doc")
Do While sDocName <> ""
' Repeat as long as there are source files
'Only work on files where right-most characters are ".doc"
If Right(sDocName, 4) = ".doc" Then
' Open file
Set docCurDoc = Documents.Open(FileName:=sSourcePath & sDocName)
' Deletes all the bookmarks
For Each bkm In ActiveDocument.Bookmarks
bkm.Delete
Next bkm
' Put Cursor add the beginning of the file and adds the bookmark
Selection.HomeKey Unit:=wdStory
ActiveDocument.Bookmarks.Add Name:="testBookmarkAdd"
'Saves the document as a docx
sNewDocName = Replace(sDocName, ".doc", ".docx")
With docCurDoc
.SaveAs FileName:=sTargetPath & sNewDocName, _
FileFormat:=wdFormatDocumentDefault
.Close SaveChanges:=wdDoNotSaveChanges
End With
End If
' Get next source file name
sDocName = Dir
Loop
MsgBox "Finished"
End Sub
Try:
Sub BookmarkAllFilesInFolder()
' Opens all word files in a directory and deletes current bookmarks
' and adds one bookmark and saves the file to a docx file
Dim sSourcePath As String, sTargetPath As String
Dim sDocName As String, docCurDoc As Document
' Looking in this path
sSourcePath = "H:\Mijn Documenten\test\"
sTargetPath = sSourcePath & "Converted\"
' Look for first DOC file
sDocName = Dir(sSourcePath & "*.doc")
' Repeat as long as there are source files
Do While sDocName <> ""
' Only open .doc files"
If Right(sDocName, 4) = ".doc" Then
' Open file
Set docCurDoc = Documents.Open(FileName:=sSourcePath & sDocName, AddToRecentFiles:=False, Visible:=False)
With docCurDoc
'Delete all existing bookmarks
While .Bookmarks.Count > 0
.Bookmarks(1).Delete
Wend
'Add our bookmark
.Bookmarks.Add Name:="TestBookmark", Range:=.Range(0, 0)
'Save the file in .docx format to the output folder
.SaveAs2 FileName:=sTargetPath & sDocName & "x", _
FileFormat:=wdFormatDocumentDefault, AddToRecentFiles:=False
.Close SaveChanges:=wdDoNotSaveChanges
End With
End If
' Get next source file name
sDocName = Dir
Loop
Set docCurDoc = Nothing
MsgBox "Finished"
End Sub
I'm a beginner at coding. So I would like to know how I could use nesting to code a macro (for VBA Word) that runs multiple other macros in all documents in a specified folder. I am trying to employ nesting by having the outer loop open all the documents in a folder (a user will input the location of the folder using InputBox), and within this loop, all the macros will be applied.
So far I know that this is what works perfectly (the code opens all documents in the specified folder);
Sub nestingMacro()
Dim currentFile As String
Dim location As String
location = InputBox("Location of folder")
If Right(location, 1) <> "\" Then location = location + "\"
currentFile = Dir(location & "*.doc*")
Do While (currentFile <> "")
Documents.Open FileName:=location & currentFile
currentFile = Dir()
Loop
End Sub
I tried adding the following;
Sub nestingMacro()
Dim currentFile As String
Dim location As String
location = InputBox("Location of folder")
If Right(location, 1) <> "\" Then location = location + "\"
currentFile = Dir(location & "*.doc*")
Do While (currentFile <> "")
Documents.Open FileName:=location & currentFile
currentFile = Dir()
If currentFile <> "" Then
'the name of the macros below
Call findReplaceStyle
Call countErrorsQuality
Call saveClose
End If
Loop
End Sub
Yes, it opens all documents in a folder, however, it runs the macros only on two of the documents then nothing happens to the others. How can I solve this?
Is there a better way to write the function IF, in order to run the macros on all documents using nesting?
Also is there a way to run the macros without actually calling their names?
Thank you!
You don't need if statement.
Sub nestingMacro()
Dim currentFile As String
Dim location As String
location = InputBox("Location of folder")
If Right(location, 1) <> "\" Then location = location + "\"
currentFile = Dir(location & "*.doc*")
Do While (currentFile <> "")
Documents.Open FileName:=location & currentFile
Call findReplaceStyle
Call countErrorsQuality
Call saveClose
currentFile = Dir()
Loop
End Sub
You don't need nesting for what you've described so far. If the code is only running on a few files in the folder, that's most likely because you're running the code from a document stored in the same folder and, as soon as it processes itself, it gets closed and that kills the macro. Try something along the lines of the following.
Sub Demo()
Application.ScreenUpdating = False
Dim strFolder As String, strFile As String, strDocNm As String, wdDoc as Document
strDocNm = ActiveDocument.Fullname
strFolder = GetFolder
If strFolder = "" Then Exit Sub
strFile = Dir(strFolder & "\*.doc*", vbNormal)
While strFile <> ""
If strFolder & "\" & strFile <> strDocNm Then
Set wdDoc = Documents.Open(FileName:=strFolder & "\" & strFile, AddToRecentFiles:=False, Visible:=False)
Call findReplaceStyle
Call countErrorsQuality
Call saveClose
End If
strFile = Dir()
Wend
Set wdDoc = Nothing
Application.ScreenUpdating = True
End Sub
Function GetFolder() As String
Dim oFolder As Object
GetFolder = ""
Set oFolder = CreateObject("Shell.Application").BrowseForFolder(0, "Choose a folder", 0)
If (Not oFolder Is Nothing) Then GetFolder = oFolder.Items.Item.Path
Set oFolder = Nothing
End Function
A potential problem with your
Call findReplaceStyle
Call countErrorsQuality
lines is that you're not passing the document you've just opened as a parameter. If anything in those subs changes the activedocument, you could run into problems. It's good coding practice to pass the document you want to process as a parameter, as in:
Call findReplaceStyle(wdDoc)
Call countErrorsQuality(wdDoc)
Drawing on your previous thread on a related topic, to accept and use such a parameter, the latter sub might be coded along the lines of:
Sub countErrorsQuality(wdDoc As Document)
Dim Rng As Range
With wdDoc
Set Rng = .Range(0, 0)
If .SpellingErrors.Count > 0 Then
With Rng
.Text "REJECTED" & vbCr
.Font.Size = 14
.Font.ColorIndex = wdRed
.Font.Bold = True
End With
End If
End With
Set Rng = Nothing
End Sub
Note that nothing gets selected. This reduces screen flicker and makes the code run faster.
I likewise suspect you don't need your
Call saveClose
code and all you really need is:
wdDoc.Close SaveChanges:=True
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
I am trying to modify the following code, it will merge the Word Documents fine, but I have text file with every line being "*Name*.docx" "*Name2*.docx", etc, I would like the VBA macro to read the text file line by line and merge all the documents that match the pattern, should be 27 documents when done and save each one preferably with the a title that includes the "*Name" tag so I can know which is which. Any help would be greatly appreciated
Sub MergeDocs()
Dim rng As Range
Dim MainDoc As Document
Dim strFile As String
Const strFolder = "C:\test\"
Set MainDoc = Documents.Add
strFile = Dir$(strFolder & "*Name*.docx")
Do Until strFile = ""
Set rng = MainDoc.Range
rng.Collapse wdCollapseEnd
rng.InsertFile strFolder & strFile
strFile = Dir$()
Loop
MsgBox ("Files are merged")
End Sub
I think it's just a matter of adding an extra loop that reads the input file line by line and then uses your loop above.
This example uses the scripting filesystemobject to open the file and read it.
I assume what you've said above is what you actually mean - and the file spec is in the text file. Change the constants to fit your needs
Sub MergeDocs()
Const FOLDER_START As String = "C:\test\" ' Location of inout word files and text file
Const FOLDER_OUTPUT As String = "C:\test\output\" ' send resulting word files here
Const TEST_FILE As String = "doc-list.txt"
Dim rng As Range
Dim MainDoc As Document
Dim strFile As String
Dim strFileSpec As String
Dim strWordFile As String
Dim objFSO As Object ' FileSystemObject
Dim objTS As Object ' TextStream
Set objFSO = CreateObject("Scripting.FileSystemObject")
strFile = FOLDER_START & TEST_FILE
If Not objFSO.FileExists(strFile) Then
MsgBox "File Doesn't Exist: " & strFile
Exit Sub
End If
Set objTS = objFSO.OpenTextFile(strFile, 1, False) 'The one was ForReading but for me it threw an error
While Not objTS.AtEndOfStream
Set MainDoc = Documents.Add
' Read file spec from each line in file
strFileSpec = objTS.ReadLine ' get file seacrh spec from input file
'strFileSpec = "*NAME2*"
strFile = Dir$(FOLDER_START & strFileSpec & ".docx") ' changed strFolder to FOLDER_START
Do Until strFile = ""
Set rng = MainDoc.Range
rng.Collapse wdCollapseEnd
rng.InsertFile FOLDER_START & strFile ' changed strFolder again
strFile = Dir$() ' Get next file in search
Loop
strWordFile = Replace(strFileSpec, "*", "") ' Remove wildcards for saving filename
strWordFile = FOLDER_OUTPUT & strWordFile & ".docx"
MainDoc.SaveAs2 strWordFile
MainDoc.Close False
Set MainDoc = Nothing
Wend
objTS.Close
Set objTS = Nothing
Set objFSO = Nothing
MsgBox "Files are merged"
End Sub
I have a plenty of word documents in a folder to which I want to apply style which I have customized.
This is my VBA-code. I want the VBA as like to go to the particular folder and apply the customized style to all the word documents. Any ideas?
Sub styleapply()
'
' styleapply Macro
'
'
Selection.WholeStory
ActiveDocument.UpdateStyles
'WordBasic.ApplyQFSetTemplate
Selection.Style = ActiveDocument.Styles("sam'style")
End Sub
This should get you most of the way there:
Sub OpenWordFolder()
Dim fd As FileDialog
Dim doc As Document
Set fd = Application.FileDialog(msoFileDialogFolderPicker)
fd.AllowMultiSelect = True
fd.Show
For Each folderItem In fd.SelectedItems
fileItem = Dir(folderItem & "\" & "*.docx")
While fileItem <> ""
Set doc = Documents.Open(FileName:=folderItem & "\" & fileItem)
Selection.WholeStory
Selection.Style = ActiveDocument.Styles("sam'style")
doc.Close SaveChanges:=True
fileItem = Dir
Wend
Next
End Sub
Note that I'm unsure if the ActiveDocument will have the custom style you've created - you may need to set the original document with the custom style to a Document object and then use that Document object to set the style for each file you've opened.