Why am I getting "run-time error '424': object required" using VBA in Excel? - vba

I'm having an issue with some code I'm writing in VBA. I'm getting this error, but I don't think I'm using it wrong, since I wrote something very similar in another sub.
Sub quicktest()
Dim testrng As Range
Set testrng = Sheet5.Range("J81")
AddNewRecordsColumn testrng
End Sub
Sub AddNewRecordsColumn(bottomcell As Range)
Dim copyrng, pasterng As Range
Set copyrng = Sheet5.Range(Sheet5.Range("E3"), bottomcell)
Set pasterng = Sheet5.Range(Sheet5.Range("D3"), bottomcell)
pasterng.Value = copyrange.Value 'this is the line highlighted by debugger
End Sub
Any help would be greatly appreciated!

On the last line, the one highlighted, copyrange does not exist. copyrng does, small difference.

Dim copyrng, pasterng As Range
Because a data type hasn't been specified for copyrng it is a variant. For Variants use Value2 or make copyrng a range.
From Help for Dim
type Optional. Data type of the variable; may be Byte, Boolean, Integer, Long, Currency, Single, Double, Decimal (not currently supported), Date, String (for variable-length strings), String * length (for fixed-length strings), Object, Variant, a user-defined type, or an object type. Use a separate As type clause for each variable you declare.

Related

Passing 2 range variables to a Sub - Object required/ByRef argument Type mismatch error

I am trying to copy range from 1 worksheet with conditional formatting rules and paste in another workbook using the exact formatting but deleting the conditional rules.
I am passing 2 range objects to my sub and when calling the macro I am getting the error. Please help me.
Sub Create()
Dim rgFrom, rgTo As Range
oldBook = ActiveWorkbook.Name
Workbooks.Add
Set rgFrom = Workbooks("Daily Flow Template.xlsm").Worksheets("DailyFlow").Range("A1:BZ110")
Set rgTo = ActiveWorkbook.Worksheets("Sheet1").Range("A1:BZ110")
PasteFormattedRange (rgFrom), rgTo ----- Error Object Required
End Sub
Sub PasteFormattedRange(ByRef rgFrom As Range, ByRef rgTo As Range)
Dim S As String
Dim rgStart As Range
Dim i As Long, CF_Format As Long
Dim SaveDisplayAlerts As Boolean, SaveScreenUpdating As Boolean
Dim HTMLInClipBoard As Boolean
Dim Handle As Long, Ptr As Long, FileName As String
Set rgStart = Selection
rgFrom.Copy
'Enumerate the clipboard formats
If OpenClipboard(0) Then
CF_Format = EnumClipboardFormats(0&)
Do While CF_Format <> 0
S = String(255, vbNullChar)
i = GetClipboardFormatName(CF_Format, S, 255)
S = Left(S, i)
HTMLInClipBoard = InStr(1, S, "HTML Format", vbTextCompare) > 0
If HTMLInClipBoard Then
Application.CutCopyMode = False
Application.Goto rgTo
ActiveSheet.PasteSpecial Format:="HTML"
Application.Goto rgStart
Exit Do
End If
CF_Format = EnumClipboardFormats(CF_Format)
Loop
CloseClipboard
End If
End Sub
ByRef argument type mismatch
This answer from "ByRef argument type mismatch in Excel VBA" might help explain this error a bit clearer than I can.
The basic gist of it is:
Unless you need to, pass arguments ByVal instead of ByRef.
If you use ByRef make sure to declare your statements explicitly rather than delcaring with the default data type (Variant) that way you will be passing a Range where a Range is expected.
This answer on my question on CodeReview also touches on passing arguments ByVal opposed to ByRef.
Object required (Error 424)
If you are not returning a value, you don't need to include parentheses ( ) - You can read about it on Using parentheses in code(VBA).
The below edit to your problem line will execute without the Object Required error:
PasteFormattedRange rgFrom, rgTo
When using parentheses for a Sub, Function or any other Method or Property, you would need to encapsulate all arguments within the parentheses rather than just one if the parentheses are actually required.
If you are assigning a value, you would need the parentheses, like so:
Sub Foo()
x = MyFunction(Argument1, Argument2)
End Sub
If you are not assigning a value, you don't include the parentheses, like so:
Sub Foo()
MySub Argument1, Argument2
End Sub

Passing two Ranges as a parameters and executing though excel sheet

I am trying to make a function that pass two range as a parameters, the code look something like this:
Function WhatEverFunction(range1 As Range, range2 As Range) As Integer
Dim column As ingeter
column = range1.Column
'make some stuff with the column
WhatEverFunction = range1.Value + range2.Value
End Function
This is how I execute the code and pass the parameters:
But this is the result:
Here are some of those corrections. Also, you are really just doing SUM so maybe consider the following:
Public Function WhatEverFunction(ByVal range1 As Range, ByVal range2 As Range) As Long
Dim myColumn As Long
myColumn = range1.column
'make some stuff with the column
WhatEverFunction = Application.WorksheetFunction.Sum(range1, range2)
End Function
Note #john Coleman's comment about what a udf cannot do. To be explicit, a UDF returns something to the cell it is placed in.
And your local settings might require WhatEverFunction = Application.WorksheetFunction.Sum(range1; range2)

How to fix late binding error in the function I have to find last row in an Excel column?

I have a function to find last row in a specific column in excel.
Below is the code
Private Function FindLastRowInColumn(ByVal XlWorkSheet As Excel.Worksheet, ByVal ColumnName As String) As Long
Dim LastRow As Long
With XlWorkSheet
LastRow = .Cells(.Rows.Count, ColumnName).End(Excel.XlDirection.xlUp).Row
End With
Return LastRow
End Function
I am getting error on the line
LastRow = .Cells(.Rows.Count, ColumnName).End(Excel.XlDirection.xlUp).Row
Error: Option Strict On disallows late binding.
How can I fix this error without turning off Option Strict?
I managed to fix the issue with the recommendations from jmcilhinney.
Below is the code that worked for me.
Public Function FindLastRowInColumn(ByVal XlWorkSheet As Excel.Worksheet, ByVal ColumnName As String) As Long
Dim LastRow As Long
With XlWorkSheet
LastRow = CType(.Cells(.Rows.Count, ColumnName), Excel.Range).End(Excel.XlDirection.xlUp).Row
End With
Return LastRow
End Function
First determine which member is late-bound. That's easy by simply typing the line out again and noting which member is not suggested by Intellisense. You will then need to determine what type the member belongs to and, assuming that it's possible, cast your reference to the object as that type. For instance, this is late binding:
Dim obj As Object = "Hello World"
Dim length As Integer = obj.Length
obj is an Object reference and Length is not a member of type Object. It is a member of type String though, and the object referred to by obj is a String so it can be cast as that type to achieve early binding:
Dim obj As Object = "Hello World"
Dim length As Integer = CStr(obj).Length
Maybe writing
Option Strict Off
at the very beginning of the file? (before imports)

VBA Excel: How to pass one parameter of different types to a function (or cast Int/String to Range)?

I'm writing some VBA functions in Excel that compute word values and cross sums of the input.
I'm passing the input as Public Function cross_sum(myRange As Range) As Integer to them so that they take cell references as input, e.g. =cross_sum(A1). Works fine.
However when I try to chain two functions like =cross_sum(word_value(A1)) I run into th VALUE error because word_value() returns an Integer value and not the Range cross_sum() is set to expect. However I did not find a way to cast an Integer (or String) into a Range.
As Excel's built-in functions support chaining as well as Range input I wonder how.
Unfortunately this is my first VBA project so I wonder if and how to cast or what type to choose to get this working both ways.
Any pointers appreciated!
TIA,
JBQ
You can pass Variant to a function and the function can determine the type of input:
Public Function Inputs(v As Variant) As String
If TypeName(v) = "Range" Then
MsgBox "you gave me a range"
Else
MsgBox "you gave me a string"
End If
Inputs = "done"
End Function
Sub MAIN()
Dim st As String
Dim rng As Range
st = "A1"
Set rng = Range(st)
x = Inputs(st)
x = Inputs(rng)
End Sub
Without your code, it is hard to know what you could change. That being said...
There is not a way to convert an integer to a range. You would have to create a function to do so if that is what you desired.
You could create a converter function, maybe titled IntegerToRange, that takes an integer and after some logic (maybe 1 = "A1", 2 = "A2" or something), will return a range. Your cell formula would then be =cross_sum(IntegerToRange(word_value(A1))
Alternatively, you could modify your word_value function to return a range instead of an integer. Your cell formula would then be =cross_sum(word_value(A1).

How to convert a String to a Range Object

Is there anyway to convert a string value to a Range object ? I'm having a function which takes a Range object as a argument and need to pass a single string parameter to it
Thank You
A string with a cell address? if so:
Dim r As Range: Set r = Range("B3")
MsgBox r.ColumnWidth
I don't like this one bit, but if you can't change the function that requires a range, you could create a function that converts a string to a range. You'd want to be sure that the only thing the first function cares about is the Value or Text properties.
Function FuncThatTakesRange(rng As Range)
FuncThatTakesRange = rng.Value
End Function
Function ConvertStringToRange(sInput As String) As Range
Dim ws As Worksheet
Set ws = Workbooks.Add.Sheets(1)
ws.Range("A1").Value = sInput
Set ConvertStringToRange = ws.Range("A1")
Application.OnTime Now + TimeSerial(0, 0, 1), "'CloseWB """ & ws.Parent.Name & """'"
End Function
Sub CloseWb(sWb As String)
On Error Resume Next
Workbooks(sWb).Close False
End Sub
Use in the Immediate Window like
?functhattakesrange(convertstringtorange("Myvalue"))
Here is my solution that involves no need for a new function.
1.Make dynamic string variable first
2.Then finalize it by creating a range object out of this string via a range method: Set dynamicrange= range (dynamicstring)
You can manipulate dynamicstring as you want to, I just kept it simple so that you can see that you can make range out of a string variable.
Sub test()
Dim dynamicrangecopystring As String
Dim dynamicrangecopy As range
dynamicrangecopystring = "B12:Q12"
Set dynamicrangecopy = range(dynamicrangecopystring)
End Sub
Why not change the function argument to a variant and then in the function determine Using VarType etc) if you have been passed a Range and use error handling to check for a string which can be converted to a range or a string that cannot be converted to a range ?
This simple function will convert string arguments into a range object, usable in other excel functions.
Function TXT2RNG(text) As Variant
Set TXT2RNG = Range(text)
End Function
Let's say Sheet1!A1 has the text value "Sheet1!B1" and Sheet1!B1 has the value "1234". The following code will use the range address stored as text in A1 as an input and copy the range B1 to A2:
Sub Tester()
Sheet1.Range(Range("A1")).Copy
Sheet1.Range("A2").PasteSpecial xlPasteAll
End Sub