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
Related
Currently I have a document template with macros endabled .dotm. The macro has a commandbutton in there that triggers the SaveAs2 object twice formatted as below.
Public Sub FileSaveAs()
Dim dlg As Dialog
Dim strSaveFolder
strSaveFolder = Application.Options.DefaultFilePath(wdDocumentsPath)
Application.Options.DefaultFilePath(wdDocumentsPath) = ActiveDocument.AttachedTemplate.Path
ActiveDocument.SaveAs2 (ActiveDocument.AttachedTemplate.Path & " UsersName" & " FORM234" & Format(Now(), "DD-MMM-YYYY hh mm ss AMPM") & ".docm")
End
Second Save as
Public Sub SuperSave()
Dim dlg As Dialog
Dim strSaveFolder
strSaveFolder = "I:\Form Storage\CoCopy\"
ActiveDocument.SaveAs2 (strSaveFolder & "UserName" & "Form234" & Format(Now(), "DD-MMM-YYYY hh mm ss AMPM") & ".docm")
End Sub
Now here is the interesting part that has me stumped now for about a week now. This code works but only on some computers. Older models it doesn't work on for some reason. It doesn't matter Windows 10 or Windows 7 or Version of Office itself. It doesn't work on computers that are older in models like a HP EliteDesk 1 or HP EliteDesk 2. The 1 won't work but 2 will.
I have never heard of the vba macro being affected by the model of the computer version of OS yes version of Word ofcourse but never version of model. I have googled left and right and went to documentation from 2010 (including microsoft's killing activex issue of 2014 which I already ruled out)
This is how blank I mean doesn't even open the white page underneath.
Any ideas? Or have you heard of some computer models not running vba code but having the same OS and same version of Office?
Justin, I figured it out by chance were you trying to save a dotm as a docm. If the macro tries to save the dotm as a docm the formatting for the data is two separate instances. I followed through with this and noticed it in a test I ran on the document when right clicked and opened and got the same result try saving the template as a docm document instead this should resolve your issue.
Cindy, Justin is right it does yield a proper path and handles correctly in the VBA console without the slash. In the first sub he seems to only be after the path for the folder and is saving on the next parent folder outside of the folder containing the template macro. I have seen this work elsewhere why it is not working on specific models has me at a loss.
The second seems to target the location more specifically than the second which makes since if the folder is targeting a co-worker. I am currently trying to recreate the issue but having no luck your code works perfectly on my two systems I have running, both are rather new.
Try changing the wdsaveformat to match an extension type the formatting might be handled differently on newer models (unlikely but worth a shot)
Or rewrite the vba and document on the older afflicted models to see if they handle the setup and formatting differently
Scenario
I have an excel file that contains data. There are multiple users accessing the file at the same time.
Problem
There will be problem if multiple users tried to input data to that excel file at the same time due to only one user is allowed to open the file at one time
Question
Is there any way whereby I can update the excel file (Eg: add a value to a cell, delete a value from a cell, find a particular cell etc) without opening it so that multiple users can update it at the same time using excel VBA?
I went to the direction of using shared files. But later found out to be excel shared files are very buggy. If use shared file, excel/macro can be very slow, intermittent crashes and sometime the whole file may get corrupted and could not be opened or repaired afterwards. Also depends on how many users use the file, the file size can grow quite big. So it is best not to use shared workbook. Totally not worth trying. Instead if need multiple users to update data simultaneously, it is better to use some database such as MSAccess, MSSql (Update MSSQL from Excel) etc with excel. For my situation since number of users are less, I didn't use any database, instead put a prompt for the user to wait until the other user close that file. Please see the codes below to check if a file is opened and if so, to prompt user. I got this code from stack overflow itself and I modified to suit my needs.
Call the module TestFileOpened as below.
Sub fileCheck()
Call TestFileOpened(plannerFilePathTemp)
If fileInUse = True Then
Application.ScreenUpdating = True
Exit Sub
End If
End Sub
Here plannerFilePathTemp is the temporary file location of your original file. Whenever an excel file opened, a temp file will be created. For example, your original file location is as below
plannerFilePath = "C:\TEMP\XXX\xxx.xlsx"
Thus your temporary file location will be
plannerFilePathTemp = "C:\TEMP\XXX\~$xxx.xlsx"
or in other words, temporary file name will be ~$xxx.xlsx
The following codes will be called upon Call TestFileOpened(plannerFilePathTemp)
Public fileInUse As Boolean
Sub TestFileOpened(fileOpenedOrNot As String)
Dim Folder As String
Dim FName As String
Set objFSO = CreateObject("Scripting.FileSystemObject")
If objFSO.FileExists(fileOpenedOrNot) Then
fileInUse = True
MsgBox "Database is opened and using by " & GetFileOwner(fileOpenedOrNot) & ". Please wait a few second and click again", vbInformation, "Database in Use"
Else
fileInUse = False
End If
End Sub
Function GetFileOwner(strFileName)
Set objWMIService = GetObject("winmgmts:")
Set objFileSecuritySettings = _
objWMIService.Get("Win32_LogicalFileSecuritySetting='" & strFileName & "'")
intRetVal = objFileSecuritySettings.GetSecurityDescriptor(objSD)
If intRetVal = 0 Then
GetFileOwner = objSD.Owner.Name
Else
GetFileOwner = "Unknown"
End If
End Function
I encountered Out of memory issues also when used shared files. So during the process, I figured out the following methods to minimize memory consumption
Some tips to clear memory
I am using the following VB Script in a Word 2010 Doc saved as a Microsoft Word Macro-Enabled Template that is protected for form fields:
Sub SaveWithBkMarkedText()
'This code saves the Word file using the bookmark value for Maintenance Memo.
'The file is also saved to a folder in KnowHow for files related to this template.
Dim FileName As String
FileName = ActiveDocument.Bookmarks("mmn").Range.Text
'Use the C:\ code when saving the file locally
ActiveDocument.SaveAs "C:\Download\TemplatesFolders\" & FileName & ".doc"
MsgBox "Your Draft has been saved to KnowHow's Release Documentation site." & _
&vbCrLf & "The file name uses the MM that you included earlier: " & FileName, _
vbInformation + vbOKOnly, "Draft Saved to Minerva"
End Sub
The value entered into the Form Field for a FORMTEXT legacy-form object uses the Bookmark as the file name. Example, if the user enters 12345 as the value, the file is saved using this value as the filename: 12345.doc. This worked fine until a week ago when the filename is now being Prefixed with FORMTEXT 12345.doc. I have tried using this same VB script in older versions of Word on a different machine, and created from a NEW Template with the script added in from scratch, and the same issue is appearing on that machine as well. Prior to this, I was able to update my template with NO problem, but now I can't update this one FORMTEXT field without it affecting the whole file. I can update any other FORMTEXT in the template that does not use the Bookmark value as the file name, and it works. Also, I have tried changing the Bookmark Reference to another FORMTEXT object, as well as saving the file as a .DOCX and the same problem occurs regardless. What is causing the FORMTEXT to appear in the filename?
You have to un-protect the document (template) and then make the VBA programming. Once it is done, then you can protect it again (for filling forms) and you will not see the "FORMTEXT" in the filename when you run the macro.
Hope it helps.
To the OP, did you resolve this issue? I'm now having the same problem, I'm using form field text with bookmarks and using VB.net to get the bookmark.text which is now prefixed with FORMTEXT, just using a bookmark on it own and its OK, no prefix. I'm going to try and remove the first 9 characters from the result using code, a workaround, yes but it might work.
Know this is an old thread but ran into same issue. As a workaround...
Replace FORMTEXT with null "". In OP circumstance:
Dim FileName As String
FileName = ActiveDocument.Bookmarks("mmn").Range.Text
FileName = Replace(FileName, "FORMTEXT ", "")
Not a "fix" for the issue or elegant but it works.
Had the same issue. Simply delete current bookmark and add a new one. If that does not work than instead of using the following:
FileName = ActiveDocument.Bookmarks("mmn").Range.Text
try using:
Selection.GoTo What:=wdGoToBookmark, Name:="mmn"
Filename = Selection.Text
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.
I have a VBA script used to process Word documents. The first thing the program does is to create an index of the documents in a defined set of folders. It then goes through the list processing each of the indexed documents.
The problem I am having is that it will sometimes decide that a particular document cannot be found, even though it previously indexed the document and a quick spot check shows the document to be in the correct place.
Can anyone shed some light on why VBA should display this behaviour?
The script is using the Dir$ function to index the files, and the Documents.Open function to open each word document for processing.
Sample code:
ChangeFileOpenDirectory (folderName)
inputFileName = Dir$(folderName & "*.doc")
Do While inputFileName <> ""
... call various functions here ...
inputFileName = Dir$
Loop
One of the functions called in the block has the following line:
Set currentDoc = Documents.Open(fileName:=docFileName, AddToRecentFiles:=False, Visible:=False)
This is the point at which the code is failing.
One of the most annoying things I have found is that recent files links are returned as the files themselves with Dir. You can use the FileSystemObject to check the file type.
I copy/paste your code and it works correctly.
However, it leaves all the files open (and hidden), and when you run it in another directory, additional files are opened and added to the open projects (take a look in the VBA editor).
My only guess is that after a while you're hitting the maximum allowable number of open files.
Try adding
currentdoc.Close
just before
inputFileName = Dir$
A few reasons, some duplicated from other answers:
If the path+ filename is long enough ... (you already answered in a comment)
If you are writing new files to same directory, Dir$ may get corrupted (happened to me)
If you have filenames with non-std chars (ex. "#")
Files locked by other processes
Files deleted while the macro is running
You may also try this code ...
Set fso = CreateObject("Scripting.FileSystemObject")
If Not fso.FileExists(file) Then ....
First enable the Microsoft Scripting reference in the VBE