Word Paste Behavior Not the Same in VBA - vba

I have a document with a number of embedded hyperlinks to convert to plain hyperlinks. Whether they get pasted as clickable URLs or plaintext URLs doesn't matter, as long as it's actually displaying the URL.
For example, I need to change Microsoft Word to http://en.wikipedia.org/wiki/Microsoft_Word (either clickable or not).
In Word, if I select the hyperlink, right click, choose "copy hyperlink," then paste special, text only, I get the optimal result (non-clickable URL). If I record VBA code that does the exact same thing, the result is the original embedded link. I've played with various options: turning off smart paste, cut and paste, turning off autoformat of hyperlinks, changing the default paste options, but none of these change my end result.
Sub Replace_w_URLs()
'
' Replace_w_URLs Macro
'
'
Selection.NextField.Select
Selection.Range.Hyperlinks(1).Range.Fields(1).Result.Select
Selection.Copy
Selection.TypeBackspace
Selection.PasteSpecial Link:=False, DataType:=20, Placement:=wdInLine, _
DisplayAsIcon:=False
End Sub

The problem is likely the default behaviour of Word to add a hyperlink if it recognizes that the text you pasted is a URL. If you're doing this in a loop, it does the same thing as if you put the cursor at the end of the URL and hit the space-bar.
The easiest way to avoid this is to just operate on the hyperlink Ranges themselves and just change the text property. When you change HyperLink.Range.Text, it has the side effect of also removing the hyperlink at the same time.
Give this a shot:
Sub Replace_w_URLs()
Dim url As Range
Do While Selection.Hyperlinks.Count > 0
Set url = Hyperlinks(1).Range.Duplicate
url.Text = Hyperlinks(1).Address
Loop
End Sub
It should replace all of the hyperlinks in your Selection with the underlying URLs.

Related

Copy selected text from one document and paste to new document in same position on the page

I was looking for a long time but unfortunately I cannot get a clear answer anywhere.
What I need is to copy selected text from one word document than open new document and paste the text to new document but in the exactly same position in the page as the original text.
Here is what I done so far:
Sub Patient()
Dim answer As Integer
answer = MsgBox("Please select text to copy", vbQuestion + vbYesNo + vbDefaultButton1, "Info")
If answer = vbYes Then
ActiveDocument.Bookmarks.Add _
Name:="myplace", Range:=Selection.Range
Selection.GoTo What:=wdGoToBookmark, Name:="myplace"
With ActiveDocument.Bookmarks
.DefaultSorting = wdSortByName
.ShowHidden = False
End With
Selection.Copy
Documents.Add Template:="Normal", NewTemplate:=False, DocumentType:=0
Windows.CompareSideBySideWith "Test_Document.docx"
Selection.PasteAndFormat (wdFormatOriginalFormatting)
Else
MsgBox "Please highlight the text first", 16
End If
End Sub
So what I done:
1- force the user to select the text to copy, if no selection is made the error message will appears.
2- set the bookmark to name "myplace"
3- copy the bookmark
4- open the new document
4- set the view side by side
5- paste the bookmark text to new document
6- I was manually formatting the text using enter to get it to required location so I can print it on existing paper.
What I need is that the selected text will by pasted to exact location on the page as original.
The original text selection can be anywhere on the page, depends on what the user selects.
I also found that the MS Word can count start and end of my bookmark so I was hoping we can write the VBA to position of pasted text exactly where the original bookmark was:
Sub Count()
With ActiveDocument.Bookmarks("myplace")
MsgBox .Range.Start & vbTab & .Range.End
End With
End Sub
Let me describe what I am trying to achieve and why I need this function.
I have a patient record, where I write basic info about the patient like name, address, telephone number etc., and then I have therapy where I describe all the symptoms and progress what the patient make trough time.
I than print the document and store it in cabinet as hard copy, as this is legal requirements.
The patient may have many visits, so I keep adding the info to the existing record and each time I need to print it.
In order to save paper, I would like to have only the new added text to be printed on the same document I printed already. I always put the existing doc back to printer.
I know that the MS Word offers print selection option but when selected text is printed, it is always printed on top of the document and this will print over my existing text.
So what I was trying to do is select the required text, assign bookmark, copy bookmark, open new document, paste the text, set the view side by side and then I was manually formatting the text using enter to get it to required location so I can print it on existing paper.
Is there any other way to achieve this than VBA?
I would be grateful for any advice or help.
Many thanks,
Peter.

VBA Inserting Excel complexe spreadsheet in .doc document

So I've been working on a word .dotm file that will combine several .doc and .xls documents into a single .pdf file.
Right now, I have two different problems, I will only detail the first one on this topic:
When inserting a complexe (very complexe) Excel sheet in my .doc document, the output is only a pile of meta data (Well mostly looks like it, if you prefer clearer language: it is a complete mess of characters and page breaks) instead of my file. I've looked for the entire day (really, I wasted my work day looking for answers) on the internet and even asked on MSDN forum (no answer at all) about this topic and everyone seems to have his code working like a charm.
Here is my code:
Sub MergeFiles()
Documents.Open FileName:="C:\test_cea\02.doc"
Selection.EndKey Unit:=wdStory
Selection.InsertFile FileName:="C:\test_cea\03.doc"
Selection.EndKey Unit:=wdStory
Selection.InsertFile FileName:="C:\test_cea\04.xls"
ActiveDocument.SaveAs2 FileName:="C:\test_cea\output.pdf", FileFormat:=wdFormatPDF
ActiveDocument.Close SaveChanges:=doNotSaveChanges
End Sub
I've tried a TREMENDOUS amount of things, from switching to opening the .xls first, to trying every single combination of parameters possible in my InsertFile() method and nothing works.
The most amusing part is: it works perfectly when trying to do it with Word UI, meaning Word can do it, but I'm doing it wrong somehow.
Here's the final answer to that question:
As Word cannot interpret an Excel file it is not possible to force file insertion this way.
Instead use the following code:
Sub MergeFiles()
Dim appExcel As Excel.Application
Dim wdDocument As Word.Document
Set appExcel = CreateObject("Excel.Application")
Set wdDocument = Documents.Open("mydoc.doc")
appExcel.Workbooks.Open("myxls.xls")
appExcel.ActiveWorkbook.Sheets(1).Range("Print_area").CopyPicture 'Copy picture prevents weird behavior from Word'
Selection.PasteSpecial Placement:=wdInLine, DataType:=wdPasteMetafilePicture
End Sub
Obviously this is a sample code that will do the whole process but the idea is to copy the Print Area (one must be defined, you can also use Sheets(1).UsedRange but this will be a problem if the Excel file is oddly formatted) as picture and paste it into Word. You can also simply copy it and paste it but it may mess up your output table formatting.
I don't even know why people down voted my question -_-
Anyway, if you encouter the same issue, simply tell me if this code works.

Using vba to copy the contents of a word document into another word document

I haven't used VB for years, so please forgive me if this turns out to be obvious. I'm trying to write a word vba macro for use in a template which will display a userform and then import the contents of fileA.docx, fileB.docx, or fileC.docx depending on the userform. (After that I'm going to use bookmarks to fill in some form data, I don't know if that's relevant). Files A, B, and C will contain text with some basic formatting such as lists, but nothing fancy.
The solutions I've seen online can copy the contents of file to a new file, but ideally I would like to import the entirety of one of those files into the new, currently unnamed file that I'm getting from the template. I think where I'm running into problems is with switching the selection to one of those files, and then back to the new unnamed document, though I could use a hand to make sure I'm copying correctly as well.
Update: I was making things too hard, though the answers here got me pointed in the right direction (thanks!). In the end I just did
ThisDocument.Activate
Selection.InsertFile("fileA")
which gives me the raw dump of everything that I wanted.
Using commands such as these you can switch between which Document you're using and copy and paste elements:
ThisDocument.Activate 'Sets the main document active
Documents("Name.doc").Activate 'Activates another document
You can insert, copy and paste things in and out of documents using copy commands.
ThisDocument.Range.InsertAfter("String") 'Insert text
Selection.WholeStory 'Select whole document
Selection.Expand wdParagraph 'Expands your selection to current paragraph
Selection.Copy 'Copy your selection
Documents("name.doc").Activate 'Activate the other document
Selection.EndKey wdStory 'Move to end of document
Selection.PasteAndFormat wdPasteDefault 'Pastes in the content
You can then go and format such, or copy and paste them with original formatting from before.
Here is a significant improvement (I think) you will want to incorporate because it:
does not use the clipboard and thus does not make your macro vulnerable to the user changing the contents of the clipboard while your macro is running
does not use a file and thus greatly improve the speed by eliminating I/O and eliminates the potential of having to deal with file system security/permissions, etc. Please do not use .InsertFile() if you are looping through documents you will slow yourself down. Use it once, at the end -only if you have to. The example below shows how to accomplish the same result without using .InsertFile()
The idea is to transfer some portion of text found in 1 source document, to a destination document that is different than the source, and keep the source formatting.
To accomplish the above (skipping the code to open documents):
For Each oTable In oDoc_Source
'the above could have been anything that returns a Range object
'such as: ActiveDocument.Content.Find.Execute ....
'...
'logic here to identify the table, or text, you are looking for
'...
'I can't believe the MS Dev Center folks could only think
'of .InsertFile(), which is the last resort I would go for,
'especially if your code runs on a web server [concurrent web requests]!
'SAFEST
'(no user interference on clipboard possible, no need to deal with file i/o and permissions)
'you need a reference to Document.Content,
'as the act of obtaining a reference "un-collapses" the range, so the below 3 lines must be in that order.
Set oRange = oDoc_DestinationDoc.Content
oRange.Collapse Direction:=wdCollapseEnd
oRange.FormattedText = oTable.Range
'BRUTE, AND PRONE TO RANDOM ERRORS AND HANGS DUE TO USER INTERFERENCE WITH CLIPBOARD
'find a way to implement WIHTOUT using the CLIPBOARD altogether to copy the below range object
'it will be easier for PC users to use the clipboard while the macro runs
'and it will probably be safer for the output of this macro to remain uncorrupted
'oTable.Range.Copy
'Set oRange = oDoc_DestinationDoc.Content
'oRange.Collapse Direction:=wdCollapseEnd
'oRange.Paste
'THE BELOW DOES NOT WORK
' '1) - cannot add a range from another document
' 'adds only text, not the formats and not the table layout
' oTable.Range.TextRetrievalMode.IncludeFieldCodes = True
' oTable.Range.TextRetrievalMode.IncludeHiddenText = True
' oDoc_DestinationDoc.Content.InsertAfter oTable.Range
'
' '2) - cannot add a range from another document
' oDoc_DestinationDoc.Content.Tables.Add oTable.Range, iRowMax, iColMax
'
' '3) - only puts in plain text, and it replaces the range without the .Collapse call
' oDoc_DestinationDoc.Content.Text = oTable.Range
Record a macro...
start in the source document
press ctrl-a to select everything
press ctrl-c to copy it to the clipboard
switch to the target document
press ctrl-v to paste into the document
stop recording
or (assuming word 2007 or later)
start in the target document with the source document closed
on the ribbon click insert > object > Text from file...
navigate to the source document
click the insert button
stop recording
I prefer the second version so I should have put it first
I was doing the same thing, tried to select the other document, copy and paste. But it didn't worked (I received an error probably because some other application was using the clipboard, but I am not sure.). So I did a little search and found the perfect solution on Microsoft Dev Center.
https://msdn.microsoft.com/en-us/vba/word-vba/articles/selection-insertfile-method-word
Selection.Collapse Direction:=wdCollapseEnd
Selection.InsertFile FileName:="C:\TEST.DOC"
'set current doc name and path
Dim docName As String: docName = ActiveDocument.name
Dim filepath As String: filepath = ActiveDocument.Path
'create a new file
Documents.Add
'get the path of a current file
ChangeFileOpenDirectory filepath
'insert content of current file to newly created doc
Selection.InsertFile _
FileName:=docName, _
Range:="", _
ConfirmConversions:=False, _
Link:=False, _
Attachment:=False
'open prompt to save a new file
With Dialogs(wdDialogFileSaveAs)
.name = docName & "-copy"
.Show
End With

Blank line after deleting contentControl in word

I'm trying to write in a word document via VB.net and for this I'm using contentControls in my Word Document but sometimes I have to delete a contentControl or another via VB code.
It's kind of easy with contentcontrol.delete but when this contentControl contains multipleline and I want to delete it then it leaves a blank line. How can I avoid this?
I will give you some tips based on VBA which I hope you could easily convert to vb.net and your solution.
You need to cover complete range of ContentControl including beginning and end of the object. You could do it in this way (VBA code for first CC in activedocument):
With ActiveDocument.ContentControls(1)
'just to make a presentation- let's select range to be deleted
ActiveDocument.Range(.Range.Start - 1, .Range.End + 2).Select
'and we delete selection
Selection.Delete
End With
Obviously you could combine .Select and .Delete lines into one to avoid selection in this way:
With.... and so on
ActiveDocument.Range(.Range.Start - 1, .Range.End + 2).Delete
End with

WORD 2010 Macro for Editing Headers & Footers

I have only basic VBA experince and my prior Macro experence was primarily with WORD 2003. Recording Macros used to take GoToFooter (or Edit Footer) Menu Commands and allow subsequent editing. In WORD 2010, this (and many other) commands do not "record" to the Macro (yet when in Record mode, I do get into Edit Footer function).
A research of various VBS options shows several ways to create Footers and to make global Footer setting changes within Macro. However If I simply want to Revise the Company name within the Footer (for example), I can find no way to do this within a Macro subroutine.
This subroutine is one that I would call from the Main Macro that is stepping through each file in a Folder (& subfolders). I have the main Macro functioning.
Does WORD 2010 Macro-VBA preclude simple Edit-Footer function?
Thanks in advance
So, thanks to Issun, here is my solution:
`
Sub Sub_FTR_0()
'
ActiveDocument.ActiveWindow.ActivePane.View.SeekView = wdSeekCurrentPageFooter
For i = 1 To ActiveDocument.Sections.Count
'REM: INSERT Code from RECORD MACRO recorded when editing one Footer correctly
Selection. [[xxx]], etc.
If i = ActiveDocument.Sections.Count Then GoTo Line1
ActiveDocument.ActiveWindow.ActivePane.View.NextHeaderFooter
Line1:
Next
ActiveWindow.ActivePane.View.SeekView = wdSeekMainDocument
End Sub
`
Here is a way you can access the headers/footers via VBA. As you can see, it's rather complicated syntax to get to something so simple :p there
Sub EditHeadersAndFooters()
Dim i As Long
For i = 1 To ActiveDocument.Sections.Count
With ActiveDocument.Sections(i)
.Headers(wdHeaderFooterPrimary).Range.Text = "Foo"
.Footers(wdHeaderFooterPrimary).Range.Text = "Bar"
End With
Next
End Sub
Here is a link to example code on how to change the headers in every file in a folder. It takes a different approach and I have never tried it, but for your reference: http://www.vbaexpress.com/kb/getarticle.php?kb_id=45
This worked for me for all pages in the document.
word.ActiveDocument.Sections(1).Headers(1).Range.Text = "Put the header here"