Deleting Blank Pages in Word Doc with VBA - vba

Trying to write a function to delete blank pages in a Word doc. Nothing gets deleted. I appreciate it if somebody can take a look.
Public Function DeleteBlankPages(wd As Word.Document, wdApp As Word.Application)
Dim par As Paragraph
For Each par In wd.Paragraphs
If IsEmpty(par.Range.Text) Then
par.Range.Select
wdApp.Selection.Delete
End If
Next par
End Function

Look up the definition of IsEmpty in the VBA language reference. It doesn't do what you imagine.
The correct way to find out if there is textual content is to check the number of characters. In VBA, this is typically done with the function Len (=length). You'd think that it the comparision should be to 0 (zero), but that's not the case for a paragraph, because a Word paragraph always contains it's paragraph mark (ANSI 13).
Also, no need to select the paragraph or range in order to delete it, just use the Deletemethod directly on the par.Range. (Which means you also don't need to pass a Word.Application object.
Also note that your code doesn't do anything to pages, only to paragraphs... It could deleted empty pages, depending on how things are formatted, but it might be wise to rename the Function and comment how it's supposed to work.
So more like this:
Public Function DeleteBlankPages(wd As Word.Document)
Dim par As Paragraph
For Each par In wd.Paragraphs
If Len(par.Range.Text) <= 1 Then
par.Range.Delete
End If
Next par
End Function

Related

Comment.Add in Word VBA (2019) is inconsistent in adding text to the comment

Context: I am using Word 2019 (Office 365 subscription, if that matters). I have added a series of buttons to my Review ribbon, each set to create a specific comment on some text. (Writing teacher. I make a lot of repeated comments.)
The structure for each comment macro is as follows:
Sub AddSomeComment()
Dim someComment As String
someComment = "Long explanation of some revision recommendation."
ActiveDocument.Comments.Add Range:=Selection.Range, Text:=someComment
End Sub
Problem: The comment balloon is always added, but it is frequently left blank. On some documents, every comment will work (1/10 maybe). On others, the first comment will work but all others will be left blank. A majority of documents will not place the text into the comment. All documents are saved as docx prior to commenting.
I have tried debugging and rewriting the code several times. I've hard coded strings in to each comment and gotten the same results. I have tried using a MsgBox() to verify that someComment has a string in it (it does).
I don't know why it might be behaving like that. Perhaps there's a "race" condition (the text is sent to the comment before it's been created).
Try it like this: create the comment and after it's been created assign the text. (Note: I'm on a mobile device so can't test for syntax errors)
Sub AddSomeComment()
Dim cmt as Comment
Dim someComment As String
someComment = "Long explanation of some revision recommendation."
Set cmt = ActiveDocument.Comments.Add Range:=Selection.Range
cmt.Range.Text = someComment
End Sub

VB.Net equivalent for (CustomizationContext) in VBA

I'm busy with some word automation and have run into an issue whereby a context menu within a document has items in, that I wish to remove.
Once the document is open, through vba I can remove these items by running the following code;
[VBA]
Dim oContextMenu As CommandBar
Dim oContextMenuItem As CommandBarControl
'Make changes to the ActiceDocument only (this is needed to make any changes to this document).
CustomizationContext = ActiveDocument
For Each oContextMenu In ActiveDocument.CommandBars
If oContextMenu.Type = MsoBarType.msoBarTypePopup Then 'Loop through all the context menus of type (msoBarTypePopup)
For Each oContextMenuItem In oContextMenu.Controls
If (InStr(oContextMenuItem.Caption, "Smokeball")) Then
oContextMenuItem.Delete
End If
Next
End If
Next
If I execute this code and check the document, all contextMenu sub items that contain the text "smokeball" are removed.
When I try move this code to my VB.NET solution (I have no choice of language, so VB it is), I get errors on the CustomizationContext = ActiveDocument line (this line has to be there for it to affect the current document).
The error I get is CustomizationContext' is not a by reference property.
Does anyone know how to get just that ONE line equivalent for vb.net?
Thanks in advance.
EDIT: In case you need to see the vb.net sub:
Private Sub RemoveUnwantedContextMenuItems()
Dim oContextMenu As CommandBar
Dim oContextMenuItem As CommandBarControl
'Make changes to the ActiceDocument only (this is needed to make any changes to this document).
WordApplication.CustomizationContext = WordApplication.ActiveDocument 'This is the error.
For Each oContextMenu In WordApplication.CommandBars
If oContextMenu.Type = MsoBarType.msoBarTypePopup Then 'Loop through all the context menus of type (msoBarTypePopup)
For Each oContextMenuItem In oContextMenu.Controls
If (InStr(oContextMenuItem.Caption, "Smokeball")) Then
oContextMenuItem.Delete()
End If
Next
End If
Next
End Sub
PS - I have also already tried using the .AttachedTemplate as well as .Normal / .NormalTemplate
Jules pointed me in the right direction with his sample code.
After lots of playing around I noticed that somewhere in the solution, the [TYPE] of WordApplication was getting changed to a dynamic type of sorts, hence, it couldn't use CustomizationContext.
My solution was this:
I changed this line;
WordApplication.CustomizationContext = WordApplication.ActiveDocument
To this:
CType(WordApplication, Microsoft.Office.Interop.Word.Application).CustomizationContext = WordApplication.ActiveDocument
Forcing the types to be correct.
Simple solution but took some time.
Thanks to Jules for pointing me in the right direction.
(Points should go to you).

VBA String pattern PinPointing

Ok so i have these 6 which are coerced during Running-time as String Values. So these lines below are String values
bdx-20131231.xml
bdx-20131231.xsd
bdx-20131231_cal.xml
bdx-20131231_def.xml
bdx-20131231_lab.xml
bdx-20131231_pre.xml
inside a macro we have a small simple loop that iterates and prints on the immediate window the string values that end with ".xml" so the xsd (second one) is not printed by the loop. Following you can see the loop
For Each el In IE.Document.getelementsbytagname("a")
If el.href Like "*.xml" Then
Debug.Print el.innertext, el.href
End If
next el
So we are left with these
bdx-20131231.xml
bdx-20131231_cal.xml
bdx-20131231_def.xml
bdx-20131231_lab.xml
bdx-20131231_pre.xml
However what i am trying to nail here is the XBRL INSTANCE DOCUMENT which has no letters at the end of it's naming it's bdx- numbers_only so it's the first one that interests us only.
However the statement... Like "*.xml" grabs and prints both 5 in the immediate window.
The first thing that came to my mind is ok split in two the bdx-20131231.xml and use the function IsNumeric on the second part after the hyphen however the value is coerced.
How can we make the loop pick only the first one bdx-20131231.xml?
For reasons of completeness you can see the whole code which the loop comes from here.
Courtesy of Tim Williams
The below should work:
Like "*[0-9].xml"

How to programmatically create a formatted text in VBA?

I need to create a text (2 lines, multiple fonts) programmatically, that I later place in several tables (<100) of my document.
The only way I found out to solve this, is to create a Word.Paragraph and copy its Range to the cells. The problem with this approach is: while creating a Paragraph, it's added to the Document.
I want to create a formatted text like creating a string, all in the code without modifying the Document.
One approach I have used is to use HTML or richtext, which is essentially a string anyway. I am fairly sure Word can interpret either of these with the right com object settings.
Another approach I have tried is using the clipboard instead of a word object. You can do something like this:
(importing system.windows.forms)
Clipboard.SetText(Me.RichTextBox1.Rtf, TextDataFormat.Rtf)
ApplicationName.Selection.Paste()
Could you use this on hidden text and this on deleting paragraphs?
Something like this:
Sub CreateNewWordDoc()
Dim para As Word.Paragraph
Set para = ActiveDocument.Paragraphs.Add
para.Range.Font.Hidden = True
' Do your manipulation
para.Range.Text = "Hello world"
para.Range.Font.Name = "Tahoma"
para.Range.Font.ColorIndex = wdBlue
' Now remove the paragraph as if it never existed!
para.Range.Delete
End Sub

Insert a document between 2 pages of another

I'm wondering if I can do the following:
Find a bookmark within a document
Identify the page number this bookmark is on
Insert another document before the identified page
My code so far:
Sub InsertDoc
Dim MasterDoc As Document
Dim bookmarkRng As Range
Dim pageNo As Long
Set MasterDoc = Documents.Open("Master.docx")
Set bookmarkRng = MasterDoc.Bookmarks("TheBookmark").Range
pageNo = bookmarkRng.Information(wdActiveEndPageNumber)
'1.This is where I need to specify to insert before/after the found page, not sure how
MasterDoc.InsertFile FileName:="AnotherDoc.docx"
'2.Is it possible to use this syntax instead and specify before/after insertion of a whole file?
MasterDoc.Bookmarks("TheBookmark").Range.InsertFile FileName:="AnotherDoc.docx"
MasterDoc.Save
MasterDoc.Close
Set MasterDoc = Nothing
End Sub
Any help is much appreciated, thanks.
It's best not to think in terms of pages, which ironically is an ill defined concept in Word. But if you're inserting material, you have to insert it at specific location anyhow. Since you find a range for the bookmark, and it looks like you want to insert after the bookmark, use the following:
MasterDoc.Bookmarks("TheBookmark").Range.InsertAfter "XXX"
Also, you could remove bookmarkRng and pageNo, then, unless you need them later for some reason.