Take this code:
With ActiveSheet.Shapes.AddShape(msoShapeRectangle, x, y, w, h).TextFrame
.Parent.Line.Visible = False
.Parent.Fill.ForeColor.RGB = RGB(r, g, b)
End With
Is there any VBA way to "execute" or "evaluate" like can be done in perl/python/... such that the text .Parent.Line.Visible
can be drawn from a variable (or cell value), rather than hard coded?
ParentLine = ".Parent.Line.Visible"
ParentLineValue = "False"
With ActiveSheet.Shapes.AddShape(msoShapeRectangle, x, y, w, h).TextFrame
**eval**(ParentLine & "=" & ParentLineValue)
.Parent.Fill.ForeColor.RGB = RGB(r, g, b)
End With
EDIT: I found MSDN information for Access that mentions Eval, but when I execute my code it says "Undefined Sub or Function", pointing at Eval (Excel does not seem to know this function).
EDIT 2: Found the definitive (negative) answer on SO.
EDIT 3: Seems like there is an answer after all, as I am not after a general solution for arbitrary code execution. Thanks to GSerg for helping with using CallByName.
In VBA, declaring variables is optional, but you can't declare AND set the variable at the same time. We've added a line that assigns the value of a variable. In VBA, just append “. Value”, an equals sign, and the value you want to assign (in quotation marks).
Use =Range(cell). Value function to access any cell in the worksheet. Assign the Age variable to it. Run your macro.
Use CallByName
.
Option Explicit
Private Type Callable
o As Object
p As String
End Type
Public Sub SetProperty(ByVal path As String, ByVal Value As Variant, Optional ByVal RootObject As Object = Nothing)
With GetObjectFromPath(RootObject, path)
If IsObject(Value) Then
CallByName .o, .p, VbSet, Value
Else
CallByName .o, .p, VbLet, Value
End If
End With
End Sub
Public Function GetProperty(ByVal path As String, Optional ByVal RootObject As Object = Nothing) As Variant
With GetObjectFromPath(RootObject, path)
GetProperty = CallByName(.o, .p, VbGet)
End With
End Function
Public Function GetPropertyAsObject(ByVal path As String, Optional ByVal RootObject As Object = Nothing) As Object
With GetObjectFromPath(RootObject, path)
Set GetPropertyAsObject = CallByName(.o, .p, VbGet)
End With
End Function
Private Function GetObjectFromPath(ByVal RootObject As Object, ByVal path As String) As Callable
'Returns the object that the last .property belongs to
Dim s() As String
Dim i As Long
If RootObject Is Nothing Then Set RootObject = Application
Set GetObjectFromPath.o = RootObject
s = Split(path, ".")
For i = LBound(s) To UBound(s) - 1
If Len(s(i)) > 0 Then
Set GetObjectFromPath.o = CallByName(GetObjectFromPath.o, s(i), VbGet)
End If
Next
GetObjectFromPath.p = s(UBound(s))
End Function
Usage:
? getproperty("activecell.interior.color")
16777215
SetProperty "activecell.interior.color", vbYellow
'Sets yellow background
? getproperty("names.count", application.ActiveWorkbook)
0
? getproperty("names.count", GetPropertyAsObject("application.activeworkbook"))
0
Dynamically add code.
Don't do this. It's wrong and it requires having that "Allow access to VB project" tick set.
Add a reference to Microsoft Visual Basic for Applications Extensibility X.X
.
Create a module called ModuleForCrap
.
Add a dynamically constructed sub/function:
ThisWorkbook.VBProject.VBComponents("ModuleForCrap").CodeModule.AddFromString _
"function foobar() as long" & vbNewLine & _
"foobar = 42" & vbNewLine & _
"end function"`
Call it:
msgbox application.run("ModuleForCrap.foobar")
Delete it:
With ThisWorkbook.VBProject.VBComponents("ModuleForCrap").CodeModule
.DeleteLines .ProcStartLine("foobar", vbext_pk_Proc), .ProcCountLines("foobar", vbext_pk_Proc)
End With
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With