Right now I have a Word Document with the following text:
FullName
Position
Address
Each line is made as a separate bookmark. The bookmark name for each line is the same as the word (the bookmark for FullName is FullName).
When I iterate through the bookmarks and update the text of the three different bookmarks, the first two get deleted and I am just left with the address. I think some how the bookmarks are getting combined in the editing process somehow.
Here is the code I have:
Dim saveFileDialog1 As New SaveFileDialog()
saveFileDialog1.Filter = "Word|*.docx"
saveFileDialog1.Title = "Save your report file"
Dim FilePath = "C:\Users\Administrator.Laptop1\Desktop\TESTER.docx"
Dim myWordDoc As Microsoft.Office.Interop.Word.Document
Dim myWordApp As Microsoft.Office.Interop.Word.Application
Dim filepathname As Object = TryCast(FilePath, Object)
Dim missing As Object = Type.Missing
Dim objTrue As Object = TryCast(True, Object)
' create Word.Application object for the document
myWordApp = New Microsoft.Office.Interop.Word.Application
' open the document
myWordDoc = myWordApp.Documents.Open(filepathname, missing, missing, missing, missing, missing, missing, missing, missing, missing, missing, missing, missing, missing, missing, missing)
'update Opinion
myWordDoc.Bookmarks("SendDate").Range.Text = (Convert.ToDateTime(TextBox7.Text)).ToString("MMMM dd, yyyy")
myWordDoc.Bookmarks("FullName").Range.Text = TextBox4.Text & " " & TextBox5.Text & " " & TextBox6.Text & vbLf
myWordDoc.Bookmarks("Position").Range.Text = TextBox8.Text & vbLf
Instead of using Interop services and bookmarks to accomplish this, you should consider using DocumentFormat.OpenXml.Wordprocessing and simple replacements.
Its more stable and behaves better, doesn't hang word.
You could simply loop through the documents body descendants for things like "{FirstName}" and do replacements, rather than using bookmarks which may always haunt you.
Related
I have some code in VBA on Microsoft Word, I just want to save some text as a file in a specific folder.
Here's the relevant part of code (not including the rest as its all spaghetti code that doesn't even reference TextBox3 at all):
Dim foldername As String
foldername = TextBox3.Text
Dim Fileout As Object
Set Fileout = fso.CreateTextFile("C:\Users\JaneDoe\Desktop\" & foldername & "\" & myValue & ".html", True, True)
Fileout.Write finaltext
Fileout.Close
This code ONLY doesn't work when it references TextBox3.Text, if I change that to "testing123" it works perfectly, but I need to use the text from TextBox3
The error I'm getting is:
Run-time error '424':
Object required
And it references this line:
foldername = TextBox3.Text
Any and all help is greatly appreciated, do keep in mind I'm a bit of a noob to VBA though so yeah :)
I am not a programmer so not sure what to do here. I would like an option of adding an image file in a Microsoft Word document userform for MAC. I had used a code earlier which works perfectly in Windows but it doesnt work for MAC and gives a 5948 error. I had added a field for the image in the userform with a button to add the image and the final submit button. The add button should allow the user to insert any size image from the local folder.
The code I was using is given below:
Dim ImagePath As String
Private Sub CMDAddImage_Click()
Dim objFileDialog As Office.FileDialog
Set objFileDialog = Application.FileDialog(MsoFileDialogType.msoFileDialogFilePicker)
With objFileDialog
.AllowMultiSelect = False
.ButtonName = "File Picker"
.Title = "File Picker"
If (.Show > 0) Then
End If
If (.SelectedItems.Count > 0) Then
Call MsgBox(.SelectedItems(1))
ImagePath = .SelectedItems(1)
End If
End With
Image1.Picture = LoadPicture(ImagePath)
End Sub
And the code in submit button was:
Dim objWord
Dim objDoc
Dim objShapes
Dim objSelection
'Set objSelection = ActiveDocument.Sections
'objSelection.TypeText (vbCrLf & "One Picture will be inserted here....")
ActiveDocument.Bookmarks("Field04").Select
Set objShapes = ActiveDocument.InlineShapes
objShapes.AddPicture (ImagePath)
End
End Sub
Can someone please help me edit the code for mac. In mac it does not allow to add the file.
You should check out the suggestion made by #JohnKorchok in a comment to your previous question - insert an image Content Control in your document instead, and throw away the VBA.
But if you need to keep using VBA and a UserForm...
Application.FileDialog is not available on Mac.
Application.GetOpenFileName is not avaialble from Word (it's an Excel thing).
Application.Dialogs does not do the same thing as GetOpenFileName so the user experience will be rather different, but at its simplest, you can use it like this:
With Application.Dialogs(wdDialogFileOpen)
' .Display = -1 for "OK" ("Open" in this case)
' .Display = 0 for "Cancel"
' (THere are other possible return values
' but I do not think they are applicable here)
If .Display = -1 Then
ImagePath = .Name
End If
End With
or if you prefer, the lengthier
Dim dlg As Word.Dialog
Set dlg = Application.Dialogs(wdDialogFileOpen)
With dlg
If .Display = -1 Then
ImagePath = .Name
End If
End With
Set dlg = Nothing
However, this dilaog does not let you specify file types or any kind of filtering, a starting folder etc. Attempts to set Finder search criteria via something like
.Name = "(_kMDItemFileName = ""*.jpg"")"
.Update
before the .Display either can't work or need different syntax.
Further, the Apple dialog may start with its
own filtering set up so the user will have to click Options to enable All Files. You don't know what file type the user will choose so you will need to deal with that.
An alternative is to invoke Applescript. For this, it appears that you can still use the VBA MacScript command, which means that you can put all the script in your VBA file. If that does not work, then unfortunately you have to use AppleScriptTask which would require you to work some more on the Script and install the script in the correct folder on every Mac where you need this feature.
Here's the code I used - you would probably need to wrap everything up in another function call and use conditional compilation or other tests to call the correct routine depending on whether the code is running on Mac or Windows
Private Sub CMDAddImage_Click()
Dim s As String
Dim sFileName As String
On Error Resume Next
s = ""
' set this to some other location as appropriate
s = s & "set thePictureFoldersPath to (path to pictures folder)" & vbNewLine
s = s & "set applescript's text item delimiters to "",""" & vbNewLine
s = s & "set theFile to ¬" & vbNewLine
' add the image file types you want here
s = s & "(choose file of type {""png"",""jpg""} ¬" & vbNewLine
s = s & "with prompt ""Choose an image to insert."" ¬" & vbNewLine
s = s & "default location alias thePictureFoldersPath ¬" & vbNewLine
s = s & "multiple selections allowed false) as string" & vbNewLine
s = s & "set applescript's text item delimiters to """"" & vbNewLine
' choose file gives as an AFS path name (with colon delimiters)
' get one Word 2016/2019 will work with
s = s & "posix path of theFile"
sFileName = MacScript(s)
If sFileName <> "" Then
' Maybe do some more validation here
ImagePath = sFileName
Image1.Picture = LoadPicture(ImagePath)
End If
End Sub
I have a Word document and I want to do following with it:
Select some part of it when I open a Word doc (let´s say from page 40 to 45).
Reverse text in selected area.
Get text reversed again as it was before opening, when I close document.
I have this code, that reverses the text:
Sub ReverseSelectedWords()
Dim i As Integer
Dim oWords As Words
Dim oWord As Range
Set oWords = Selection.Range.Words
For i = 1 To oWords.Count Step 1
Set oWord = oWords(i)
Do While oWord.Characters.Last.Text = " "
Call oWord.MoveEnd(WdUnits.wdCharacter, -1)
Loop
Debug.Print "'" & oWord.Text & "'"
oWord.Text = StrReverse(oWord.Text)
Next i
End Sub
For what you've described as being your goal, it would make far more sense to apply a password for opening to the document and provide only the intended reader(s) with that password. No code required.
I want to generate an automatic footer when I save a new MS Word file, and update the footer if I SaveAs the file.
The code below used to work well with an old Word. With the latest Word it only works if I press F12 on the keyboard. Any help would be greatly appreciated!
Sub FileSaveAs()
Dialogs(wdDialogFileSaveAs).Show
Dim i As Long
Dim ThisPath As String
Dim pName As String
Dim TextInFooter As String
Dim FullName As String
ThisPath = ActiveDocument.Path
pName = ActiveDocument.Name
FullName = ThisPath & "\" & pName
TextInFooter = "This file was saved in: " & FullName & " on the " & Now
For i = 1 To ActiveDocument.Sections.Count
With ActiveDocument.Sections(i)
.Footers(wdHeaderFooterPrimary).Range.Text = TextInFooter
End With
Next
End Sub
As you noticed, the new version triggers the FileSaveAs only on F12. Not sure if this is bug or a feature.
If it is only important that the document shows the information in print or on open - my suggested workaround:
You could avoid the insertion into the footer on save and insert it using fields, the document already has the information you are inserting. You simply need to make it visible. The footer would be then:
This file was saved as { FILENAME \p } the { SAVEDATE \# "dd.MM.yyyy HH:mm:ss"}
Adjust the Date/Time format as needed. You have to force the update of the fields - this is where the auto macros come into it.
Sub AutoOpen()
' set fields to update before printing (if saved as and printed while open)
Options.UpdateFieldsAtPrint = True
' Update all current fields in just opened document
ActiveDocument.Fields.Update
End Sub
Sub AutoClose()
' update fields when closing
ActiveDocument.Fields.Update
End Sub
The only difference would be, that you have the full path including file name and extension there. Additionally, there might be times, when the file is saved but not yet opened/closed/printed and has also not updated the fields.
In theory, you could insert the footer into the document with the AutoOpen macro as well (activedocument.fields.add).
I'd like to be able to delete individual files that are stored as attachments in an Access Database through VB.Net
I've managed to get storing, opening and "downloading" from an Access Database to work effectively, but the last piece of the puzzle would be to allow my end-user to delete an individual file in the attachments field.
This seems to be much harder than the other options as I can only seem to find information on how to delete the entire database entry, not just a single attachment. It gets even more complicated if there are more than one attachments stored against the entry.
I am using the following code to check what happens when the datagrid is clicked:
If e.ColumnIndex = ViewFileColum.Index Then
'Get the file name and contents for the selected attachment.
Dim gridRow = childgrid.Rows(e.RowIndex)
Dim tableRow = DirectCast(gridRow.DataBoundItem, DataRowView)
Dim fileName = CStr(tableRow(FILE_NAME_COLUMN_NAME))
Dim fileContents = GetFileContents(DirectCast(tableRow(FILE_DATA_COLUMN_NAME), Byte()))
DisplayTempFile(fileName, fileContents)
End If
If e.ColumnIndex = DownloadFileColumn.Index Then
'Get the file name and contents for the selected attachment.
MoveFile = True
Dim gridRow = childgrid.Rows(e.RowIndex)
Dim tableRow = DirectCast(gridRow.DataBoundItem, DataRowView)
Dim fileName = CStr(tableRow(FILE_NAME_COLUMN_NAME))
Dim fileContents = GetFileContents(DirectCast(tableRow(FILE_DATA_COLUMN_NAME), Byte()))
DisplayTempFile(fileName, fileContents)
End If
I want to add a third section that states if the DeleteFileColumn button is clicked then to remove that particular attachment from the database, but this doesn't seem possible.
When retrieving the information for the above two options, I use the following code:
Dim tempFolderPath = Path.GetTempPath()
Dim tempFilePath = Path.Combine(tempFolderPath, fileName)
'If the specified file exists, add a number to the name to differentiate them.
If File.Exists(tempFilePath) Then
Dim fileNumber = 1
Do
tempFilePath = Path.Combine(tempFolderPath,
String.Format("{0} ({1}){2}",
Path.GetFileNameWithoutExtension(fileName),
fileNumber,
Path.GetExtension(fileName)))
fileNumber += 1
Loop Until Not File.Exists(tempFilePath)
End If
'Save the file and open it.
'If "DOWNLOAD" button is clicked
If MoveFile = True Then
File.WriteAllBytes(SaveLocation & "\" & Path.GetFileNameWithoutExtension(fileName) & Path.GetExtension(fileName), fileContents)
MoveFile = False
'If "OPEN" button is clicked
Else
File.WriteAllBytes(tempFilePath, fileContents)
Dim attachmentProcess = Process.Start(tempFilePath)
If attachmentProcess Is Nothing Then
'Remember the file and try to delete it when this app closes.
tempFilePaths.Add(tempFilePath)
Else
'Remember the file and try to delete it when the associated process exits.
attachmentProcess.EnableRaisingEvents = True
AddHandler attachmentProcess.Exited, AddressOf attachmentProcess_Exited
tempFilePathsByProcess.Add(attachmentProcess, tempFilePath)
End If
End If
This code copies the information before opening it, so I don't ever actually deal with the file in the database directly. I've used adapted this code from another example I found online, but am having a hard time working out how to physically deal with the file on the database, or if its even possible?
Thanks
You need to create an Access DAO Recordset2 object for the attachments field, find the record corresponding to the specific attachment you want to delete, and then Delete() that record.
The following example will remove a document named "testDocument.pdf" from the attachments field for the record where ID=1:
' required COM reference:
' Microsoft Office 14.0 Access Database Engine Object Library
'
' Imports Microsoft.Office.Interop.Access.Dao
'
Dim dbe As New DBEngine
Dim db As Database = dbe.OpenDatabase("C:\Users\Public\Database1.accdb")
Dim rstMain As Recordset = db.OpenRecordset(
"SELECT Attachments FROM AttachTest WHERE ID=1",
RecordsetTypeEnum.dbOpenDynaset)
rstMain.Edit()
Dim rstAttach As Recordset2 = CType(rstMain.Fields("Attachments").Value, Recordset2)
Do Until rstAttach.EOF
If rstAttach.Fields("FileName").Value.Equals("testDocument.pdf") Then
rstAttach.Delete()
Exit Do
End If
rstAttach.MoveNext()
Loop
rstAttach.Close()
rstMain.Update()
rstMain.Close()
db.Close()