vba - properly passing range value to a function - vba

in my application i call a function and pass 4 values to calculate a cell adress:
nettowertadresse = searchAdress(Dateiname, CurrentSheet, "Nettowert", Range("A1:C60"))
function:
Function searchAdress(inputworkbook As String, inputsheet As String, inputsearchtext As String, inputrange As Range) As Range
With Workbooks(inputworkbook).Sheets(inputsheet).Range(inputrange)
Set searchAdress = .Find(inputsearchtext, LookIn:=xlValues)
End With
End Function
now the problem is that i get error 1004 "application defined or object defined error" and i think that maybe the range is not properly passed because the debugger shows no value for the variable "inputrange" when jumping to the function. please give some advice on how to make this function work. thanks.

Your function, searchAddress, declares inputrange as Range. This means that the object inside your function is a Range object.
So you should not be using it as .Range(inputrange). Instead try using this code, which treats it correctly as a Range object:
Function searchAdress(inputworkbook As String, inputsheet As String, inputsearchtext As String, inputrange As Range) As Range
With Workbooks(inputworkbook).Sheets(inputsheet)
Set searchAdress = inputrange.Find(inputsearchtext, LookIn:=xlValues)
End With
End Function
Also note that there is another bug in your code that calls this function. You need to use the keyword Set when assigning the return value to your nettowertadresse variable:
Set nettowertadresse = searchAdress(Dateiname, CurrentSheet, "Nettowert", Range("A1:BA2"))
Otherwise you will experience Run-time error '91', which you mention in your follow-up question.

you add a Range to a rangeobject in your function, your function looks like this then:
With Workbooks(inputworkbook).Sheets(inputsheet).Range(Range("A1:C60"))
Set searchAdress = .Find(inputsearchtext, LookIn:=xlValues)
End With
You should change this:
Function searchAdress(inputworkbook As String, inputsheet As String, inputsearchtext As String, inputrange As String) As Range
With Workbooks(inputworkbook).Sheets(inputsheet).Range(inputrange)
Set searchAdress = .Find(inputsearchtext, LookIn:=xlValues)
End With
End Function
And then pass this to the function:
nettowertadresse = searchAdress(Dateiname, CurrentSheet, "Nettowert", "A1:C60")

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

VBA: Using a range returned from a function

I'm trying to use WorksheetFunction.Match in VBA, but I'm having issues in populating the lookup_array parameter. For the lookup_array, I'm using the output of another function -GetSubRange() as Range - that returns a range.
I've verified that my WorksheetFunction.Match() syntax works, and that my GetSubRange() function also works - when coded differently, I can get the address, select it, etc.
The result is that the function returns a #VALUE! error, which I've concluded is that the lookup_array parameter isn't referencing the range input properly.
Any ideas?
Here's what I'm trying to do:
Function GetValue(rng As Range, colName As String, key As String) As String
Dim rngSubRange As Range
Set rngSubRange = GetSubRange(rng, colName)
GetValue = WorksheetFunction.Match(key, rngSubRange, 0)
End Function
Function GetSubRange(rng As Range, colName As String) As Range
Dim rngHeader As Range
Dim colNum As Integer
Set rngHeader = ThisWorkbook.Names(rng.Name.Name &"_Header").RefersToRange
colNum = Application.Match(colName, rngHeader, 0)
Set GetSubRange = rng.Columns(colNum)
End Function
The error was in the algorithm: I was searching in the wrong subrange. rngSubRange was getting the range of the value column, but the key was in another column. I had to create to subranges: one for the key column and one for the value column.

Pass a Range as a Function Parameter

I am writing a function that needs to pass a specified range into it, but I keep getting an error whenever I call the function. Here's some example code--the code in the function is unimportant, as all I want to do is be able to use the passed in range for anything within.
My Declaration:
Sub exampleFunction (exampleRange as Range)
exampleRange.Borders(xlEdgeLeft).Weight = xlMedium
End Sub
But when I try to call the function with this code:
Dim myRange As Range
Set myRange = Sheet1.Range ("C2")
exampleFunction (myRange) ' <-- This is what doesn't work
I get an error that says "Compile Error: Expected: =".
What do I need to do to pass in myRange correctly during the function call?
exampleFunction (myRange)
should be
exampleFunction myRange
or for multiple arguments:
exampleFunction myRange, myString, myInt
You only use () when your method returns a value or when using the Call keyword.
If you wrap your argument in () - and you're not calling a Function or using Call - then VBA will first evaluate the argument before passing it to your method - you often don't want that.
You can see the impact of this evaluation in the Immediate window:
? typename( Range("A1") ) '>> "Range"
? typename( (Range("A1")) ) '>> "Double" (if A1 has a numeric value)
' "String" (if A1 has a text value)

vba byref argument reference not available

Given that the called procedure actually sets the passed Range object ByRef, I am expecting the object reference to be available in the calling procedure. But it is still Nothing.
What is the fix?
calling
Private Sub Specs_TryGetRangeFromDefinedName_CanFindGlobalName()
Dim Specs As New SpecSuite
Dim rngResult As Excel.range
Dim bResult As Boolean
bResult = TryGetRangeFromDefinedName(rngResult, "LongTermTaxRate", ThisWorkbook.Name)
With Specs.It("should return refersTo range when the name is global")
.Expect(bResult).ToEqual True
.Expect(rngResult.address).ToEqual "$B$2" ** FAIL (object is Nothing)2
End With
SpecRunner.RunSuite Specs
End Sub
called
Public Function TryGetRangeFromDefinedName(ByRef aRange As Excel.range, _
ByRef aName As String, _
ByRef aWkbName As String, _
Optional ByRef aSheetName As String = vbNullString) As Boolean
Dim rngResult As Excel.range
If IsValued(aName) And IsValued(aWkbName) Then
On Error Resume Next
If IsValued(aSheetName) Then
' local name (presumably)
Set rngResult = Workbooks(aWkbName).Worksheets(aSheetName).range(aName)
Else
' global name (presumably)
Set rngResult = Workbooks(aWkbName).Names(aName).RefersToRange
End If
TryGetRangeFromDefinedName = (err.Number = 0)
On Error GoTo 0
End If
End Function
Parameter aRange is never used, and rngResult is assigned but never referenced. Get rid of rngResult and assign aRange instead.
Also, the intent of your method would be clearer if the String parameters were passed ByVal, since they're not assigned.
These observations are all Rubberduck code inspections results (disclaimer: I co-own this project).

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