How to programmatically create a formatted text in VBA? - 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

Related

Deleting Blank Pages in Word Doc with 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

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).

Adding a hyperlink in word, with vb.net

I'm currently trying to add a hyperlink to a web url in word through a VB program. I'm stumbling around to try and find the proper syntax and what I need to accomplish this, because I've been getting a lot of unhelpful VBA examples, which is not what I need at all.
My code looks like this:
sPara2 = oDoc.Content.Paragraphs.Add
sPara2.Range.Text = attachmentRdr("attachmentName")
sPara2.Range.Hyperlinks.Add(attachmentRdr("attachmentPath"))
sPara2.Format.SpaceAfter = 24 '24 pt spacing after paragraph.
sPara2.Range.InsertParagraphAfter()
where attachmentRdr is a sqlDatareader reading strings of text (attachment name, and path) from a database. If I run this, I get an error for bad parameters (which gets' proced off of the hyperlinks.add()).
Pass range through as the first parameter to the Add function, followed by your URL:
Dim range As Microsoft.Office.Interop.Word.Range
range = Me.Application.Selection.Range
range.Hyperlinks.Add(range, "http://www.microsoft.com")

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.

Font of all headings in a Word Document

I am trying to retrieve the font name and size of all the headings from a word document. Any idea how to get it?
The basic structure will be something like below:
Public Sub ShowFontAndSize()
Dim singleLine As Paragraph
Dim lineText As String
For Each singleLine In ActiveDocument.Paragraphs
Debug.Print singleLine.Range.Font.Name
Debug.Print singleLine.Range.Font.Size
Next singleLine
End Sub
The catch will be that this won't sense if there are different fonts and sizes on the same line. If that's a possibility, you will need to add another loop with For Each singleCharacter In singleLine.Range.Characters inside of the paragraphs loop.
Edit: A trickier problem is what to do with this data once you've collected it. Building up an array seems like the natural fit, but VBA arrays are borderline useless, since basic methods like .append() require you to redim the whole array. See http://www.cpearson.com/excel/VBAArrays.htm for more info if you would like to go down that road.
The most straight forward solution is to open the document in Word and access the object model. This is traditionally done using VBA, but you can also use .NET (e.g. C# og VB.NET) by using VSTO (Visual Studio Tools for Office). Personally I find C#/VB.NET much better languages than VBA.
Once you have access to the object model you will have to enumerate paragraphs in the document. When you find a heading (perhaps defined by the style) you will have to figure out the formatting of the heading.
This is what I got from a brief skim of the MSDN page on "HeadingStyles":
MsgBox ActiveDocument.HeadingStyles(1).Style