Edit Value In Excel Range - vb.net

I have an excel sheet with values in a range which I want to perform some calculations on in vb.net. I pass that range to vb.net using COM. When I try editing the values of the range, nothing happens.
My question seems to be very similar to these questions, but I can't quite figure out what step I am missing.
How to edit cell value in VB.net - Using .Interop.Excel
VB.net Office Solution - Accessing value in named Range in a Worksheet
VBA CODE:
Function MyTestRange (Byref myrng as range)
Set classLib = New VBProject.CClass
MyTestRange = classLib.MyTestRange(myrng)
End Function
VB.NET code
Imports Microsoft.Office.Interop.Excel
Public Class CClass
Function MyTestRange(ByRef myrng As Range) As Double
Dim newrng As Range
Dim b As Integer = myrng.Rows.Count
Dim i As Integer
newrng = myrng
For i = 1 To b
newrng.Value2(i, 1) = myrng.Value2(i, 1) + 1
Next i
MyTestRange = newrng.Value2(1, 1)
End Function
End class
While this code doesn't generate an error, it doesn't change the values in newrng.
Edit:
I have tried many iterations based on the link provide, but always get the same error :
An exception of type 'System.Runtime.InteropServices.COMException' occurred in mscorlib.dll but was not handled in user code
Additional information: Exception from HRESULT: 0x800A03EC
This is the simplest way to generate the error:
Dim c As Object
c = myrng.Value
myrng.Value = c
Hence amending the values to something new, seems out of reach!
Edit 2:
After chatting with user Mat's Mug, I tried to edit a value in a range, purely in VBA.
This sub works perfectly:
Sub rangesub()
Dim example As Range
Set example = Range("A1:A4")
example.Value = Application.Transpose(Array(1, 2, 3, 4))
End Sub
Excel functions also seem able to handle passing ranges:
Function SimpleCopyRange(myrng)
SimpleCopyRange = myrng
End Function
A very simple combination of this code works:
Function EditRange(myrng)
Dim example As Range
Set example = Range("A1:A4")
EditRange = example
End Function
However there is an unspecified error if I try to edit the range:
Function EditRange(myrng)
Dim example As Range
Set example = Range("A1:A4")
example.Value = Application.Transpose(Array(1, 2, 3, 4))
EditRange = example
End Function
The application.transpose part obviously adds a layer of complexity, and can be replaced with example.Value = 8 without any changes in results.

Looking at this question/answer:
Excel VBA: Iterating over range parameter and change cell values
It appears that a UDF can only change the calling cell.
I think therefore this method is impossible.
The workaround is to to rewrite the code to work with an array, assign the range to an array, edit the array and pass it to the new function.

Related

Pass name created in Name Manager Excel to Function VBA

I created a name in Name Manager. How to pass the name "MyRange1" parameter for my function in VBA code?
In Excel:
=MyFunction(MyRange1)
MyFunction is:
Public Function MyFunction(nameDefined As Variant) As String
'How get value of nameDefined ??
End Function
There are two ways to pass a Named Range:
as a String
as a Range Object
so a UDF() in a worksheet cell would have either:
=myudf("Name1")
or
=myudf(Name1)
Naturally, the UDF() would have to be coded to expect one or the other,
Note that there could be volatility problems with using only a String.
EDIT#1:
Here is an example of passing a Range rather than a String. Say we create MyRange1 like:
and the UDF() is like:
Public Function MyFunction(rng As Range) As String
Dim r As Range
For Each r In rng
MyFunction = MyFunction & "..." & r.Text
Next r
End Function
Then we can use it in a worksheet cell like:
=MyFunction(MyRange1)
Once the UDF() has the range, it can get the list of items contained therein.
To figure out similar questions, you can put a Breakpoint in the code and analyse the Locals window:
From the Locals window you can notice that you can access "Str2" with nameDefined(2,1)
( or in your version of Excel it might be nameDefined(2) for horizontal array )
You can also check the run-time type with some of the VBA functions:
t = VBA.TypeName(nameDefined) ' t = "Variant()"
v = VBA.VarType(nameDefined) ' v = vbArray + vbVariant ( = 8204 )
b = VBA.IsArray(nameDefined) ' b = True ( also True for range with more than one cell )

VBA Excel Invalid ReDim/Expected Array with Array of Ranges Module

I have a module that stores an array of Range objects that is called in other modules. While this module is functional, it's sloppy, and I would like the code to be easy to read/edit for future developers. Ideally this would not only be easy to read/edit but also be a range array (as opposed to variant array).
How the module is called(ideally would be 'As Range'):
Sub CallModule()
'...
Dim rangeArray As Variant
'...
rangeArray = RngArr()
'...
Call AnotherModule(rangeArray(count))
End Sub
Current Module:
Public Function RngArr() As Variant
RngArr = Array(Range("'ActivityTracker'!B12"), Range("'ActivityTracker'!H12"), Range("'ActivityTracker'!B26"), Range("'ActivityTracker'!H26"), Range("'ActivityTracker'!B39"), Range("'ActivityTracker'!H39"), Range("'ActivityTracker'!B53"))
End Function
I am getting a couple of errors when I attempt to put it together,
Returns 'expected array':
Public Function RngArr() As Range
ReDim RngArr(0 To 6) '<---Expected Array
Set RngArr(0) = Range("'ActivityTracker'!B12")
Set RngArr(1) = Range("'ActivityTracker'!H12")
Set RngArr(2) = Range("'ActivityTracker'!B26")
Set RngArr(3) = Range("'ActivityTracker'!H26")
Set RngArr(4) = Range("'ActivityTracker'!B39")
Set RngArr(5) = Range("'ActivityTracker'!H39")
Set RngArr(6) = Range("'ActivityTracker'!B53")
End Function
Returns 'Invalid ReDim':
Public Function RngArr() As Variant
ReDim RngArr(0 To 6) As Range '<---Invalid ReDim
Set RngArr(0) = Range("'ActivityTracker'!B12")
Set RngArr(1) = Range("'ActivityTracker'!H12")
Set RngArr(2) = Range("'ActivityTracker'!B26")
Set RngArr(3) = Range("'ActivityTracker'!H26")
Set RngArr(4) = Range("'ActivityTracker'!B39")
Set RngArr(5) = Range("'ActivityTracker'!H39")
Set RngArr(6) = Range("'ActivityTracker'!B53")
End Function
I don't know VBA well enough to know exactly what's going on with these errors and I have a number of these modules that need to be fixed. So if someone could give a quick explanation of why I am getting these errors and how to fix them I would really appreciate it!
EDIT: The purpose of this module is to give global access to the locations of various tables in the worksheet so the locations themselves are what matter, not the values in the cells. But this array is used a few times in the workbook because other modules need access to the tables in order to be able to work properly. Also I know you can reference the tables directly but there are many cases in this particular program that would make referencing tables individually much harder than it needs to be.
Public Function RngArr() As Range()
Dim rv(0 To 6) As Range
Set rv(0) = Range("'ActivityTracker'!B12")
Set rv(1) = Range("'ActivityTracker'!H12")
Set rv(2) = Range("'ActivityTracker'!B26")
Set rv(3) = Range("'ActivityTracker'!H26")
Set rv(4) = Range("'ActivityTracker'!B39")
Set rv(5) = Range("'ActivityTracker'!H39")
Set rv(6) = Range("'ActivityTracker'!B53")
RngArr = rv
End Function
Sub Tester()
Debug.Print RngArr()(2).Address()
End Sub
It's not clear what you're trying to do here.
The following code works though:
Public Function testArr() As Variant
Dim newArr() As Range
ReDim newArr(1 To 5) As Range
Set newArr(1) = Sheets("Sheet1").Range("A1")
testArr = newArr
End Function
Public Sub test()
Dim myArr As Variant
myArr = testArr()
End Sub
myArr is still going to be a variant when it gets returned, not a range array if you do it this way, but this seems to match your intent.

Error code is 91 on Find

This may seem like a simple question but Im very new to VBA and Im not sure why I'm receiving the error.
Dim c As String
c = Sheet2.Range("B3:B54").Find("NLwk01")
Error code is 91: Object variable or With block variable not set.
I thought I should've maybe used cells instead of range, but that gives another error with
Error code 5: Invalid procedure call or argument.
As it was mentioned in comment thread, Excel VBA Find() function returns the Range object. Therefore, pertinent to you particular example, it could be coded as in the following sample snippet:
Sub FindRowIndex()
Dim c
Dim rowIdx As Integer
Dim cellValue As String
'return Range object if found
Set c = Sheet2.Range("B3:B54").Find("NLwk01")
If Not c Is Nothing Then
'return the row index (shown as an example)
rowIdx = c.Row
'return the same string used as search criterion "NLwk01"
cellValue = c.Value
End If
End Sub
Pertinent to your case search area ("B3:B54") the rowIdx can be declared As Integer; for extended area you may use Long.
Also, as mentioned in comments thread, you may declare: Dim c As Range.
Hope this may help.

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 pass a dynamic array into a VBA object. Compile error: Invalid use of property

I'm trying to pass an array into a custom class for storage and further use within that object. The class object has the following definition:
' Class Name: MBRMCurves
Implements ICurves
Private m_lInterpDates() As Long
Public Property Get InterpDates() As Long()
InterpDates = m_lInterpDates
End Property
Public Property Let InterpDates(lInterpDates() As Long)
m_lInterpDates = lInterpDates
End Property
The module that calls this code looks like this:
Dim objResult As New MBRMCurves
'Store the forward prices
Dim fx_fwd() As Double
'Store the interpolation dates
Dim int_dates() As Long
'initially there are no people
Dim NumberTenors As Integer
NumberTenors = 0
Dim cell As range
' Create ranges of Dates
Dim range As range
Dim range_topcell As range
' TODO Pri1 Create the Curves Obj
With Worksheets("test")
' Populate the dates of the FWD rates.
Set range_topcell = .range("B5")
Debug.Print range_topcell.Value
Set range = .range(range_topcell, range_topcell.End(xlDown))
Debug.Print range.Count
' Add more columns to the FWD array
ReDim fx_fwd(0 To range.Count - 1, 0 To 3)
ReDim int_dates(0 To range.Count - 1)
' Set the counter
NumberTenors = 0
' Populate the dates of the FWD rates into the first column of the dates array.
For Each cell In range
NumberTenors = NumberTenors + 1
int_dates(NumberTenors - 1) = cell.Value
Next cell
' Add interpolation dates to Curves object
objResult.InterpDates int_dates
The last line in the above code is giving me the compile error: Invalid use of property.
I believe that the syntax of me Let function is correct, but I might be missing a more subtly nuanced oversight.
Can anyone see what I'm doing wrong? I'm working with Excel 2003 and VBA 6.5 on Windows XP.
Any suggestions would be greatly appreciated.
Thanks,
Christos
a property is not a method call and you need to set it equal to your array:
objResult.InterpDates = int_dates
There still might be an issue with the array your passing in but this is a first step.