MS Word macro - use system variable for template path - vba

I have a template that contains several macros, this template will be distributed on several devices.
I have the following macros to insert a text using quick parts of ms word.
Application.Templates( _
"C:\Users\user_name\AppData\Roaming\Microsoft\Word\STARTUP\template_name.dotm" _
).BuildingBlockEntries("alphabet").Insert Where:=Selection.Range, _
RichText:=True
ActiveDocument.TrackRevisions = Not ActiveDocument.TrackRevisions
The issue is, the code contains the absolute path to the template, which won't be the same on different machines.
I have tried using %Appdata% instead, but there macro did nothing, with no error messages.
is there any way around this ?
Thank you

You can use Environmental Variables in your VBA code to get the 'UserName' i.e.
"C:\Users\" & LCase(Environ("UserName")) & "\AppData\Roaming\.."
Here is one link to show other variables (or just search for 'VBA using environmental variables' (without quotes: https://www.wiseowl.co.uk/blog/s387/environment-variable-vba.htm

Related

Problems saving document immediately after Document Merge

I have an application where I need to merge several nearly identical documents which had been sent out to several users and received with minor changes and comments. The documents are fairly large (500K - 1M) and can contain tables and embedded graphics. The point of this is to consolidate the changes and comments from the various users into one document, keeping track of who did or said what.
The heart of this is the following procedure which uses Application.Merge.
Public Sub runMerge(files As String)
Dim i As Integer
Dim v() As String
v = Split(files, vbCr)
Word.Application.ScreenUpdating = False
Word.Documents.Open fileName:=v(0), ReadOnly:=False, addtorecentfiles:=False
For i = 1 To UBound(v)
ActiveDocument.Merge fileName:=v(i), _
MergeTarget:=wdMergeTargetCurrent, _
DetectFormatChanges:=True, _
UseFormattingFrom:=wdFormattingFromCurrent, _
addtorecentfiles:=False
DoEvents
Next i
Word.Application.ScreenUpdating = True
Word.Application.ScreenRefresh
ActiveDocument.SaveAs2 "Merge " & Replace(Now, ":", "."), , , , False
End Sub
The code opens the first file explicitly, then merges the remaining documents in a loop. Apart from being a bit fragile, this works correctly as long as the first document was explicitly opened.
Once merged, I use SaveAs2 with a new unqualified file name (i.e. no explicit directory). This works fairly well.
However, if I attempt to use SaveAs2 to place the file in a different directory, as in
ActiveDocument.SaveAs2 "C:\.....\Merge " & Replace(Now, ":", "."), , , , False
the resulting document does not re-appear on the screen after the merge. Further, when explicitly opened later, the document appears somehow damaged, strangely formatted, in one case, some of the text appeared in an orange colour. This behaviour has been seen in Word 2013 and 2016.
Apart from saving the document in whatever default directory (My Documents, in my case), then explicitly moving the file in VBA using copy and Kill and what not, how would one save this without an extra step?
In the end, I did the following to solve the save problem.
Using the super-easy FileCopy VBA function, I copied the first file in the merge group to the directory where I wanted the merged file to end up.
The merge loop remains unchanged.
When the merge loop is done, I used the solution from an earlier post, VBA word table copy loses data, ActiveDocument.Select followed by Selection.Collapse.
ActiveDocument.Save, not SaveAs

Embed a file into a Word doc using VBA

I am attempting to do this from Access 2010 using Word 2010. I have a WordDoc object and cannot find a way to embed a file.
I tried starting from nothing using a bookmark:
bmFile.Range.InsertFile "C:\Users\Me\Desktop\TestFile.xlsx"
and that trew an error about the File being corrupted.
I tried editing an existing embeded file using WordDoc.InlineShapes(1) but no properties were changable or relevant.
Any ideas would be greatly appreciated.
Thanks
theWordDocObject.InlineShapes.AddOLEObject _
FileName:="pathtofile", _
LinkToFile:=False, DisplayAsIcon:=False
(works at least with Excel files)
From an existing file (as per your example) you should be able to do this
bmFile.Range.InlineShapes.AddOLEObject ClassType:="Excel.Sheet.12", _
FileName:="C:\Users\Me\Desktop\TestFile.xlsx", _
LinkToFile:=False, _
DisplayAsIcon:=False
It's actually nastier to insert an object without using a file. You can do it by setting the FileName parameter to "", but then the OLE server will be started and display its UI (which doesn't happen when you embed from a file).
As for modifying anything in the embedded object, it isn't particularly straightforward because the object's UI tends to get in the way, but the starting point is the OLEFormat member of the Shape (or InlineShape). Difficult to find because "OLEFormat" is not a particularly informative name.

VBA Excel variables value after closing the excel file

I have an user form which selects a directory path. That path is stored in a variable. The problem is that every time I start the macro, I have to rechoose the path for the directory. How should be the path variable declared in order to keep it's value once the macro is closed, or the excel file is closed ?
Persisting data between calls to a macro is simpler; use a variable at module scope in the .bas module containing the macro.
Persisting data on saving is more difficult. You could write to the registry but that's tricky and you'll need to use various Windows API functions.
The simplest thing to do would be to write the data to somewhere on the workbook.
The registry is simple in VBA. It's is very limited and uses ini file concepts.
There's a few of them such as (from Object Browser [F2] in VBA editor)
Function GetAllSettings(AppName As String, Section As String)
Member of VBA.Interaction
Sub SaveSetting(AppName As String, Section As String, Key As String, Setting As String)
Member of VBA.Interaction
Sub DeleteSetting(AppName As String, [Section], [Key])
Member of VBA.Interaction
Function GetSetting(AppName As String, Section As String, Key As String, [Default]) As String
Member of VBA.Interaction
Also the newer Windows Scripting Host Shell object also makes registry access easy.
object.RegDelete(strName)
object.RegRead(strName)
object.RegWrite(strName, anyValue [,strType])
Also WMI can access registry. Unlike both above methods it can ennumerate, so you can see what is there without have to know in advance.
Dim proglist()
Set oReg=GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\default:StdRegProv")
ret = oReg.EnumKey(&H80000002, "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall", proglist)
If err.num =0 then
For each prog in proglist
msgbox prog
Next
Else
Msgbox err.num & " " & err.description & " " & err.source
err.clear
End If
It can also check security and monitor changes to keys.
I would use a Name, which can be saved with the workbook.
ThisWorkbook.Names.Add Name:="SavedPath", RefersTo:= someString
Another simple alternative is to put that value in a cell, eventually in a hidden sheet, or a hidden row/column of any suitable sheet.
A third solution is to add it to the file properties.
Registry tricks are complex, don't work if you change machine or if user has not enough rights.
I have solved the problem storing the data on a cell and then on excel file initialization giving the data to corresponding variables. Thank you very much for those who thought to a solution !

What VBA code should be used in Microsoft Word 2007 Macro to create Table of Contents

I would like to define a macro in Microsoft Word 2007 that inserts a table of contents with the provided automatic styles when a hotkey is pressed. I successfully defined a macro to insert a non-styled (e.g. basic) table of contents as follows:
Sub InsertTableOfContents()
'
' InsertTableOfContents Macro
'
'
With ActiveDocument
.TablesOfContents.Add Range:=Selection.Range, RightAlignPageNumbers:= _
True, UseHeadingStyles:=True, UpperHeadingLevel:=1, _
LowerHeadingLevel:=3, IncludePageNumbers:=True, AddedStyles:="", _
UseHyperlinks:=True, HidePageNumbersInWeb:=True, UseOutlineLevels:= _
True
.TablesOfContents(1).TabLeader = wdTabLeaderDots
.TablesOfContents.Format = wdIndexIndent
End With
End Sub
However, when I attempt to insert a styled table of contents as follows:
Sub InsertStyledTOC()
'
' Macro to insert a table of contents styled like Automatic Table 2
'
ActiveDocument.AttachedTemplate.BuildingBlockEntries("Automatic Table 2"). _
Insert Where:=Selection.Range, RichText:=True
End Sub
I get the following error:
Run-time error 5941 The requested member of the collection does not exist
I beleive this indicates that the referenced member of BuildingBlockEntries (e.g. Automatic Table 2) does not exist, but I am unclear as to why or how to correct it.
Thank you for the help
Edit - I attempted to use the filepath to the application's default Building Blocks template as suggested:
Application.Templates("C:\Program Files\Microsoft Office\Office12\Document Parts\1033\Building Blocks.dotx").BuildingBlockEntries("Automatic Table 2").Insert Where:=Selection.Range _
, RichText:=True
However, I still receive the error: Run-time error 5941 The requested member of the collection does not exist
Your code expects the Building Blocks to be found in the attached template, which, if you haven't done anything special, is probably Normal.dotm. Microsoft actually stores built-in building blocks in a different template. If you record a macro, you'll see where this template is located (mine is in "C:\Users\owner\AppData\Roaming\Microsoft\Document Building Blocks\1033\14\Built-In Building Blocks.dotx").
So, you have two options. You can use the Templates collection to get to that template and insert the building block from there (macro recorder is your friend here). Or, you can save the building block to Normal.dotm to make accessing it a little easier. To do this, click on Insert > Quick Text > Buliding Blocks, find your Building Block in the list, edit its properties, and save it to Normal. If you do that, your code should work (I have 2010, but I'm betting this is pretty similar).
I don't know of any real difference between those two options, assuming this is just for you and not something you need to distribute.
Edited to add the code I get from the macro recorder:
Application.Templates( _
"C:\Users\owner\AppData\Roaming\Microsoft\Document Building Blocks\1033\14\Built-In Building Blocks.dotx" _
).BuildingBlockEntries("Automatic Table 2").Insert Where:=Selection.Range _
, RichText:=True
So, you should try replacing the code in InsertStyledTOC with that.

MS Word Macro ... unable to insert PNG

Has anyone had problems inserting a PNG file into a word document, using a VBA Macro?
I have an MS Word document that contains a very large directory listing of image files, inside a table. I've been asked to update the document by inserting the corresponding image in front of the name.
Now, if I enter the image manually (using Insert|Image|From File), I'm able to successfully place the PNG image ... so I decided to write a quick VBA Macro to insert the image for me. The following is a sample of the code:
Dim myFile As String
Selection.SelectCell
Selection.Copy
myFile = _
Chr(34) & "C:\Documents and Settings\...\Project\Images\" _
& Left(Selection.Text, Len(Selection.Text) - 2) & Chr(34)
Selection.InlineShapes.AddPicture _
FileName:=myFile, LinkToFile:=False, SaveWithDocument:=True
Outcomes:
Whenever I execute the macro, I get the "Unable to Convert" error dialog, and no image is inserted.
I even changed the code to invoke the wdDialogInsertPicture Dialog instead, and it worked just fine.
This is very confusing ... using a manual process, the insert works, but going with an automated solution, the insert doesn't work!
Any ideas or suggestions?
I've tried the macro several times and it works ... it seems that I'm no longer able to re-create the error again. So, I'm going to mark this under the "mysteries of Office VBA" column and leave it as is ... this is not a high-priority project, so there is no need for me to continue investigating.
Thanks to Alain and Joel Spolsky for their help.