WORD 2010 Macro for Editing Headers & Footers - vba

I have only basic VBA experince and my prior Macro experence was primarily with WORD 2003. Recording Macros used to take GoToFooter (or Edit Footer) Menu Commands and allow subsequent editing. In WORD 2010, this (and many other) commands do not "record" to the Macro (yet when in Record mode, I do get into Edit Footer function).
A research of various VBS options shows several ways to create Footers and to make global Footer setting changes within Macro. However If I simply want to Revise the Company name within the Footer (for example), I can find no way to do this within a Macro subroutine.
This subroutine is one that I would call from the Main Macro that is stepping through each file in a Folder (& subfolders). I have the main Macro functioning.
Does WORD 2010 Macro-VBA preclude simple Edit-Footer function?
Thanks in advance
So, thanks to Issun, here is my solution:
`
Sub Sub_FTR_0()
'
ActiveDocument.ActiveWindow.ActivePane.View.SeekView = wdSeekCurrentPageFooter
For i = 1 To ActiveDocument.Sections.Count
'REM: INSERT Code from RECORD MACRO recorded when editing one Footer correctly
Selection. [[xxx]], etc.
If i = ActiveDocument.Sections.Count Then GoTo Line1
ActiveDocument.ActiveWindow.ActivePane.View.NextHeaderFooter
Line1:
Next
ActiveWindow.ActivePane.View.SeekView = wdSeekMainDocument
End Sub
`

Here is a way you can access the headers/footers via VBA. As you can see, it's rather complicated syntax to get to something so simple :p there
Sub EditHeadersAndFooters()
Dim i As Long
For i = 1 To ActiveDocument.Sections.Count
With ActiveDocument.Sections(i)
.Headers(wdHeaderFooterPrimary).Range.Text = "Foo"
.Footers(wdHeaderFooterPrimary).Range.Text = "Bar"
End With
Next
End Sub
Here is a link to example code on how to change the headers in every file in a folder. It takes a different approach and I have never tried it, but for your reference: http://www.vbaexpress.com/kb/getarticle.php?kb_id=45

This worked for me for all pages in the document.
word.ActiveDocument.Sections(1).Headers(1).Range.Text = "Put the header here"

Related

VBA Ribbon Bar Integration

I have an Excel macro that performs a few functions on a document (Creates as form, and a few emails) all from MS-Word documents. If the macro is executed from the main spreadsheet (where the macro is), everything works normally. I want to place this macro on the ribbon allowing a user to launch it without having (or knowing where the main excel document is located or having it open). I created a sub to check to see if the spreadsheet was open and modified the ribbon to include an icon for the macro.
Which works. However, when launched from the ribbon while the main Excel spreadsheet is not open, it opens the workbook and runs the macro in entirety (Without executing the open workbook line of the macro). I assume the spreadsheet is being open because the macro that is being called resides with it (makes sense). Since the macro is dependent on the data contains in the spreadsheet, I need to allow the users to modify it and then re-running the macros from the ribbon again.
Does anyone have a recommended approach or best practices? Thank you in advance.
Sub MainForm()
Dim WorkingFolder As String
Dim File01 As String 'Main Excel Data File, where all data is
Dim File02 As String 'Preliminary Email to send to user
Dim File03 As String 'Final Email to Send to user when production is complete
Dim wb As Workbook
WorkingFolder = "C:\Temp\"
File01 = "01-MainData.xlsm"
File02 = "02-PreProductionEmail.docx"
File03 = "03-FinalProductionEmail.docx"
If wbIsOpen(File01) = True Then
MsgBox "Workbook Is Open"
Run ("'C:\Users\Guest\Nextcloud\Documents\Excel Forms\02-TEST-Production Request-Data.xlsm'!CreateProductionForm")
Else
MsgBox "The Main Datafile is not open, verify the last row before re-runing", vbOKOnly, "Not Open"
Set wk = Workbooks.Open(WorkingFolder & DataFile)
End If
End Sub
The Guide mentioned by Ricardo was not quite what I needed but it was helpful and did put me on the right track. Thank you again Ricardo. To get this working, I needed to do the following.
1 - Make the procedure above its own separate *.xlam file (saved as an add-in).
2 - Add the add-in to start automatically via the developers tab
3 - Add the Macro to the Ribbon.
I have modified the sample above to included the open statement along with the statement that executes a macros from another workbook.
Appreciate the guidance.

VBA macro for simulating Ctrl+click on a bookmark/hyperlink

I'm trying to write a VBA macro in Microsoft Word to do the same thing as Ctrl+click does (follow a link or go to the bookmark).
I've tried SendKeys but I don't think that works for left mouse click.
I've actually came up with a partially working solution involving the use of
Selection.GoTo What:=wdGoToBookmark, Name:=BLAbut this unfortunately means I can't use ctrl+< because it seems that the history of where the cursor previously was is not saved.
So instead of coming up with my own solution, is there actually a way to just bind the action of Ctrl+click to another button? Or is there a way to write a macro that'll do the same action including keeping track of the history of the cursor?
The following code should do what you want. Install it on a standard code module.
Option Explicit
Dim ReturnRange As Range
Sub GotoBookmark()
' 13 Sep 2017
With Selection
If .Hyperlinks.Count Then
Set ReturnRange = .Range
.Hyperlinks(1).Follow
End If
End With
End Sub
Sub ReturnToLink()
' 13 Sep 2017
If Not ReturnRange Is Nothing Then ReturnRange.Select
End Sub
For testing purposes, create a bookmark in your document and a hyperlink to it. Select the hyperlink and run Sub GotoBookmark. Then run procedure ReturnToLink to go back to where you came from. Note that you can return from anywhere as well as multiple times.
You may wish to create keyboard shortcuts to call the two subs.

Troubleshooting Large Macro for Word 2016

I am trying to create a macro for Word 2016 that will automatically edit a document based on a list of about 250 search terms that I used the "find and replace" function to change. When I record the macro from start to finish and attempt to run, I receive a message saying "Procedure is too long". I have looked through answers on here and understand that you can clean up some code and/or create sub sections within the code to troubleshoot. However, I am not sure what I am doing and the code is very long.
Could someone help me please?
portion of code is included below:
Portion of code
Break your macro into steps. The easiest way is (use a copy of your document for testing, so you can always put the original text back if you make a mistake!):
Record a short macro. It doesn't matter what it does. Name it something like DoAllReplacements.
Record a macro that does your first block of replacements. Name it something like DoReplacement1.
View the macros, and edit the DoReplacement1 macro. Copy all of the text from the end of the comment block to the line just before End Sub.
Put the edit caret (cursor) at the end of the DoReplacement1 End Sub and hit enter twice. Enter the following text:
Sub DoReplacement2()
End Sub
Paste the code from the clipboard between the Sub and End Sub lines you just added. Edit the macro code to do your next block of replacements.
Repeat the above until you have all of your replacements coded, using as many new DoReplacementX routines as needed.
Go back to the very first macro you recorded (DoAllReplacements), and remove all of the code between the Sub DoAllReplacements() and End Sub. Add new calls to the individual DoReplacementX macros you wrote.
Sub DoAllReplacements()
DoReplacement1
DoReplacement2
DoReplacement3
' Etc. until you've added them all
End Sub
Exit the macros code window. Use View Macros, select your DoAllReplacements macro and execute it.

Using vba to copy the contents of a word document into another word document

I haven't used VB for years, so please forgive me if this turns out to be obvious. I'm trying to write a word vba macro for use in a template which will display a userform and then import the contents of fileA.docx, fileB.docx, or fileC.docx depending on the userform. (After that I'm going to use bookmarks to fill in some form data, I don't know if that's relevant). Files A, B, and C will contain text with some basic formatting such as lists, but nothing fancy.
The solutions I've seen online can copy the contents of file to a new file, but ideally I would like to import the entirety of one of those files into the new, currently unnamed file that I'm getting from the template. I think where I'm running into problems is with switching the selection to one of those files, and then back to the new unnamed document, though I could use a hand to make sure I'm copying correctly as well.
Update: I was making things too hard, though the answers here got me pointed in the right direction (thanks!). In the end I just did
ThisDocument.Activate
Selection.InsertFile("fileA")
which gives me the raw dump of everything that I wanted.
Using commands such as these you can switch between which Document you're using and copy and paste elements:
ThisDocument.Activate 'Sets the main document active
Documents("Name.doc").Activate 'Activates another document
You can insert, copy and paste things in and out of documents using copy commands.
ThisDocument.Range.InsertAfter("String") 'Insert text
Selection.WholeStory 'Select whole document
Selection.Expand wdParagraph 'Expands your selection to current paragraph
Selection.Copy 'Copy your selection
Documents("name.doc").Activate 'Activate the other document
Selection.EndKey wdStory 'Move to end of document
Selection.PasteAndFormat wdPasteDefault 'Pastes in the content
You can then go and format such, or copy and paste them with original formatting from before.
Here is a significant improvement (I think) you will want to incorporate because it:
does not use the clipboard and thus does not make your macro vulnerable to the user changing the contents of the clipboard while your macro is running
does not use a file and thus greatly improve the speed by eliminating I/O and eliminates the potential of having to deal with file system security/permissions, etc. Please do not use .InsertFile() if you are looping through documents you will slow yourself down. Use it once, at the end -only if you have to. The example below shows how to accomplish the same result without using .InsertFile()
The idea is to transfer some portion of text found in 1 source document, to a destination document that is different than the source, and keep the source formatting.
To accomplish the above (skipping the code to open documents):
For Each oTable In oDoc_Source
'the above could have been anything that returns a Range object
'such as: ActiveDocument.Content.Find.Execute ....
'...
'logic here to identify the table, or text, you are looking for
'...
'I can't believe the MS Dev Center folks could only think
'of .InsertFile(), which is the last resort I would go for,
'especially if your code runs on a web server [concurrent web requests]!
'SAFEST
'(no user interference on clipboard possible, no need to deal with file i/o and permissions)
'you need a reference to Document.Content,
'as the act of obtaining a reference "un-collapses" the range, so the below 3 lines must be in that order.
Set oRange = oDoc_DestinationDoc.Content
oRange.Collapse Direction:=wdCollapseEnd
oRange.FormattedText = oTable.Range
'BRUTE, AND PRONE TO RANDOM ERRORS AND HANGS DUE TO USER INTERFERENCE WITH CLIPBOARD
'find a way to implement WIHTOUT using the CLIPBOARD altogether to copy the below range object
'it will be easier for PC users to use the clipboard while the macro runs
'and it will probably be safer for the output of this macro to remain uncorrupted
'oTable.Range.Copy
'Set oRange = oDoc_DestinationDoc.Content
'oRange.Collapse Direction:=wdCollapseEnd
'oRange.Paste
'THE BELOW DOES NOT WORK
' '1) - cannot add a range from another document
' 'adds only text, not the formats and not the table layout
' oTable.Range.TextRetrievalMode.IncludeFieldCodes = True
' oTable.Range.TextRetrievalMode.IncludeHiddenText = True
' oDoc_DestinationDoc.Content.InsertAfter oTable.Range
'
' '2) - cannot add a range from another document
' oDoc_DestinationDoc.Content.Tables.Add oTable.Range, iRowMax, iColMax
'
' '3) - only puts in plain text, and it replaces the range without the .Collapse call
' oDoc_DestinationDoc.Content.Text = oTable.Range
Record a macro...
start in the source document
press ctrl-a to select everything
press ctrl-c to copy it to the clipboard
switch to the target document
press ctrl-v to paste into the document
stop recording
or (assuming word 2007 or later)
start in the target document with the source document closed
on the ribbon click insert > object > Text from file...
navigate to the source document
click the insert button
stop recording
I prefer the second version so I should have put it first
I was doing the same thing, tried to select the other document, copy and paste. But it didn't worked (I received an error probably because some other application was using the clipboard, but I am not sure.). So I did a little search and found the perfect solution on Microsoft Dev Center.
https://msdn.microsoft.com/en-us/vba/word-vba/articles/selection-insertfile-method-word
Selection.Collapse Direction:=wdCollapseEnd
Selection.InsertFile FileName:="C:\TEST.DOC"
'set current doc name and path
Dim docName As String: docName = ActiveDocument.name
Dim filepath As String: filepath = ActiveDocument.Path
'create a new file
Documents.Add
'get the path of a current file
ChangeFileOpenDirectory filepath
'insert content of current file to newly created doc
Selection.InsertFile _
FileName:=docName, _
Range:="", _
ConfirmConversions:=False, _
Link:=False, _
Attachment:=False
'open prompt to save a new file
With Dialogs(wdDialogFileSaveAs)
.name = docName & "-copy"
.Show
End With

Restrict/Lock bookmarks from editing in word

I have many word document with lots of bookmarks.
I use VBA code to change these bookmarks with data from a DB.
The problem is, sometimes the users need to edit these documents, and they tend to accidentally delete/change my bookmarks, which leads to the VBA code not recognizing the bookmark anymore.
So basically, what i'm wondering is how i can restrict users from editing my bookmarks in a word document.
I don't need a super secure solution, just enough protection so that the user knows that, "i should not touch this part".
Thanks in advance for your answer..
EDIT:
I was reading on different forums, and came across this,
http://social.msdn.microsoft.com/Forums/office/en-US/f70ca604-bbdb-4b5a-8363-f9e126105e91/writeprotection-of-bookmarks-in-word?forum=vsto
Which sort of does what i want. but was not able to implement/convert it to VBA code. Can someone also see how i maybe can use it?
Thanks again.
EDIT: office 2007 / 2010.
The following idea is tested for Word 2010. It should work for 2007 and 2013 as well but not for 2003.
I would suggest to use ContentControls (called CC further in the text) together with Bookmarks. Next, you will need to control one event which will check if user is selecting inside any of the ContentControl. If so, we will show the message and/or move selection outside protected area.
Step 1st. Each of your bookmarks should be enclosed inside RichText ContentControl. You could do it manually for selected bookmarks or you can run the following simple code to do it for all bookmarks inside your active document.
(Important assumption! there are not any other ContentControls in your document!)
Sub Add_Bookmark_CC()
Dim bookM As Bookmark
For Each bookM In ActiveDocument.Bookmarks
ActiveDocument.ContentControls.add wdContentControlRichText, bookM.Range
Next
End Sub
2nd step. We will control one event: Document_ContentControlOnEnter. Go to ThisDocument module in your Document VBAProject and create the following event (see some comments inside the code):
Private Sub Document_ContentControlOnEnter(ByVal ContentControl As ContentControl)
Debug.Print Now, ContentControl.Range.Bookmarks.Count
If ContentControl.Range.Bookmarks.Count > 0 Then
'Optional message box for user
MsgBox "There is bookmark inside this area which you should not change. " & _
vbNewLine & "You will be moved out of this range"
'optionam selection change right after CC area
Dim newPos As Long
newPos = ContentControl.Range.End + 2
ActiveDocument.Range(newPos, newPos).Select
End If
End Sub
Alternative for step 1st and 2nd. If you don't want to use CC event you could add CC to each bookmarks with CC content protection. In this situation you only need 1st step and the following sub:
Sub Add_Bookmark_CC_Protected()
Dim bookM As Bookmark
Dim CC As ContentControl
For Each bookM In ActiveDocument.Bookmarks
Set CC = ActiveDocument.ContentControls.add(wdContentControlRichText, bookM.Range)
CC.LockContents = True
Next
End Sub
Final! As you can see there are some more possible combination of steps 1 and 2.
The following code allows you to delete all CC if you need for any initial tests:
Sub Remove_All_CC()
Dim CC As ContentControl
For Each CC In ActiveDocument.ContentControls
CC.Delete
Next CC
End Sub
Protect your whole document using
'whole document readonly
ThisDocument.Protect Password:="password", NoReset:=False, Type:=wdAllowReadOnly
or
'only write in form fields (can't delete them, just fill them out)
ThisDocument.Protect Password:="mypassword", NoReset:=False, Type:=wdAllowOnlyFormFields
and now give some parts of the document free for editing:
ThisDocument.Bookmarks("myBookmark").Range.Editors.Add wdEditorEveryone
Selection.Range.Editors.Add wdEditorEveryone
Alternative
(not tested)
don't protect your whole document, just restrict the bookmarks you want to lock
ThisDocument.Bookmarks("myBookmark").Range.Editors.Add wdEditorOwners
or
ThisDocument.Bookmarks("myBookmark").Range.Editors.Add "abc#test.com"