Error when calling custom function from subroutine in VBA - vba

I have a VBA script for Excel, that has a sub and a custom function. When I try to call the function from the sub, I get an error upon exiting the function.
Run-time error '424': Object required
I've tried several different things, but haven't had any luck. What do I need to do differently to make this work correctly? Thanks!
Public Sub FindValues()
Dim sh As Worksheet
Dim rn As Range
Dim RowCount As Integer
Dim currRow As Integer
Dim currValue As String
Dim firstRow As Boolean
Set sh = Worksheets("MetaData")
'for each row in Worksheets("MetaData")
For Each rn In sh.Rows
currRow = rn.Row
If (currRow = 1 And firstRow = False) Then
'Set flag
firstRow = True
ElseIf sh.Cells(rn.Row, 1).Value = "" Then
Exit For
Else
'get value from column A
currValue = sh.Cells(currRow, "A").Value
'search for value in column B & C in item relations spreadsheet
Dim FoundVal As Variant
Set FoundVal = FindItemRelations(currValue)
MsgBox ("String value found: " & vFound.Value & ", Column: " & vFound.Column)
MsgBox (FoundVal)
RowCount = RowCount + 1
End If
Next rn
End Sub
Public Function FindItemRelations(cv As String) As Variant
Dim found As Boolean
found = False
With Worksheets("ItemRelations")
Set rFoundB = .Columns("B").Find(What:=cv)
If Not rFoundB Is Nothing Then
'if value found in B, set value and exit
FindItemRelations = rFoundB
found = True
Else
'search column C for value
Set rFoundC = .Columns("C").Find(What:=cv)
'if value found in C, set value and exit
FindItemRelations = rFoundC
found = True
End If
If found = False Then
FindItemRelations = Nothing
'Exit Function
End If
End With
End Function

It seems that youre else statement always sets the found var to be true, even if rFoundB and rFoundC could not be found :
Else
'search column C for value
Set rFoundC = .Columns("C").Find(What:=cv)
'if value found in C, set value and exit
FindItemRelations = rFoundC
found = True
End If
This should do the trick :
Public Function FindItemRelations(cv As String) As Variant
Dim found As Boolean
found = False
With Worksheets("ItemRelations")
'search column B for value
Set rfoundb = .Columns("B").Find(What:=cv)
'search column C for value
Set rfoundc = .Columns("C").Find(What:=cv)
If Not rfoundb Is Nothing Then
'if value found in B, set value and exit
FindItemRelations = rfoundb
found = True
ElseIf Not rfoundc Is Nothing Then
'if value found in C, set value and exit
FindItemRelations = rfoundc
found = True
Else
FindItemRelations = "Not Found"
End If
End With
End Function

I've changed a few bits below to return a Range from FindItemRelations and using Set appropriately. Hope this is what you need.
Public Sub FindValues()
Dim sh As Worksheet
Dim rn As Range
Dim RowCount As Integer
Dim currRow As Integer
Dim currValue As String
Dim firstRow As Boolean
Set sh = Worksheets("MetaData")
'for each row in Worksheets("MetaData")
For Each rn In sh.Rows
currRow = rn.Row
If (currRow = 1 And firstRow = False) Then
'Set flag
firstRow = True
ElseIf sh.Cells(rn.Row, 1).Value = "" Then
Exit For
Else
'get value from column A
currValue = sh.Cells(currRow, "A").Value
'search for value in column B & C in item relations spreadsheet
Dim FoundVal As Variant
Set FoundVal = FindItemRelations(currValue)
If Not FoundVal Is Nothing Then
MsgBox ("String value found: " & FoundVal.Value & ", Column: " & FoundVal.Column)
End If
'MsgBox (FoundVal)
RowCount = RowCount + 1
End If
Next rn
End Sub
Public Function FindItemRelations(cv As String) As Range
Dim found As Boolean
found = False
Dim rFoundB, rFoundC As Range
With Worksheets("ItemRelations")
Set rFoundB = .Columns("B").Find(What:=cv)
If Not rFoundB Is Nothing Then
'if value found in B, set value and exit
Set FindItemRelations = rFoundB
found = True
Else
'search column C for value
Set rFoundC = .Columns("C").Find(What:=cv)
'if value found in C, set value and exit
Set FindItemRelations = rFoundC
found = True
End If
If found = False Then
FindItemRelations = Nothing
'Exit Function
End If
End With
End Function

Related

VBA Excel Object Defined Error in code for exporting data to different server

I am a self-taught VBA Excel user and I am having trouble with some code that I am editing from a previous author for my needs. This code is supposed to look at a certain range of cells in the same column and export them with the respective tag in the next column over.
I keep getting an object defined error on the 29th line of the following code:
Public oServer As PISDK.Server
Public Sub SaveDataToPI()
Dim wsCurrent As Worksheet
Dim rValue As Double
Dim RowIndex As Integer
Dim strPITagName As String
Dim dtCurrent As Date
Dim blnSavedData As Boolean
'Dim bwLab As Double
'Dim bwAct As Double
'Dim bwDif As Double
'Dim MoistureLab As Double
'Dim MoistureAct As Double
'Dim MoistureDif As Double
With Application
.Cursor = xlWait
.StatusBar = "Sending Data To PI...."
.ScreenUpdating = True
End With
Set wsCurrent = ActiveSheet
With wsCurrent
'first column of data
For RowIndex = 5 To 500
If Len(EntryScreen2.Cells(RowIndex, 3).Value) < 1 Then
Exit For
End If
' Blank out error messages in column 4 if there
EntryScreen2.Cells(RowIndex, 4).Value = ""
Next
End With
With wsCurrent
'first column of data
For RowIndex = 5 To 500
If Len(EntryScreen2.Cells(RowIndex, 3).Value) < 1 Then
Exit For
End If
If Len(EntryScreen2.Cells(RowIndex, 2).Value) > 0 And Len(EntryScreen2.Cells(RowIndex, 3).Value) > 0 Then
'Save Data To PI
dtCurrent = wsCurrent.Range(wsCurrent.Cells(2, 2), wsCurrent.Cells(2, 2)).Value
Call SavePIData(EntryScreen2.Cells(RowIndex, 3).Value, EntryScreen2.Cells(RowIndex, 2).Value, dtCurrent, RowIndex)
EntryScreen2.Cells(RowIndex, 2).Value = ""
blnSavedData = True
End If
Next
End With
If blnSavedData = True Then MsgBox "Data Saved to PI, Check Column D for Errors"
With Application
.Cursor = xlDefault
.StatusBar = "Ready...."
.ScreenUpdating = True
End With
End Sub
Public Function GetServer(szServer As String) As PISDK.Server
'Dim oServer As PISDK.Server
Dim oCon As Object
Set oServer = Servers(szServer)
On Error Resume Next
If oServer.Connected = False Then
oServer.Open
End If
On Error GoTo 0
If oServer.Connected = False Then
Set oCon = CreateObject("PISDKdlg.Connections")
On Error Resume Next
oCon.Login oServer, , , False
End If
Set GetServer = oServer
End Function
Public Sub SavePIData(strPITagName As String, dblValue As Double, dtCurrent As Date, RowIndex As Integer)
Dim oTag As PIPoint
'Dim oServer As Server
On Error GoTo Error
Set oServer = GetServer("pksfpi")
Set oTag = oServer.PIPoints(strPITagName)
'Send Data to database
oTag.Data.UpdateValue dblValue, dtCurrent
Set oTag = Nothing
Exit Sub
Error:
EntryScreen2.Cells(RowIndex, 4).Value = Err.Description
End Sub
Public Sub SaveEditedDataToPI(strPITagName As String, dtCurrent As Date, dblValue As Double)
Dim oTag As PIPoint
'Dim oServer As Server
On Error Resume Next
' strPITagName , dtCurrent, rValue
Set oServer = GetServer("pksfpi")
Set oTag = oServer.PIPoints(strPITagName)
'Send Data to database
oTag.Data.UpdateValue dblValue, dtCurrent, dmReplaceOnlyDuplicates
Set oTag = Nothing
End Sub
If you find anything else wrong in my code, feel free to let me know so that I don't run into anymore problems.
Thanks!!

Moving row from one workbook to another

I am new to StackOverflow, but have been working on this problem for some time, and am pretty stuck. Right now, my code takes 'Name' input from a textbox, and if the data in column A matches the name that was input, it copies data from the entire row in that sheet, copies it to another sheet, then deletes the data from the original sheet, and tells the user how many rows were moved. This code is listed below:
I have two problems. One, I need an error check where if the name that is typed into the textbox does not exist, it displays a messagebox with that message, and two, I need to allow for this code to do what it does, but from seperate workbooks. As in, copy the data from a sheet in one workbook, and move it to a sheet in another workbook. My code only works within the same workbook right now.
Any and all help is appreciated. Thank you in advance.
Private Sub buttonDelete_Click()
'When the Delete button is clicked, the following function is ran to copy the row from Current Services, move it to Cancelled Services
'and then delete the row from Current Services.
Dim wkBk1 As Workbook
Dim wkBk2 As Workbook
Dim xRg As Range
Dim xCell As Range
Dim I As Long
Dim J As Long
Dim K As Long
Dim count As Long
On Error Resume Next
Set wkBk1 = Workbooks.Open("C:\Users\Nathan\Desktop\Sandbox\testMacro.xlsm")
Set wkBk2 = Workbooks.Open("C:\Users\Nathan\Desktop\Sandbox\testMacro2.xlsm")
If Err.Number = 1004 Then
MsgBox "File Does Not Exist"
End If
I = wkBk1.Worksheets("Current Customers").UsedRange.Rows.count
J = Worksheets("Cancelled Services").UsedRange.Rows.count
count = 0
If J = 1 Then
If Application.WorksheetFunction.CountA(Worksheets("Cancelled Services").UsedRange) = 0 Then J = 0
End If
Set xRg = Worksheets("Current Customers").Range("A1:A" & I)
On Error Resume Next
Application.ScreenUpdating = False
For K = 1 To xRg.count
If CStr(xRg(K).Value) = Me.fName.Value Then
count = count + 1
xRg(K).EntireRow.Copy Destination:=Worksheets("Cancelled Services").Range("A" & J + 1)
xRg(K).EntireRow.Delete
If CStr(xRg(K).Value) = Me.fName.Value Then
K = K - 1
End If
J = J + 1
End If
Next
Application.ScreenUpdating = True
MsgBox count & " rows moved"
End Sub
EDIT : OK, here is one more wrinkle. What if I wanted to search through four or five different workbooks, and move all of the rows where the conditions are met into one worksheet called 'Cancelled Services' that will be a worksheet in one of the aforementioned workbooks.
There are a LOT of strange things going on in your code, so I've tried to clean it up a bit and left some comments as to why you shouldn't have some things in there. I've addressed the first part of your question, but in order to move rows between workbooks you need to decide what data you're looking to move and where, especially by fully qualifying your ranges using Workbook, or in your case, wkBk1 and wkBk2
Private Sub buttonDelete_Click()
'When the Delete button is clicked, the following function is ran to copy the row from Current Services, move it to Cancelled Services
'and then delete the row from Current Services.
Dim wkBk1 As Workbook, wkBk2 As Workbook
Dim xRg As Range, xCell As Range
Dim I As Long, J As Long, K As Long, count As Long
Dim MyName As String
'Assign our name value here
MyName = Me.fName.Value
'Let's use an error handler instead - this way our Err.Number will actually be triggered
On Error GoTo Handler
Set wkBk1 = Workbooks.Open("C:\Users\Nathan\Desktop\Sandbox\testMacro.xlsm")
Set wkBk2 = Workbooks.Open("C:\Users\Nathan\Desktop\Sandbox\testMacro2.xlsm")
On Error GoTo 0
I = wkBk1.Worksheets("Current Customers").UsedRange.Rows.count
J = Worksheets("Cancelled Services").UsedRange.Rows.count 'Need to add either wkBk1 or wkBk2 to the front of this
'We don't really NEED this, as count is initialized as 0 anyways
'count = 0
If J = 1 Then
'What is the purpose of this? Can it ever even return true if J = 1?
If Application.WorksheetFunction.CountA(Worksheets("Cancelled Services").UsedRange) = 0 Then J = 0
End If
Set xRg = Worksheets("Current Customers").Range("A1:A" & I) 'Need to add either wkBk1 or wkBk2 to the front of this
'Here we check the range for the name. If it's not there, we throw a messsage box and exit the sub
If Not WorksheetFunction.CountIf(xRg, MyName) > 0 Then
MsgBox "Name doesn't exist in the range"
Exit Sub
End If
'Got rid of On Error Resume Next, we don't need it and it's sloppy coding
Application.ScreenUpdating = False
'This whole snippet needs to be changed
'Also since you're deleting rows, you need to step BACKWARDS through this loop
For K = 1 To xRg.count
If CStr(xRg(K).Value) = MyName Then
xRg(K).EntireRow.Copy Destination:=Worksheets("Cancelled Services").Range("A" & J + 1)
xRg(K).EntireRow.Delete
'Why do we have this? We already know this is true?
'If CStr(xRg(K).Value) = MyName Then
K = K - 1
'End If
'Move count to AFTER we've actually moved the row, with On Error Resume Next your count could've gone up without a row being moved...
count = count + 1
J = J + 1
End If
Next
Application.ScreenUpdating = True
MsgBox count & " rows moved"
Handler:
If Err.Number = 1004 Then
MsgBox "File Does Not Exist"
End If
End Sub
This code uses FIND rather than looking at each row. It creates a range of all found rows as it goes and then copies the whole lot over in one hit before deleting the original values. Before ending it tells you how many it found.
This assumes that you have a textbox called fname and button called buttonDelete on a Userform.
Private Sub buttonDelete_Click()
Dim wrkBk1 As Workbook
Dim wrkBk2 As Workbook
Dim sPath As String
Dim wrkSht1 As Worksheet
Dim wrkSht2 As Worksheet
Dim rLastCell_Cur As Range
Dim rLastCell_Can As Range
Dim sNameToSearch As String
Dim rSearchRange As Range
Dim rFound As Range
Dim sFirstAddress As String
Dim lFoundCount As Long
Dim rFoundUnion As Range
sPath = "C:\Users\Nathan\Desktop\Sandbox\"
If Not (FileExists(sPath & "testMacro.xlsm") And FileExists(sPath & "testMacro2.xlsm")) Then
'One of the files doesn't exist so display message and exit.
MsgBox "One of the files does not exist.", vbOKOnly + vbCritical
Else
Set wrkBk1 = Workbooks.Open(sPath & "testMacro.xlsm")
Set wrkBk2 = Workbooks.Open(sPath & "testMacro2.xlsm")
If Not (WorkSheetExists("Current Customers", wrkBk1) And _
WorkSheetExists("Cancelled Services", wrkBk2)) Then
'One of the sheets doesn't exist so display message and exit.
MsgBox "One of the required sheets doesn't exist.", vbOKOnly + vbCritical
Else
'Find the limits of the two sheets.
Set wrkSht1 = wrkBk1.Worksheets("Current Customers")
Set rLastCell_Cur = LastCell(wrkSht1)
Set wrkSht2 = wrkBk2.Worksheets("Cancelled Services")
Set rLastCell_Can = LastCell(wrkSht2).Offset(1) 'We want the cell below the last cell here.
'Grab what we're searching for and where we're searching for it.
sNameToSearch = Me.fName
With wrkSht1
Set rSearchRange = .Range(.Cells(1, 1), .Cells(rLastCell_Cur.Row, 1))
End With
With rSearchRange
'Perform first search.
Set rFound = .Find(What:=sNameToSearch, LookIn:=xlValues, LookAt:=xlWhole, SearchDirection:=xlNext)
'If something was found then we're good to go.
If Not rFound Is Nothing Then
sFirstAddress = rFound.Address
Do
lFoundCount = lFoundCount + 1
'Create a union of ranges to copy over.
If rFoundUnion Is Nothing Then
Set rFoundUnion = rFound.EntireRow
Else
Set rFoundUnion = Union(rFoundUnion, rFound.EntireRow)
End If
'Look for the next item.
Set rFound = .FindNext(rFound)
Loop While rFound.Address <> sFirstAddress
'All instances have been found so copy it all over and then delete the original.
rFoundUnion.Copy wrkSht2.Cells(rLastCell_Can.Row, 1)
rFoundUnion.Delete Shift:=xlUp
End If
MsgBox "Found " & lFoundCount & " occurrences of " & sNameToSearch, vbOKOnly + vbInformation
End With
End If
End If
End Sub
Public Function FileExists(FilePath As String) As Boolean
FileExists = Dir(FilePath) <> ""
End Function
Public Function WorkSheetExists(SheetName As String, Optional WrkBk As Workbook) As Boolean
Dim wrkSht As Worksheet
If WrkBk Is Nothing Then
Set WrkBk = ThisWorkbook
End If
On Error Resume Next
Set wrkSht = WrkBk.Worksheets(SheetName)
WorkSheetExists = (Err.Number = 0)
Set wrkSht = Nothing
On Error GoTo 0
End Function
Public Function LastCell(wrkSht As Worksheet, Optional Col As Long = 0) As Range
Dim lLastCol As Long, lLastRow As Long
On Error Resume Next
With wrkSht
If Col = 0 Then
lLastCol = .Cells.Find("*", , , , xlByColumns, xlPrevious).Column
lLastRow = .Cells.Find("*", , , , xlByRows, xlPrevious).Row
Else
lLastCol = .Cells.Find("*", , , , xlByColumns, xlPrevious).Column
lLastRow = .Columns(Col).Find("*", , , , xlByColumns, xlPrevious).Row
End If
If lLastCol = 0 Then lLastCol = 1
If lLastRow = 0 Then lLastRow = 1
Set LastCell = wrkSht.Cells(lLastRow, lLastCol)
End With
On Error GoTo 0
End Function
This update to the buttonDelete_Click() procedure will open all Excel files within a specific folder and copy the found name to another file that isn't in that folder.
Private Sub buttonDelete_Click()
Dim colFiles As Collection
Dim vFile As Variant
Dim sTemp As String
Dim wrkBk1 As Workbook
Dim wrkBk2 As Workbook
Dim sPath As String
Dim wrkSht1 As Worksheet
Dim wrkSht2 As Worksheet
Dim rLastCell_Cur As Range
Dim rLastCell_Can As Range
Dim sNameToSearch As String
Dim rSearchRange As Range
Dim rFound As Range
Dim sFirstAddress As String
Dim lFoundCount As Long
Dim rFoundUnion As Range
sPath = "C:\Users\Nathan\Desktop\Sandbox\"
'Put the full path of each Excel file in to a collection.
'These contain the "Current Customers" sheet.
Set colFiles = New Collection
sTemp = Dir$(sPath & "*.xls*")
Do While Len(sTemp) > 0
colFiles.Add sPath & sTemp
sTemp = Dir$
Loop
If Not (FileExists("C:\Users\Nathan\Desktop\Cancelled.xlsx")) Then
'Cancelled Services book doesn't exist.
MsgBox "Cancelled Services doesn't exist.", vbOKOnly + vbCritical
Else
'Open Cancelled Services before working through the collection of Current Customers.
Set wrkBk2 = Workbooks.Open("C:\Users\Nathan\Desktop\Cancelled.xlsx")
Set wrkSht2 = wrkBk2.Worksheets("Cancelled Services")
For Each vFile In colFiles
Set wrkBk1 = Workbooks.Open(vFile)
'The file will only be processed if it contains "Current Customers" sheet.
If WorkSheetExists("Current Customers", wrkBk1) Then
Set wrkSht1 = wrkBk1.Worksheets("Current Customers")
Set rLastCell_Can = LastCell(wrkSht2).Offset(1)
Set rLastCell_Cur = LastCell(wrkSht1)
'Grab what we're searching for and where we're searching for it.
sNameToSearch = Me.fName
With wrkSht1
Set rSearchRange = .Range(.Cells(1, 1), .Cells(rLastCell_Cur.Row, 1))
End With
With rSearchRange
'Perform first search.
Set rFound = .Find(What:=sNameToSearch, LookIn:=xlValues, LookAt:=xlWhole, SearchDirection:=xlNext)
'If something was found then we're good to go.
If Not rFound Is Nothing Then
sFirstAddress = rFound.Address
Do
lFoundCount = lFoundCount + 1
'Create a union of ranges to copy over.
If rFoundUnion Is Nothing Then
Set rFoundUnion = rFound.EntireRow
Else
Set rFoundUnion = Union(rFoundUnion, rFound.EntireRow)
End If
'Look for the next item.
Set rFound = .FindNext(rFound)
Loop While rFound.Address <> sFirstAddress
'All instances have been found so copy it all over and then delete the original.
rFoundUnion.Copy wrkSht2.Cells(rLastCell_Can.Row, 1)
rFoundUnion.Delete Shift:=xlUp
End If
End With
End If
Set rFound = Nothing
Set rFoundUnion = Nothing
sFirstAddress = ""
wrkBk1.Close SaveChanges:=True
Next vFile
MsgBox "Found " & lFoundCount & " occurrences of " & sNameToSearch, vbOKOnly + vbInformation
End If
End Sub
To answer the first question about checking if a sheet exist in a workbook, you can use a Function like this:
Public Function U_W_DoesWorksheetExist(ByVal sheetname As String, aWorkbook As Workbook) As Boolean
On Error Resume Next
U_W_DoesWorksheetExist = (Not aWorkbook.Sheets(sheetname) Is Nothing)
On Error GoTo 0
End Function
Now, when you reference the destination, you are saying just Worksheets("Cancelled Services") and the Macro will assume the ActiveWorkook as the main workbook where to copy the Sheet. You need to reference the Workbook where the sheet you are pasting is located. See if the code below works for you and take a look at the comments I added on it:
Private Sub buttonDelete_Click()
'When the Delete button is clicked, the following function is ran to copy the row from Current Services, move it to Cancelled Services
'and then delete the row from Current Services.
Dim wkBk1 As Workbook
Dim wkBk2 As Workbook
Dim xRg As Range
Dim xCell As Range
Dim i As Long
Dim J As Long
Dim K As Long
Dim count As Long
Dim arrFromWorkbookPath(1 To 4) As String
Dim c As Long
' If you need more than 4 rearrange the Array to as many as you need.
arrFromWorkbookPath(1) = "C:\Users\Nathan\Desktop\Sandbox\FromWB1.xlsm"
arrFromWorkbookPath(4) = "C:\Users\Nathan\Desktop\Sandbox\FromWB2.xlsm"
arrFromWorkbookPath(3) = "C:\Users\Nathan\Desktop\Sandbox\FromWB3.xlsm"
arrFromWorkbookPath(4) = "C:\Users\Nathan\Desktop\Sandbox\FromWB4.xlsm"
' The Workbook were you will be pasting the sheets.
Set wkBk2 = Workbooks.Open("C:\Users\Nathan\Desktop\Sandbox\testMacro2.xlsm")
For c = LBound(arrFromWorkbookPath) To UBound(arrFromWorkbookPath)
On Error Resume Next
' Open the Workbook from where the sheet will be copied from.
Set wkBk1 = Workbooks.Open(arrFromWorkbookPath(c))
If Err.Number = 1004 Then
MsgBox "File Does Not Exist"
Exit Sub
End If
' USE PROCEDURE LIKE THIS TO CHECK "Current Customers" in wkBk1 and Cancelled Services in wkBk2.
If U_W_DoesWorksheetExist("Current Customers", wkBk1) And U_W_DoesWorksheetExist("Cancelled Services", wkBk1) Then
i = wkBk1.Worksheets("Current Customers").UsedRange.Rows.count
J = wkBk2.Worksheets("Cancelled Services").UsedRange.Rows.count
count = 0
If J = 1 Then
If Application.WorksheetFunction.CountA(wkBk2.Worksheets("Cancelled Services").UsedRange) = 0 Then J = 0
End If
Set xRg = wkBk1.Worksheets("Current Customers").Range("A1:A" & i)
On Error Resume Next
Application.ScreenUpdating = False
For K = 1 To xRg.count
If CStr(xRg(K).Value) = Me.fName.Value Then
count = count + 1
' Here you need to specify the workbook, not just the sheet wkBk2.Worksheets("Cancelled Services").
xRg(K).EntireRow.Copy Destination:=wkBk2.Worksheets("Cancelled Services").Range("A" & J + 1)
xRg(K).EntireRow.Delete
If CStr(xRg(K).Value) = Me.fName.Value Then
K = K - 1
End If
J = J + 1
End If
Next
wkBk1.Close False
Else
' Display error if the sheet doesn't exist.
MsgBox "Sheets Current Customers or Cancelled Services don't exists."
End If
Next c
Application.ScreenUpdating = True
End Sub

Putting images onto an excel sheet via URL links

My sheet has three columns, "A" = Images, "B" = Image Names, and "C" = URL Links, with Rows 1 and 2 being used as headers and rows 3 to 1002 for user input. The Current working code will search for the image names in Column "B" in the folder you select, and inserts them into Column "A". This macro runs off of a commandbutton I have placed on a userform I have created.
Working code is as follows (this is a edited version of the accepted answer here):
Private Sub Add_Images_Click()
Const EXIT_TEXT As String = ""
Const NO_PICTURE_FOUND As String = "No picture found"
Dim picName As String
Dim picFullName As String
Dim rowIndex As Long
Dim lastRow As Long
Dim selectedFolder As String
Dim data() As Variant
Dim wks As Worksheet
Dim Cell As Range
Dim pic As Picture
On Error GoTo ErrorHandler
selectedFolder = GetFolder
If Len(selectedFolder) = 0 Then GoTo ExitRoutine
Application.ScreenUpdating = False
Set wks = ActiveSheet
lastRow = wks.Cells(2, "B").End(xlDown).Row
data = wks.Range(wks.Cells(3, "B"), wks.Cells(lastRow, "B")).Value2
For rowIndex = 3 To UBound(data, 1)
If StrComp(data(rowIndex, 1), EXIT_TEXT, vbTextCompare) = 0 Then GoTo ExitRoutine
picName = data(rowIndex, 1)
picFullName = selectedFolder & picName
If Len(Dir(picFullName)) > 0 Then
Set Cell = wks.Cells(rowIndex, "A")
Set pic = wks.Pictures.Insert(picFullName)
With pic
.ShapeRange.LockAspectRatio = msoFalse
.Height = Cell.Height
.Width = Cell.Width
.Top = Cell.Top
.Left = Cell.Left
.Placement = xlMoveAndSize
End With
Else
wks.Cells(rowIndex, "A").Value = NO_PICTURE_FOUND
End If
Next rowIndex
ExitRoutine:
Set wks = Nothing
Set pic = Nothing
Application.ScreenUpdating = True
UserForm.Hide
Exit Sub
ErrorHandler:
MsgBox Prompt:="Unable to find photo", _
Title:="An error occured", _
Buttons:=vbExclamation
Resume ExitRoutine
End Sub
Private Function GetFolder() As String
Dim selectedFolder As String
With Application.FileDialog(msoFileDialogFolderPicker)
.InitialFileName = Application.DefaultFilePath & "\"
.Title = "Select the folder containing the Image/PDF files."
.Show
If .SelectedItems.count > 0 Then
selectedFolder = .SelectedItems(1)
If Right$(selectedFolder, 1) <> Application.PathSeparator Then _
selectedFolder = selectedFolder & Application.PathSeparator
End If
End With
GetFolder = selectedFolder
End Function
I'm looking for a way to edit this macro so that it would be able to use the URL links for the images in Column "C" and find and insert the images into Column "A" that way. I found a working code (can't remember where, or I'd link it) that I tried to adapt with my current code to achieve the desired results.
The sample code I found online:
Sub Images_Via_URL()
Dim url_column As Range
Dim image_column As Range
Set url_column = Worksheets(1).UsedRange.Columns("A")
Set image_column = Worksheets(1).UsedRange.Columns("B")
Dim i As Long
For i = 2 To url_column.Cells.Count
With image_column.Worksheet.Pictures.Insert(url_column.Cells(i).Value)
.Left = image_column.Cells(i).Left
.Top = image_column.Cells(i).Top
.Height = 100
.Width = 100
End With
Next
End Sub
The following code is my failed attempt to edit it myself. It worked once for a list of 7 URL links, then I deleted one of the links in the middle to see if it would handle the blank cell correctly, and now it flat out wont work. It goes into the "ExitRoutine" every time.
Not Working Code:
Option Explicit
Private Sub URL_Images_Click()
Const EXIT_TEXT As String = ""
Const NO_PICTURE_FOUND As String = "No picture found"
Dim picURL As String
Dim rowIndex As Long
Dim lastRow As Long
Dim data() As Variant
Dim wks As Worksheet
Dim Cell As Range
Dim pic As Picture
On Error GoTo ErrorHandler
Application.ScreenUpdating = False
Set wks = ActiveSheet
lastRow = wks.Cells(2, "B").End(xlDown).Row
data = wks.Range(wks.Cells(3, "C"), wks.Cells(lastRow, "C")).Value2
For rowIndex = 3 To UBound(data, 1)
**If StrComp(data(rowIndex, 1), EXIT_TEXT, vbTextCompare) = 0 Then GoTo ExitRoutine**
picURL = data(rowIndex, 1)
If Len(picURL) > 0 Then
Set Cell = wks.Cells(rowIndex, "A")
Set pic = wks.Pictures.Insert(picURL)
With pic
.ShapeRange.LockAspectRatio = msoFalse
.Height = Cell.Height
.Width = Cell.Width
.Top = Cell.Top
.Left = Cell.Left
.Placement = xlMoveAndSize
End With
Else
wks.Cells(rowIndex, "A").Value = NO_PICTURE_FOUND
End If
Next rowIndex
ExitRoutine:
Set wks = Nothing
Set pic = Nothing
Application.ScreenUpdating = True
UserForm.Hide
Exit Sub
ErrorHandler:
MsgBox Prompt:="Unable to find photo", _
Title:="An error occured", _
Buttons:=vbExclamation
Resume ExitRoutine
End Sub
I've bolded the line that is forcing it to the "ExitRoutine". I'm not sure how exactly that line works as I am not the one who originally wrote it. Any help would be great!
lastRow = wks.Cells(2, "B").End(xlDown).Row
data = wks.Range(wks.Cells(3, "C"), wks.Cells(lastRow, "C")).Value2
For rowIndex = 3 To UBound(data, 1)
'....
If you start at rowIndex = 3 then you're skipping the first two rows of your input data: a 2-D array from a range always has lower bounds of 1 for both dimensions, regardless of the location of the range.
In this case data(1,1) will correspond to C3, whereas data(3,1) is C5

MS word vba - find text and associated headings

Here is some working code in case anyone needs it.
The key word is found using the range.find function, once found the absolute line number is found. Then the selection function scrolls up line by line to find heading levels 1 and 2. The results are stored in array and pasted onto an excel spreadsheet once complete.
If anyone has a more elegant method please let me know.
'===================================================
'FIND KEY WORD AND ASSOCIATED LEVEL 1 AND 2 HEADINGS
'===================================================
Sub FIND_HDNG_2()
Dim SENTENCE As String
Dim hdng1name As String, hdng1No As String, hdng2name As String, hdng2No As String
Dim aRange As Range, Style_Range As Range
Dim CurPage As Integer, CurPage2 As Integer, CurPage3 As Integer
Dim hdng_STYLE As String
Dim LineNo As Integer, Hdng_LineNo As Integer
Dim SELECTION_PG_NO As Integer, RANGE_PG_NO As Integer
Dim HDNG_TXT As String
Dim ARRY(200, 5) As String
Dim COUNT As Integer
Dim HDNG1_FLAG As Boolean, HDNG2_FLAG As Boolean
Dim LINESUP As Integer
On Error Resume Next
COUNT = 1
Set aRange = ActiveDocument.Range
Do
aRange.Find.Text = "must" ' the KEY WORD I am looking for
aRange.Find.Execute Forward:=True
If aRange.Find.Found Then
'extract sentence
LineNo = GetAbsoluteLineNum(aRange)
RANGE_PG_NO = aRange.Information(wdActiveEndPageNumber)
aRange.Expand Unit:=wdSentence
aRange.Copy
SENTENCE = aRange.Text
aRange.Collapse wdCollapseEnd
'find heading name and number
Selection.GoTo What:=wdGoToLine, Which:=wdGoToAbsolute, COUNT:=LineNo 'go to line no of the range
LINESUP = 0
Do
LINESUP = LINESUP + 1
Selection.MoveUp Unit:=wdLine, COUNT:=1
Selection.HomeKey Unit:=wdLine
Selection.EndKey Unit:=wdLine, Extend:=wdExtend
HDNG_TXT = Selection.Text
'reached first page without finding heading
SELECTION_PG_NO = Selection.Information(wdActiveEndPageNumber)
If SELECTION_PG_NO = 1 Then 'exit if on first page
hdng2No = "BLANK"
hdng2name = "BLANK"
Exit Do
End If
hdng_STYLE = Selection.STYLE
If hdng_STYLE = "Heading 1,Heading GHS" And HDNG1_FLAG = False Then
hdng1No = Selection.Paragraphs(1).Range.ListFormat.ListString
hdng1name = Selection.Sentences(1)
HDNG1_FLAG = True
Exit Do
End If
If hdng_STYLE = "Heading 2" And HDNG2_FLAG = False Then
hdng2No = Selection.Paragraphs(1).Range.ListFormat.ListString
hdng2name = Selection.Sentences(1)
HDNG2_FLAG = True
End If
Loop
End If
HDNG1_FLAG = False
HDNG2_FLAG = False
ARRY(COUNT, 1) = hdng1No
ARRY(COUNT, 2) = hdng1name
ARRY(COUNT, 3) = hdng2No
ARRY(COUNT, 4) = hdng2name
ARRY(COUNT, 5) = SENTENCE
COUNT = COUNT + 1
Loop While aRange.Find.Found
Call PASTE_RESULT_EXCEL(ARRY)
End Sub
'===================================================
'PASTE RESULTS TO EXCEL
'===================================================
Sub PASTE_RESULT_EXCEL(ByRef ARY() As String)
Dim appExcel As Object
Dim wb As Object
Dim ws As Object
Dim min As String
Dim filename As String
Dim X As Integer, Y As Integer
filename = "DOC_NAME"
Set appExcel = CreateObject("Excel.Application")
With appExcel
.Visible = True
Set wb = .Workbooks.Add
min = CStr(Minute(Now()))
wb.SaveAs "D:\IPL\" + filename + "--" + min + ".xlsx"
Set ws = wb.Worksheets(1)
For X = 1 To 200
For Y = 1 To 5
ws.Cells(X + 5, Y).Value2 = ARY(X, Y)
Next Y
Next X
Set ws = Nothing
Set wb = Nothing
Set appExcel = Nothing
End With
End Sub
'===================================================
'FIND ABSOLUTE LINE NUMBER OF KEY WORD
'===================================================
Function GetAbsoluteLineNum(r As Range) As Integer
Dim i1 As Integer, i2 As Integer, COUNTER As Integer, rTemp As Range
r.Select
Do
i1 = Selection.Information(wdFirstCharacterLineNumber)
Selection.GoTo What:=wdGoToLine, Which:=wdGoToPrevious, COUNT:=1, Name:=""
COUNTER = COUNTER + 1
i2 = Selection.Information(wdFirstCharacterLineNumber)
Loop Until i1 = i2
r.Select
GetAbsoluteLineNum = COUNTER
End Function

Correct order of mulitple if statements in vba

I need this macro to hide certain columns when the value of $A$5 is equal to "Company 2". The query below hides the columns successfully but doesn't executed the print loop. What's the correct way to set this up?
Sub PrintAll()
Dim BrokerCell As Range
Dim TotalCell As Range
Dim Rng As Range
Dim Wks As Worksheet
Set Wks = Worksheets("PRINT PAGE")
If Range("$A$5").Value = "Company 1" Then
Set Rng = ThisWorkbook.Names("Company1").RefersToRange
ElseIf Range("$A$5").Value = "Company 2" Then
Set Rng = ThisWorkbook.Names("Company2").RefersToRange
Else: Set Rng = ThisWorkbook.Names("Company3").RefersToRange
End If
If Range("$A$5").Value = "Company 2" Then
Columns("M:O").Select
Selection.EntireColumn.Hidden = True
Else: Columns("M:O").Select
Selection.EntireColumn.Hidden = False
For Each BrokerCell In Rng
If BrokerCell <> "" And Range("$S$5").Value <> "" Then
Wks.Range("$B$5").Value = BrokerCell.Text
Wks.PrintOut
End If
Next BrokerCell
End If
End Sub
Your For Each loop is contained within the Else portion of the If Range("$A$5").Value = "Company 2" Then statement. It will only execute when that If statement evaluates to false.
If you need your For Each loop to execute in all instances, then move it after the End If. If you need it to execute only when the If statement evaluates to True, then move it before the Else.
I believe this is what oyu are looking to accomplish, see below.
Sub PrintAll()
Dim BrokerCell As Range
Dim TotalCell As Range
Dim Rng As Range
Dim Wks As Worksheet
Dim sCellValue As String
Set Wks = Worksheets("PRINT PAGE")
sCellValue = Replace(Range("$A$5").Value, " ", "")
If sCellValue = "Company1" Then
Set Rng = ThisWorkbook.Names(sCellValue ).RefersToRange
ElseIf sCellValue = "Company2" Then
Set Rng = ThisWorkbook.Names(sCellValue ).RefersToRange
Else
Set Rng = ThisWorkbook.Names("Company3").RefersToRange
End If
Columns("M:O").Select
If sCellValue = "Company2" Then
Selection.EntireColumn.Hidden = True
Else
Selection.EntireColumn.Hidden = False
End If
For Each BrokerCell In Rng
If BrokerCell <> "" And Range("$S$5").Value <> "" Then
Wks.Range("$B$5").Value = BrokerCell.Text
Wks.PrintOut
End If
Next BrokerCell
End Sub