Every time i try to attribute any type of string to this i get Object reference not set to an instance of an object. I have tried every combination of possible way to handle the string, convert it to a string again and all the fuzz. It's very frustrating and i guess it's some kind of base principle of the structure/class usage and the string array or whatnot (which is also very dumb)
Private Class movie
Public name As String
Public actors As String
Public year As Integer
Public country As String
Public votes As Integer
End Class
Private movies() As movie
If File.Exists(OpenFileDialog1.FileName) Then
lblPath.Text = OpenFileDialog1.FileName
Dim iFile As New StreamReader(lblPath.Text)
While Not iFile.EndOfStream
current = iFile.ReadLine
movies(i).name = "sasasasa"
lbMovies.Items.Add(movies(i).name)
i = i + 1
End While
End If
these are the code parts where i use it
You are creating an empty array of movie objects, as was pointed out previously. Consequently movies(i) is Nothing. When you try to access a member (movies(i).name) the appropriate exception is generated. Note that your code does not even reach the assignment operator = but fails prior to that. In other words, this has nothing to do with strings altogether; you will get the same error if you write movies(i).votes = 42 instead. To fix your code you will first have to create a movie object, populate it and append it to your array.
Related
I have a VBA Function which returns an object of my own class module "CInputDBEntries".
UIPath receives this object as a COM__Object and to read it I need to do some CType Conversion. However no matter how I do it, I can't access the members (values) of the object.
I already tried to convert it to "Object" but can't access the values.
I also tried saving multiple class objects as a Collection but it fails at the CType conversion because it's bugged (VBACollection to Microsoft.VisualBasic.Collection = COM CastTypeException)
I also posted this on the UIPath forums: https://forum.uipath.com/t/invoke-vba-how-to-read-the-retrieved-com-object-in-uipath-vba-function-returns-custom-type/96115
Class Definition:
Private strTitle As String
Private strValue As String
Private boolIntegrity As Boolean
The method:
Public Function ReadRelevantEntries() As CInputDBEntries
Dim entry As CInputDBEntries
entry.Title = "title"
entry.Val = "value"
entry.Integrity = True
Set ReadRelevantEntries = entry
End Function
Currently my conversion is this: CType(listExcelEntries, Object)
Expected result is to be able to pull the values out of the COM__Object so I can read the 2 strings and my bool variable.
Found the solution:
This is the wrong approach
var propertyInfo = comObject.GetType().GetProperty("PropertyName")
This is the correct approach
//get the value of comObject.PropertyName
object propertyValue = comObject.GetType().InvokeMember("PropertyName", System.Reflection.BindingFlags.GetProperty, null, comObject, null);
Credits: https://smehrozalam.wordpress.com/2010/02/16/c-using-reflection-with-com-objects/
I wonder about how I can store a part of code in a string field of an object and convert it at run-time in executable code.
Let's say I have my class:
Public Class Car
Public m_IDCar As String
Public m_Brand As String
Public m_Description As String
Public m_Condition As String ' => here I need to store an If, or an If condition as a String, that will be executed at run-time.
End Class
Then the code that happens when CommandButton1.Click():
Dim carList As List(Of Car)
Dim parameter as String
' here I create carList with data from a database, so for each car In the database I create its relative object, with its .m_IDCar, .m_Brand, .m_Description and .m_Condition, and add it to carList
parameter = TextBox1.Text ' => given in input by the user
For each car As Car in carList
If (car.m_Condition = True) then ' => here there must be something to do cause, as things are now, in car.m_Condition is stored a String, but I need to parse it in code that returns a boolean value and, if this value would be True, the code will enter in the If statement.
'do something
End If
Next
Example of car.m_Condition could be:
car.m_Condition = "(car.m_Name=""BMW"" AND car.m_Description.Contains(parameter)) OR car.m_Brand=""AUDI"""
I need some tips on how to implement this approach, if someone would help me.
TY!
EDIT:
Thanks David, I have seen that question and seems a lot similar. I've seen that the user asked how store the entire If in a string:
Dim code As String = "IIf(1 = 2, True, False)"
(the users that asked that question used IIf)
The best way for me would be to store the condition to evaluate in a string and, maybe, the value to with compare the result in another one. So, for example:
Dim condition As String = "(car.m_Name=""BMW"" AND car.m_Description.Contains(parameter)) OR car.m_Brand=""AUDI"""
Dim valueToCompareWith as String = "True"
and the following If
If (car.m_Name=""BMW"" AND car.m_Description.Contains(parameter)) OR car.m_Brand=""AUDI"" = True) Then
'do something
End If
will become:
If (condition = valueToCompareWith) Then '(conceptually, because in this form it's simply a String comparison that returns always False)
'do something
End If
EDIT2:
Thanks Plutonix, I've read about your hint on Getters and Setters, I've not specified it, but the context I'm working on is a lot more complex then this. I've made a very simple example just for focus the problem, but I'm working with a good amount of objects, with various fields to compare and for every comparison there are different conditions in the If, with different logics and different types of data to compare.
I started learning VBA for my job at the end of last summer, and I can proudly say this is the first time I haven't be able to find the answer on Google. I started teaching myself about Classes this week, and I have come across a situation where I would like to be able to identify an "indexed property" for my class.
Since that probably isn't the clearest explanation, here is a hypothetical example:
The class which I have created for my super awesome sandwich shop (clsSASS) contains properties for Calories, Weight in Grams, Price, and Ingredients. The first three are variables with very straight forward let and get statements. I.E.:
Public pCal As Integer
Public Property Get Calories() As Integer
Calories= pCal
End Property
Public Property Let Calories(Value As Integer)
pCal = Value
End Property
Ingredients however is designed to contain, in order of entry, the list of ingredients. My initial instinct was to do something like this:
Public pIngd As Collection
Public Property Get Ingredients(Value As Integer) As Collection
Ingredients = pIngd(Value)
End Property
Public Property Set Ingredients(Object As Collection)
Set pIngd = Object
End Property
So if Bacon were the first ingredient in the list (and let's be honest it always would be), something like clsNewSandwich.Ingredients(1) would return the string 'Bacon'.
The problem arose when I added a container property to a class, and then couldn't figure out how to identify the individual items in the container. So this may just be a simple syntax issue that has nothing to do with classes whatsoever.
Many Thanks!
*edited for clarity/continuity
OK - I will retract my advice about always naming let/set and Get the same, since in this case you cannot, since the "input" and "output" types are not the same. So, in the sample below I've named the property which just returns one ingredient as Ingredient
Class "clsSASS":
Dim pIngd As Collection
Property Set Ingredients(c As Collection)
Set pIngd = c
End Property
Property Get Ingredient(v As Integer) As String
Ingredient = pIngd(v)
End Property
Regular module:
Sub Tester()
Dim c As New Collection
Dim s As New clsSASS
c.Add "bacon"
c.Add "lettuce"
c.Add "tomato"
Set s.Ingredients = c
Debug.Print s.Ingredient(1) 'bacon
Debug.Print s.Ingredient(2) 'lettuce
Debug.Print s.Ingredient(3) 'tomato
End Sub
I have been tasked with modifying some legacy ActiveX DLLs written in Visual Basic 6. One of the things I need to do is to emulate the "ScriptingContext" object, (so that we can support other mechanisms for running the DLLs other than IIS without having to re-write large chunks of the code).
Something that has been causing me some grief is the "ASPTypeLibrary.Application" object which has two very different ways to access its stored values, eg:
.Application("KeyName")
or
.Application.Value("KeyName")
How can I create my own VB6 class which supports both of these access mechanisms? I can do one or the other but not both?
(a simple code example would be great thanks, I'm not a VB6 programmer)
I have found a way to do this, see the code snippet below taken from two classes, "clsContext" and "clsContextApp". The latter implements the ".Value" functionality and the former has the ".Application" property...
I have now discovered an even more difficult problem. The ScriptingContext's "ASPTypeLibrary.Request" object has three different ways to access its ".Request.QueryString" property:
.Request.QueryString("KeyName")
or
.Request.QueryString.Value("KeyName")
or
.Request.QueryString
The last method returns a string comprised of all the Key/Value pairs concatenated by "&" characters. I have no idea how to implement this?
' clsContext
Public ContextApp As clsContextApp
Public Property Get Application(Optional ByRef Key As Variant = Nothing) As Variant
If (Key Is Nothing) Then
Set Application = ContextApp
Else
If (Not ContextApp.p_Application.Exists(Key)) Then
Application = ""
Else
Application = ContextApp.p_Application.Item(Key)
End If
End If
End Property
Public Property Let Application(ByRef Key As Variant, ByVal Value As Variant)
If (VarType(Key) = vbString) Then
If (VarType(Value) = vbString) Then
If (Not ContextApp.p_Application.Exists(Key)) Then
ContextApp.p_Application.Add Key, Value
Else
ContextApp.p_Application.Item(Key) = Value
End If
End If
End If
End Property
' clContextApp
Public p_Application As Scripting.Dictionary
Public Property Get Value(Key As String) As String
If (Not p_Application.Exists(Key)) Then
Value = ""
Else
Value = p_Application.Item(Key)
End If
End Property
Public Property Let Value(Key As String, Value As String)
If (Not p_Application.Exists(Key)) Then
p_Application.Add Key, Value
Else
p_Application.Item(Key) = Value
End If
End Property
Well I've managed to answer the additional question regarding ScriptingContext's "ASPTypeLibrary.Request" object which has three different ways to access its ".Request.QueryString" property.
I've included a code snippet below that is based on the code from my previous answer for the "ASPTypeLibrary.Application" object. If I add a new Property to the "clsContextApp" class and make it the default property for that class, then it will be called when the ".Application" property is called without any qualification eg:
MyString = Context.Application
Setting a particular property as the default property in VB6 is a little obscure, but I followed the directions I found here.
' clsContextApp Default Property
Property Get Values(Optional ByVal Index As Integer = -1) As String ' This is the Default Value for clsContextApp
Attribute Values.VB_UserMemId = 0
Dim KeyName As String, Value As String
Values = ""
If (Index < 0) Then
For Index = 0 To p_Application.Count - 1
KeyName = p_Application.Keys(Index)
Value = p_Application.Item(KeyName)
If (Index > 1) Then
Values = Values + "&"
End If
Values = Values + KeyName + "=" + Value
Next Index
Else
If (Index < p_Application.Count) Then
KeyName = p_Application.Keys(Index)
Value = p_Application.Item(KeyName)
Values = KeyName + "=" + Value
End If
End If
End Property
Adding a reference to Microsoft Active Server Pages Object Library, and to COM+ Services Type Library, and then using the object browser reveals some basic things you seem to be missing.
GetObjectContext is a global method in COMSVCSLib with no arguments used to retrieve the current ObjectContext as its return value.
ObjectContext is a Class. It has a read-only default property, named Item that takes a String argument and is of type Variant.
Passing "Application" as an argument to Item returns the current instance of the Application Class.
ScriptingContext is a Class. It is obsolete.
Application is another Class. It has a default property named Value that takes a String argument and is of type Variant.
Value is a property of the Application Class and provides access to a read-write key/value pair store where keys are always Strings. Since it is of type Variant you can store objects as well as simple values and arrays of various types.
None of this looks difficult to replicate in VB6. The key/value store could be a Collection or Scripting.Dictionary.
I have a set of owners, who each have their own set of opportunities.
I have two class modules, ClmOpportunity which has a bunch of properties, and ClmOwner which has a single name property and a Collection storing ClmOpportunity Objects:
Public name As Variant
Private opps As New collection
Public Function addOpportunity(opp As ClmOpportunity)
opp.ID = opps.Count + 1
opps.Add opp, opps.Count + 1
End Function
These owner objects are also being stored in a collection in my main module. When I try to use the function addOpportunity as shown below:
Dim item As New ClmOpportunity
item.name = "test"
owners.item(overallOwner).addOpportunity (item)
I get the error:
"object doesn't support this property or method"
I am quite new to VBA and I don't understand why this is, I am passing in a ClmOpportunity, so it should be fine right?
Any help would be greatly appreciated!
You don't use parentheses if there's no return value...
owners.item(overallOwner).addOpportunity item
...then you'll get a "type mismatch" error because a collection expects a string value as a key, so you'll need to adjust your addOpportunity function (which should probably be a Sub if you don't intend adding a returned value)