copy selection from chrome to excel - vba

I'd like to create a quick way of copying and pasting in between Chrome and Excel. The program would need to perform a task of pasting the selection in a given cell. If we access Excel it's fairly easy, we just need to use Microsoft Forms Library in order to get what we copied to clipboard and paste it in the highlighted field. I'd like to extend this process. Now it looks as follows:
I copy something in Chrome
I need to switch to Excel and access the macro in order to paste what's selected
What I have so far:
Option Explicit
Public Clipboard As New MSForms.DataObject
Sub pasteTable1()
'Tools -> References -> Microsoft Forms 2.0 Object Library
'of you will get a "Compile error: user-defined type not defined"
Dim DataObj As New MSForms.DataObject
Dim S As String
DataObj.GetFromClipboard
S = DataObj.GetText
Debug.Print S 'print code in the Intermediate box in the Macro editor
ActiveSheet.Paste Destination:=Worksheets("Arkusz1").Range("A1")
End Sub
Would it be possible to skip the intermediate step and make Excel paste what's in the clipboard without having to open it? In other words I'd like to have a way of pasting the contents of clipboard automatically once the selection is made.

Related

VBA Ribbon Bar Integration

I have an Excel macro that performs a few functions on a document (Creates as form, and a few emails) all from MS-Word documents. If the macro is executed from the main spreadsheet (where the macro is), everything works normally. I want to place this macro on the ribbon allowing a user to launch it without having (or knowing where the main excel document is located or having it open). I created a sub to check to see if the spreadsheet was open and modified the ribbon to include an icon for the macro.
Which works. However, when launched from the ribbon while the main Excel spreadsheet is not open, it opens the workbook and runs the macro in entirety (Without executing the open workbook line of the macro). I assume the spreadsheet is being open because the macro that is being called resides with it (makes sense). Since the macro is dependent on the data contains in the spreadsheet, I need to allow the users to modify it and then re-running the macros from the ribbon again.
Does anyone have a recommended approach or best practices? Thank you in advance.
Sub MainForm()
Dim WorkingFolder As String
Dim File01 As String 'Main Excel Data File, where all data is
Dim File02 As String 'Preliminary Email to send to user
Dim File03 As String 'Final Email to Send to user when production is complete
Dim wb As Workbook
WorkingFolder = "C:\Temp\"
File01 = "01-MainData.xlsm"
File02 = "02-PreProductionEmail.docx"
File03 = "03-FinalProductionEmail.docx"
If wbIsOpen(File01) = True Then
MsgBox "Workbook Is Open"
Run ("'C:\Users\Guest\Nextcloud\Documents\Excel Forms\02-TEST-Production Request-Data.xlsm'!CreateProductionForm")
Else
MsgBox "The Main Datafile is not open, verify the last row before re-runing", vbOKOnly, "Not Open"
Set wk = Workbooks.Open(WorkingFolder & DataFile)
End If
End Sub
The Guide mentioned by Ricardo was not quite what I needed but it was helpful and did put me on the right track. Thank you again Ricardo. To get this working, I needed to do the following.
1 - Make the procedure above its own separate *.xlam file (saved as an add-in).
2 - Add the add-in to start automatically via the developers tab
3 - Add the Macro to the Ribbon.
I have modified the sample above to included the open statement along with the statement that executes a macros from another workbook.
Appreciate the guidance.

Copy link's address

How I can copy hyperlink's address into clipboard?
Using the "record macro" option, I get this:
Sub CopyHyperlink()
Selection.Range.Hyperlinks(1).Range.Fields(1).Result.Select
Selection.Copy
End Sub
But, this doesn't give me the desired result. See the picture to compare actual and desired results:
As you see, my code is actually copying link's text, instead of it's address.
Probably, there should be something like
Selection.Range.Hyperlinks(1).Address
but it doesn't work at all.
How make it work properly?
Assuming that you have used Selection because you recorded it with macro recorder, you should change it according to your workbook.
Insert the following library:
Tools -> References -> Microsoft Forms 2.0 Object Library
and use the following code:
Sub CopyHyperlink()
Dim clipboard As MSForms.DataObject
Set clipboard = New MSForms.DataObject
clipboard.SetText Selection.Hyperlinks(1).Address
clipboard.PutInClipboard
End Sub

Access The Nth Item of Clipboard

Is there a way to retrieve several items from the clipboard? I'm using something like this:
Dim clipboard As MSForms.DataObject
Dim str1 As String
Dim str2 As String
Set clipboard = New MSForms.DataObject
clipboard.GetFromClipboard
str1 = clipboard.GetText(1)
str2 = clipboard.GetText(2)
However, I get an error where I assign a value to my second variable that says the following:
Run-time error '-2147221404 (800040064)':
DataObject:GetText Invalid FORMATETC Structure
Help is much appreciated!
Turns out there are two clipboards: the Windows clipboard and the Office clipboard.
The Office clipboard can hold up to 24 items (all can be the same type), whereas the Windows clipboard can only hold one item of each type.
Copying to the Windows clipboard is as easy as highlighting then
typing Ctrl-C.
Copying to the Office clipboard is as easy as
highlighting then typing Ctrl-CC. The Office clipboard is only active
if there is at least one Office application open and active at the
time.
In VBA, using the MSForms.DataObject only gets you access to the Windows clipboard, so there is only a single text item available. After a variety of searches, I'm not able to find out how to open/control/copy/paste using the Office clipboard from VBA.
Having said all that, there is likely little reason to use any clipboard when writing and running a VBA macro. You can (temporarily) store those values in unused cells on a worksheet, in a public variable, in a public object, or even a private variable (probably with publically accessible properties). All of those methods serve exactly the same purpose as storing data in the clipboard.
In skimming around the interwebz on this topic, I ran across several references to using the clipboard to copy data between different workbooks, or between Office apps like Excel-to-Word. You still don't need the clipboard for this, as VBA can open the remote/external application/workbook/document and copy/paste the data directly.

Saving/restoring clipboard in Excel VBA

I have an Excel workbook with many sheets. Most sheets have some code in the Worksheet_Activate() subroutine.For some reason this code causes the contents of the clipboard to be lost - extremely annoying, as spreadsheet user cannot copy and paste between sheets.
In an attempt to fix this I have added the following lines at the beginning of the Worksheet_Activate code:
Dim dClipBoard As MsForms.DataObject
On Error Resume Next
Set dClipBoard = New MsForms.DataObject
dClipBoard.GetFromClipboard
And the following lines just before exit of the Worksheet_Activate code:
On Error Resume Next
dClipBoard.PutInClipboard
Unfortunately, it doesn't work. My clipboard is still lost when I move from sheet to sheet.
I can imagine 2 different workarounds for this case.
1- If possible change the code in the worksheets. Where ever the .copy command is used replace it with codes like these:
range("Some Range") = range("Some other range")
2- If changing the code is not possible (using the approach you are currently using) instead of storing the data to an MsForms.DataObject you could copy them to some auxiliary sheet, And retrieve the data from the worksheet before the exit worksheet event triggers.

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