Can't insert pictures in Excel with VBA - excel

I am getting completely crazy about this issue, please help me.
I have made a shell script that writes in a text file the path of some images that are stored in a folder. Then I use an excel code to read each path and write it in an excel cell.
I have then made a code that should take that path and use it to insert the picture. I have tried with Pictures.insert(path) and shapes.addpictures "path", but I have the same issue every time, the picture can't be loaded.
What's weird, is that, if I manually insert the picture before and then delete it, the code will perfectly load the picture. But if it's the first time then no.
The paths that I'm using look like that: "/Users/theodorebedos/Documents/code_tilly/new_pict_tilly/IMG_9040.jpg"
I'm using a mac, maybe that matters?
Private Sub Convert_Img()
Dim myPict As Picture
Dim PictureLoc As String
Dim EndPictRow, i As Integer
Dim StartPath As String
If Worksheets("Main").Cells(3, 1).Value <> "" Then
EndPictRow = Worksheets("Main").Range("A2").End(xlDown).Row
For i = 3 To EndPictRow
PictureLoc = Worksheets("Main").Cells(i, 1).Value
Worksheets("Main").Cells(i, 1).ClearContents
Worksheets("Main").Cells(i, 1).ColumnWidth = 30
Worksheets("Main").Cells(i, 1).RowHeight = 150
ActiveSheet.Shapes.AddPicture PictureLoc, False, True, Worksheets("Main").Cells(i, 1).Left, Worksheets("Main").Cells(i, 1).Top, Worksheets("Main").Cells(i, 1).Width, Worksheets("Main").Cells(i, 1).Height
Next i
End If
End Sub
Edit:
When I use "Pictures.insert" or "shapes.addpicture path, true, true " I have no error message in VBA but I have in excel instead of my picture, a blank image with inside an error message like this:
image
If I use "shapes.addpicture path, FALSE, true" then I have an error message like this but no image at all is loaded: image 2
And then an error 1004 like that:
image3
And if I do the process to have image 1, then I save the document, reopen it, I'll have this directly: image 4
Thanks for you help. It will be much appreciated.

I streamlined your code so it becomes possible to see what it's doing. Note that I avoided reading values from the cell's properties which were just set or are obvious.
Once the column width has been set, the width of all cells in it are the same.
The Left property of all cells in a column is always the same.
If the column is column A, the Left is always 0.
Of course, what you tried to achieve is to enter a value only once. That is good practice but to read properties from the sheet is slow. The faster way - less code volume and better readable, too - is to declare a constant at the top and use that name in the code.
So you end up with this code.
Private Sub Convert_Img()
Const ClmWidth As Single = 30
Const RowHight As Single = 150
Dim EndPictRow As Long, R As Long
' sorry, I recommend i for arrays and R for rows (C for columns)
With Worksheets("Main")
' End(xlDown) will find the first blank cell below the base cell.
' There might be more filled cells further down.
' End(xlUp) will find the first used cell above the base cell
' disregarding more blanks above that one.
EndPictRow = .Cells(.Rows.Count, "A").End(xlUp).Row
' no need to set the column width multiple times in the loop
.Columns(1).ColumnWidth = ClmWidth
' this loop will never run if R < EndPicRow
For R = 3 To EndPictRow
With .Cells(R, 1)
.RowHeight = RowHight
' this will work only once:-
.Worksheet.Shapes.AddPicture CStr(.Value), False, True, 0, .Top, ClmWidth, RowHight
End With
Next R
End With
End Sub
The reason why it works only once becomes quite obvious. The new picture takes its source path from the cell's Value. Of course, once you insert a picture (image) in the cell that value can't be the path (string) anymore. If you run the code a second time it will fail. However, if that is your need, it should be possible to extract the path from the formula that defines the picture in the cell. Given that the picture itself isn't present at that location the formula should either hold the path or a reference to a location within the workbook's background data, depending upon how it was loaded.

Ok, so it's not perfect yet, but I put the loop off and I used Dir() as you said #Variatus.A pop-up window like this opened when I executed the command Dir(). It asked me the authorisation to access the file. I pressed yes and then it worked.
It worked but only for that file. So I guess, I am on the right way now and I need to find how to give access to all the files in that folder before running the code. I can't do it for all of them.
Thank you very much.

I hope someone will benefit from this old thread. As it turns out this is some sort of a permission issue also noted already in one of the comments, possibly only occurring with Excel 16 macros on OSX.
It seems like Excel is lacking the permissions to access the resources linked and is not asking for them. We need to grant permissions to all files in the folder. The following code demonstrates how to achieve this, given the identifier to build the paths is in Column A2:20. Run this macro (adjust the way the path is built), then grant access once the dialogue appears:
Sub GrantAccess()
Dim cName As Variant
Dim files() As Variant
Set xRange = ActiveSheet.Range("A2:A20")
For Each cell In xRange
ReDim Preserve files(1 To cell.Row - 1)
cName = "/Users/adjust-your-path/path" & Cells(cell.Row, "A") & "_thumb_600.png"
files(cell.Row - 1) = cName
Next
fileAccessGranted = GrantAccessToMultipleFiles(files)
End Sub
Code used:
Sub URLPICInsertMM()
Dim cShape As Shape
Dim cRange As Range
Dim cColumn As Long
Dim cName As String
Dim img As Picture
Application.ScreenUpdating = False
Set xRange = ActiveSheet.Range("B2:B10")
For Each cell In xRange
'cName = Application.GetOpenFilename(Title:="Select Picture To Be Imported")
' files are located in thumbs sub-directory
cName = "/Users/.../IonChannels/thumbs/" & Cells(cell.Row, "A") & "_thumb_300.png"
Set img = ActiveSheet.Pictures.Insert(cName)
img.Select
Set cShape = Selection.ShapeRange.Item(1)
If cShape Is Nothing Then GoTo line22
Cells(cell.Row, "C").Value = "file://" & cName
Set cRange = Cells(cell.Row, cell.Column)
With cShape
.LockAspectRatio = msoTrue
'If .Width > cRange.Width Then .Width = cRange.Width
If .Height > cRange.Height Then .Height = cRange.Height
.Top = cRange.Top + (cRange.Height - .Height)
.Left = cRange.Left + (cRange.Width - .Width)
End With
line22:
Set cShape = Nothing
Range("T2").Select
Next
Application.ScreenUpdating = True
End Sub
Edit:
Evidence:
I created a simple test sheet (the idea is to load some protein visualization thumbs into an excel sheet) with an identifier in Column A, image file descriptors are constructed from the identifier + path and file extension.
The image is inserted into Column B and the file descriptor as text into Column C.
When I ran the macro for the first time, only the first image was loaded. Excel formats the file descriptor as a hyperlink. When clicking the file:///... link, Excel opens a dialog that asks to grant permissions to that file (screenshot). If I grant access and accept warnings, then run the macro again, the image appears.
After running macro again, image is displayed:

Related

VBA partial match

I've been making what started out as a basic asset tracker, but as its progressed more and more has been added.
before this I've never done anything with excel, meaning most of what i have done has been through searching, copying, and making slight changes to code found online.
Im now trying to search for a client name held on a "Database" sheet and display all assets assigned to that client on a "Reports" sheet
I have "Userform5" with a command box auto populating the name of the client as you begin typing
Client name is often referred to differently, so the official client name is loaded into the command box, however on the spreadsheet it may have been inputted as a shortened version of the name. Eg, Tarmac Trading Limited is the official name loaded into the command box, on the Database this may be input as just Tarmac or another slight variation.
i have a code that works fine, but only for exact matches, and will even disregard if a space has been entered at the end of the client name on "database"
is there a way to change the below code to search for partial matches?
Sub ClientSearch_Click()
Application.ScreenUpdating = False
Dim Client As String
Dim finalrow As Integer
Dim i As Integer
Sheets("Reports").Range("A2:aj10000").ClearContents
Client = Trim(Cmbclient.Text)
Sheets("Database").Activate
finalrow = Sheets("Database").Range("A10000").End(xlUp).Row
For i = 2 To finalrow
'Function equalsIgnoreCase(str1 As String, str2 As String) As Boolean
' equalsIgnoreCase = LCase(str1) = LCase(str2)
'End Function
If LCase(Sheets("Database").Cells(i, 4)) = LCase(Client) Then
Range(Cells(i, 1), Cells(i, 50)).Copy
Sheets("Reports").Range("A100").End(xlUp).Offset(1, 0).PasteSpecial xlPasteValues
End If
Next i
Sheets("Reports").Activate
Range("A:AZ").EntireColumn.Hidden = True
Range("B:B,D:D,E:E,F:F,G:G,H:H,I:I,J:J,K:K,L:L,M:M,N:N,Q:Q,AB:AB,AF:AF,AG:AG,AH:AH,AI:AI,AJ:AJ").EntireColumn.Hidden = False
Application.ScreenUpdating = True
Unload UserForm5
End Sub
Replace
If LCase(Sheets("Database").Cells(i, 4)) = LCase(Client) Then
with
If LCase(Sheets("Database").Cells(i, 4)) = LCase(Client) Or InStr(LCase(Client), LCase(Sheets("DataBase"), Cells(i, 4))) > 0 Then

Excel VBA coping and pasting numerous shapes now erroring in Windows 10 but did not in 2016

I am a bit of a novice at VBA but have always found solutions from reading forums.
I now have an issue that I can't resolve, my company recently switched from Windows 2016 to Windows 10 (luckily at the moment I still have both laptops) but I am having issues with my code inconsistently erroring in a few Excel VBA tools I had developed in the old version.
My colleague also had this issue but managed to resolve his issue by disabling and enabling missing libraries.. I have tried this but not resolving.
The error..
Basically my tool "draws" a Gantt view of projects by copying and pasting shapes, resizing them and renaming them in specified cell locations.. previous version no issues at all took a few seconds.. Windows 10 is being completely inconsistent.. sometimes it will run with no issues (say 20% of the time) and then it will error at completely different areas of the code!
The error I get is "Run-time Error 1004 Paste method of Worksheet class failed"
I'm not sure why my code would run find in old Windows but not Windows 10.. but it maybe because my code is a bit rubbish and selecting the shapes and cells etc and it just can't cope sometimes?
Here is an example of the code I'm using, any advice would be appreciated:
Sub DrawDevelopment()
Dim rngData As Range
Set rngData = Sheets("Gantt Extract").Range("a4:a300")
For Each G In rngData
G_Address = G.Offset(0, 39).Value
G_size = G.Offset(0, 40).Value
G_Scheme = G.Offset(0, 1).Value
If G_Address <> "" Then
Sheets("Gantt").Shapes("Development").Select
Selection.Copy
Range(G_Address).Select
Sheets("Gantt").Paste
Selection.Name = "Delete" & (G_Scheme)
With Selection.ShapeRange
.Width = G_size
Selection.ShapeRange.IncrementTop 4
Selection.ShapeRange.ZOrder msoBringToFront
End With
End If
Next G
End Sub
Example of what overall code is drawing with shapes
While not specific to Windows 10, something might be causing an issue that is being exposed by the use of unqualified Select statements here.
I've tried re-writing it without the Select - but in order to test it I had to strip away the ShapeRange usage also before it would work with my shapes.
There might be a better way to reference the pasted shape, but I couldn't see one immediately so this does look a bit messy but works on my Win10 machine:
Sub DrawDevelopment()
Dim rngData As Range
Dim shtCopyFrom As Worksheet
Dim shtCopyTo As Worksheet
Set shtCopyFrom = Sheets("Gantt")
Set shtCopyTo = Sheets("Gantt Extract")
Set rngData = shtCopyTo.Range("a4:a300")
For Each g In rngData.Cells
G_Address = g.Offset(0, 39).Value
G_size = g.Offset(0, 40).Value
G_Scheme = g.Offset(0, 1).Value
If G_Address <> "" Then
shtCopyFrom.Shapes("Development").Copy
With shtCopyTo
.Paste
Set objShape = .Shapes(.Shapes.Count)
objShape.Name = "Delete" & (G_Scheme)
Set pasteCell = .Range(G_Address)
With objShape
.Width = G_size
.IncrementTop 4
.ZOrder msoBringToFront
.Left = pasteCell.Left
.Top = pasteCell.Top
End With
End With
End If
Next g
End Sub

Using VBA to Print Data From Excel to PDF

Seemingly very simple question but I have an excel spreadsheet that uses vba code to take a screenshot of something, pastes it into a 'Screenshot' tab and then exports that tab to a pdf. My issue is that the page break that I pass does not line up with the dotted page break line that seems to be produced by default(?)...
Section of Code:
Set Screen = Sheets("Screenshots")
Set Block = Sheets("BlockChart")
Set CopyRangeBlock = Block.Range("A1:N51")
Set PasteRange = Screen.Cells(1, 1)
Application.DisplayStatusBar = True
CopyRangeBlock.CopyPicture xlScreen, xlPicture
DoEvents
Screen.Paste Destination:=PasteRange
DoEvents
Sheets("Screenshots").Rows(52).PageBreak = xlPageBreakManual
Application.CutCopyMode = False
The range of the data to screenshot is from "A1:N:51" and therefore I place a page break at row 52. However, a dotted page break line appears (seemingly by default) at row 50. This screws up my export to pdf and produces blank pages. This is particularly an issue when I loop through the code to generate multiple pages in a pdf. How can I make it so that the dotted line either doesn't appear or matches with the page break that I set so that I'm not getting extra blank pages?
Example:
Just to reiterate the point, the whole worksheet has pre-determined dotted lines for the print area. I essentially want to modify these (via manual breaks or something) so that each page printed to a pdf is a custom size that fits the data I screenshot.
By following code you can paste some example ranges as screenshots to the destination worksheet, each with a manual page break between them.
I left 1 row blank before and after each screenshot (reason: when a border of a shape is directly placed at a page break, the border might be printed on the adjacent page too).
Please adapt the zoom level in the last code line, to get even the largest screenshot printed on 1 page (e. g. 54 %). If you want to get it calculated automatically, see the second code part of this answer.
Private Sub CollectScreenshots()
Dim wsSource As Worksheet, wsDestination As Worksheet
Dim rngExampleRanges As Range
Dim rngCopy As Range
Dim rowPaste As Long
Dim shpScreenshot As Shape
Dim dlg As Dialog
Application.DisplayStatusBar = True
Set wsSource = Sheets("BlockChart")
Set rngExampleRanges = wsSource.Range("A1:N51, A52:B53, C60:E99")
Set wsDestination = Sheets("Screenshots")
' Copy all ranges as screenshot into destination worksheet:
rowPaste = 1
With wsDestination
.ResetAllPageBreaks
For Each rngCopy In rngExampleRanges.Areas
rngCopy.CopyPicture Appearance:=xlScreen, Format:=xlPicture
DoEvents
If rowPaste > 1 Then .HPageBreaks.Add Before:=.Rows(rowPaste)
.Paste Destination:=.Cells(rowPaste + 1, 1), Link:=False
DoEvents
Set shpScreenshot = .Shapes(.Shapes.Count)
rowPaste = shpScreenshot.BottomRightCell.Row + 1
Next rngCopy
End With
Application.CutCopyMode = False
' set appropriate zoom level
wsDestination.PageSetup.Zoom = 54
End Sub
Automatic Zoom Level
If you want Excel to calculate the optimum zoom level, it is a bit more complicated.
If you have a cell range, e. g. A1:N51, which has to be printed on 1 page, then you can set the page dialog parameters manually like this:
define the print area as A1:N51
set scaling to 1 page width and 1 page height
Then you can visually see the calculated zoom level within the page setup dialog.
Unfortunately you can not read this zoom level directly via VBA, as Worksheet.PageSetup.Zoom in this case returns False only. If you urge Excel to use the zoom level, e. g. by setting FitToPagesWide to False, Excel calculates a new zoom level.
To read the calculated zoom level, you have to send a keyboard shortcut to the page setup dialog. To get the correct keyboard shortcut for that, please check within your page setup dialog, which shortcut is used for zoom level. In my German Excel version, it's Alt + V.
Then exchange the last line from above code by following:
' get cell dimensions of the largest screenshot:
Dim maxVerticalCells, maxHorizontalCells
For Each shpScreenshot In wsDestination.Shapes
maxVerticalCells = Application.WorksheetFunction.Max( _
maxVerticalCells, _
shpScreenshot.BottomRightCell.Row - shpScreenshot.TopLeftCell.Row + 1)
maxHorizontalCells = Application.WorksheetFunction.Max( _
maxHorizontalCells, _
shpScreenshot.BottomRightCell.Column - shpScreenshot.TopLeftCell.Column + 1)
Next shpScreenshot
' set appropriate zoom level
With wsDestination
' Simulate a print area with required dimensions to get it printed to 1 page
.PageSetup.Zoom = False
.PageSetup.FitToPagesWide = 1
.PageSetup.FitToPagesTall = 1
.PageSetup.PrintArea = _
.Range(.Cells(1, 1), .Cells(maxVerticalCells, maxHorizontalCells)).Address
' change the page setup to automatic and keep previous zoom level
' by sending keys to page setup dialog
.Activate
Dim strKeys As String
strKeys = "P" ' key "P" for first tab in that dialog
strKeys = strKeys & "%V" ' key <Alt>+<V> for automatic zoom (German, might be %A in other countries)
strKeys = strKeys & "~" ' key <Enter>
SendKeys strKeys ' send keys to following dialog
Application.Dialogs(xlDialogPageSetup).Show
Dim myZoomlevel As Double
myZoomlevel = .PageSetup.Zoom
' Reset print area, reset automatic page adaption, use previous zoom level
.PageSetup.PrintArea = ""
.PageSetup.FitToPagesWide = False
.PageSetup.FitToPagesTall = False
.PageSetup.Zoom = myZoomlevel
End With

Excel VBA Find Duplicates and post to different sheet

I keep having an issue with some code in VBA Excel was looking for some help!
I am trying to sort through a list of names with corresponding phone numbers, checking for multiple names under the same phone number. Then post those names to a separate sheet.
So far my code is:
Sub main()
Dim cName As New Collection
For Each celli In Columns(3).Cells
Sheets(2).Activate
On Error GoTo raa
If Not celli.Value = Empty Then
cName.Add Item:=celli.Row, Key:="" & celli.Value
End If
Next celli
On Error Resume Next
raa:
Sheets(3).Activate
Range("a1").Offset(celli.Row - 1, 0).Value = Range("a1").Offset(cName(celli.Value) - 1, 0).Value
Resume Next
End Sub
When I try to run the code it crashes Excel, and does not give any error codes.
Some things I've tried to fix the issue:
Shorted List of Items
Converted phone numbers to string using cstr()
Adjusted Range and offsets
I'm pretty new to all this, I only managed to get this far on the code with help from other posts on this site. Not sure where to go with this since it just crashes and gives me no error to look into. Any ideas are appreciated Thank you!
Updated:
Option Explicit
Dim output As Worksheet
Dim data As Worksheet
Dim hold As Object
Dim celli
Dim nextRow
Sub main()
Set output = Worksheets("phoneFlags")
Set data = Worksheets("filteredData")
Set hold = CreateObject("Scripting.Dictionary")
For Each celli In data.Columns(3).Cells
On Error GoTo raa
If Not IsEmpty(celli.Value) Then
hold.Add Item:=celli.Row, Key:="" & celli.Value
End If
Next celli
On Error Resume Next
raa:
nextRow = output.Range("A" & Rows.Count).End(xlUp).Row + 1
output.Range("A" & nextRow).Value = data.Range("A1").Offset(hold(celli.Value) - 1, 0).Value
'data.Range("B1").Offset(celli.Row - 1, 0).Value = Range("B1").Offset(hold
Resume Next
End Sub
Update2:
Used hold.Exists along with an ElseIf to remove the GoTo's. Also changed it to copy and paste the row to the next sheet.
Sub main()
Set output = Worksheets("phoneFlags")
Set data = Worksheets("filteredData")
Set hold = CreateObject("Scripting.Dictionary")
For Each celli In data.Columns(2).Cells
If Not hold.Exists(CStr(celli.Value)) Then
If Not IsEmpty(celli.Value) Then
hold.Add Item:=celli.Row, Key:="" & celli.Value
Else
End If
ElseIf hold.Exists(CStr(celli.Value)) Then
data.Rows(celli.Row).Copy (Sheets("phoneFlags").Cells(Rows.Count, 1).End(xlUp).Offset(1, 0))
'output.Range("A" & nextRow).Value = data.Range("A1").Offset(hold(celli.Value) - 1, 0).Value
End If
Next celli
End Sub
When developing code, don't try (or be afraid of) errors as they are pointers to help fix the code or the logic. As such, don't use On Error unless it is absolutely indicated in the coding algorithm (*). using On Error when not necessary only hides errors, does not fix them and when coding it is always better to avoid the errors in the first place (good logic).
When adding to the Dictionary, first check to see if the item already exists. The Microsoft documentation notes that trying to add an element that already exists causes an error. An advantage that the Dictionary object has over an ordinary Collection object in VBA is the .exists(value) method, which returns a Boolean.
The short answer to your question, now that I have the context out of the way, is that you can first check (if Not hold.exists(CStr(celli.Value)) Then) and then add if it does not already exist.
(*) As a side note, I was solving an Excel macro issue yesterday which took me most of the day to nut out, but the raising of errors and the use of debugging code helped me make some stable code rather than some buggy but kind-of-working code (which is what I was fixing in the first place). However, the use of error handling can be a short cut in some instances such as:
Function RangeExists(WS as Worksheet, NamedRange as String) As Boolean
Dim tResult as Boolean
Dim tRange as Range
tResult = False ' The default for declaring a Boolean is False, but I like to be explicit
On Error Goto SetResult ' the use of error means not using a loop through all the named ranges in the WS and can be quicker.
Set tRange = WS.Range(NamedRange) ' will error out if the named range does not exist
tResult = True
On Error Goto 0 ' Always good to explicitly limit where error hiding occurs, but not necessary in this example
SetResult:
RangeExists = tResult
End Function

Web Query from URL in Cell

I believe I have thoroughly researched this question (sorry if you have seen the answer, please be patient with me).
Truly a newcomer to VBA/Macros and do not even fully understand where to "put" the codes that are provided in these message boards, that is why I prefer a formula.
My sheet has cells which feed to a hyperlink (i.e. A1=JFK, B1:CVG, C1=HYPERLINK("http://www.gcmap.com/dist?p="&A1&"-"&B1,"My Flight").
If you visit the link (http://www.gcmap.com/dist?P=jfk-cvg) it shows the flying distance between these two points - 589 mi.
What I am trying to do is do a web query in Excel based off the link provided in cell C1, and then have the web query point to the total distance included in the link - and then populate another cell on my sheet (D1) with that distance.
Any and all help would be appreciated!
How's something like this:
Sub getMiles()
'Thanks to http://stackoverflow.com/questions/16975506/how-to-download-source-code-from-a-website-with-vba for idea
Dim k As Long, s
Dim URL2 As String
Dim ws As Worksheet, newWS As Worksheet
Set ws = ActiveSheet
Application.ScreenUpdating = False
URL2 = ws.Cells(1, 3) 'Cell C1 is the URL
' to get data from the url we need to creat a win Http object_
' tools > references > select Windows Win Http Services 5.1
Dim Http2 As New WinHttpRequest
'open the url
Http2.Open "GET", URL2, False
' send request
Http2.Send
'MsgBox Http2.ResponseText
Debug.Print s
'Debug.Print Http2
Debug.Print URL2
Dim Resp As String: Resp = Http2.ResponseText
Dim Lines2 As Variant: Lines2 = Split(Resp, ">")
Worksheets.Add after:=Sheets(Sheets.Count)
Set newWS = ActiveSheet
newWS.Name = "Temp for source code"
k = 0
For k = LBound(Lines2) To UBound(Lines2)
newWS.Cells(1 + k, 1).Value = Lines2(k)
k = k + 1
Next k
Dim findString As String, stringCell As Range
findString = " mi"
Set stringCell = newWS.Columns(1).Find(what:=findString)
Dim milesFlown As String
milesFlown = Left(stringCell.Value, WorksheetFunction.Search("&", stringCell, 1) - 1)
'MsgBox ("You would fly " & milesFlown)
ws.Cells(1, 4).Value = milesFlown
Application.DisplayAlerts = False
newWS.Delete
Application.DisplayAlerts = True
Application.ScreenUpdating = True
End Sub
It's sort of roundabout, but what it does is get the source code of your URL, and in that source code, look for a string that only seems to occur before the miles are given (" mi"), then finds the numbers to the left of the &, and sets that as your miles. You will need to tweak the macro to correctly point to the cell with your URL. Let me know if you need any help doing so!
edit: Ah, to use this code, with Excel open, press ALT+F11, this will open up the VB editor. I think you can insert this code (just copy/paste) into the "Sheet1 (Sheet1)" part. If not, you'll need to right click "VBAProject ([yourbook])" and Insert Module, and put the code there. It should then show up in your macro list (View tab --> Macros).
Edit2: Also, you'll need to add a Reference most likely in VBA. Press ALT+F1 to open VB Editor, then in Tools -> References, look for "Microsoft WinHTTP Services, version 5.1" and add a check mark, and click "Ok" to add this reference. Otherwise, you'll get an error.
Edit3: Updated the code. It now puts the source code on a new sheet, so anything you have in Col. A won't be deleted.

Resources