VBA: variable name = type name? - vba

Consider
Type Country
...
End Type
Type Ambassador
Country As Country
End Type
Is this a problem in VBA? As you can see, the ambassador needs a country, which has the same name as its type. Is this an issue? If yes, what are the recommended workaround?

Related

Create table with variable number of columns

I am hoping to get a few ideas for something to push me in the right direction. I have a custom class that stores data from a table based on criteria. The raw data (consisting of over 100 columns and varying between 10-1000 rows) is on a worksheet. My code does the following:
1 - Creates an object from the custom class
2 - Adds a value to the properties of the object
3 - Adds the object to a collection
4 - Returns the collection to the controller which sends it to the view to build the table
The following will build a collection of column ranges from the raw data, at least:
Private mcolColumnAddresses As Collection
Private Sub Class_Initialize()
Set mcolColumnAddresses = New Collection
Dim vHeader As Variant
For Each vHeader In mwksReport.Range(mwksReport.Cells(1, 1), mwksReport.Cells(1, mlLastColumn))
mcolColumnAddresses.Add vHeader.Offset(1, 0).Resize(mlLastRow - 1), vHeader.value
Next vHeader
End Sub
The end users want the ability to choose the columns they want for building the new table. But a typical class for a table would use a row as an object with the column headers as the properties. How would I build a table using class properties when the columns are not known until run-time? I hope that makes sense.
Note: I am not asking for code but for suggestions. Has anybody else had this requirement? If so, how did you approach it? An example is welcome, too.
But a typical class for a table would use a row as an object with the column headers as the properties
If your table has really more than 100 columns, or if the column names are only known a runtime, you should probably approach this different. One object per row is fine, but your class could provide a method for accessing all column values by their name. In VBA syntax:
Function GetValue(byval columnName as string) as Variant
'...
As you see, you have to sacrifice some type safety here, but that is typically a small price to pay for getting this solved in a sensible manner.
Internally, your objects can store the values in some Dictionary (in VBA available through the MS Scripting Runtime), indexed by the column names. This leads to
Function GetValue(byval columnName as string) as Variant
if valueDict.ContainsKey(columnName) then
GetValue = valueDict(columnName)
else
'... add some error handling here
end if
End Function
For populating the dictionary, any database has possibilities to determine column names for a table, just google for " get column names programmatically" to find some example code.

VBA - Compile Error: Expected Function or Variable

To start, I am not a programmer. Im just someone trying to make a document that has an "invoice" number that increases on the document that goes up every time I print the document. I found a macro code online but I keep getting the
Compile error
I'll attach a snap shot of what im getting with the piece that keeps screwing up high lighted.
Is there something I'm doing wrong?
To expand on braX's answer...
That's the syntax for assigning the return value of a Function or Property Get member - namely, you are assigning to the procedure's identifier:
Public Function GetTotallyRandomNumber() As Long
GetTotallyRandomNumber = 4
End Function
Seems you mean to have a local variable named SerialNumber, however VBA already knows this identifier as the name of a Sub procedure named SerialNumber, and because a Sub procedure doesn't return anything, it can't legally be assigned like this.
Declare a local variable inside the procedure's scope, before the illegal assignment:
Dim SerialNumber As String
SerialNumber = System.PrivateProfileString(...)
And then your code will work... however I wouldn't recommend using the exact same name as the procedure.
My recommendation would be to name the local variable SerialNumber, and to rename the Sub procedure so that its name starts with a verb. Procedures do something, they're actions: find a meaningful name that describes what it does, and go with that.
Naming is hard though - if you can't find a simple name that describes what your procedure does, it's probably because it's doing too many things. Split it up into smaller, more focused procedures.
Public Sub PrintActiveDocumentAndAddSerialNumberBookmark()
You are treating a Function like a Subroutine. Subroutines do not return values.
If you want the routine to return a value, then change Sub to Function (at the top)
If you are not wanting it to return anything, then choose a different variable name instead of SerialNumber, or change the name of the Subroutine.
You cannot use a variable name that is the same as the name of the Subroutine.

GetType() Shows non-existent type?

As I am trying to figure out how to work with the Siemens Tia Portal Openness framework, I try to find an item in my Tia Portal project with the ControllerTarget type.
I try to find the items like this:
Imports Siemens.Engineering
Imports Siemens.Engineering.HW
Module Module1
Sub Main()
Dim myTiaPortal
myTiaPortal = New TiaPortal(TiaPortalMode.WithoutUserInterface)
'The portal is open, now create a project.
Dim tiaProject As Project
'Open the sample project:
Dim fileName As String
fileName = "C:\Path\To\Project\Sample_Project.ap13"
tiaProject = myTiaPortal.Projects.Open(fileName)
'Get the frist device from the project:
Dim tiaDevice As Device
tiaDevice = tiaProject.Devices.First
For Each item As IDeviceItem In tiaDevice.DeviceItems
Console.WriteLine(item.GetType())
Next
Console.ReadKey()
End Sub
End Module
This shows two items in the project:
Siemens.Engineering.HW.DeviceItemImplementation
Siemens.Engineering.HW.ControllerTargetImplementation
When I try to define an object of the type ControllerTargetImplementation I get the message that this datatype does not exist.
When I try to convert the item of type ControllerTargetImplementation to an object of type ControllerTarget, this seems to work perfectly.
Does this mean that the type returned by GetType() does not have to be the same as the actual type of the object? Is this normal? Or is this a strange thing in the openness platform?
When I try to define an object of the type ControllerTargetImplementation I get the message that this datatype does not exist.
Types can be internal to an assembly, which means that while they exist and things like GetType will show them to be there, you can't use them directly.
When I try to convert the item of type ControllerTargetImplementation to an object of type ControllerTarget, this seems to work perfectly.
Given the names involved here, it certainly sounds like ControllerTarget is the type being exposed to you, the consumer of the library, while the implementation of that type, perhaps a subclass or an implementation of an interface (ie is ControllerTarget a class or interface?) is hidden from you as you don't need to know about how it does it's job, nor interfere with it.
Does this mean that the type returned by GetType() does not have to be the same as the actual type of the object?
The actual type of the object is what is reported by GetType, but that doesn't mean that it's necessarily what you refer to it as. For instance, consider the following:
Class A
End Class
Class B
Inherits A
End Class
Sub Main
Dim obj as A = new B()
Console.WriteLine(obj.GetType())
End Sub
This will report obj as having a type of B (because that's the actual type we instantiated with new B()), even though it's stored against a variable of type A.

Which data type category is String

As I understand, there are the 2 different ways to categorize data types in VBA.
Object type vs. Non-Object
Value type vs. Reference type
I would assume that object types are the same as reference types. But I read that there is a difference regarding assignment between object and non-object types:
Dim i As Integer
i = 1
Dim chrt As Chart
Set chrt = something
Notice the "Set". Now in the following link, String is categorized as reference type.
http://msdn.microsoft.com/en-us/library/t63sy5hs.aspx
But
Dim str As String
Set str = "abc"
is wrong and
Dim str As String
str = "abc"
is correct. Thus reference type and object type is not equivalent. What is the difference?
Your MSDN link is referring to Visual Studio 2013 (.NET), where String is indeed an object (like everything in the .net framework).
VBA strings are values, not objects.
As I understand, there are the 2 different ways to categorize data
types in VBA.
Object type vs. Non-Object
Value type vs. Reference type
It's simpler than that. An object type is a reference type, and a non-object type is a value type.
In VBA object references are assigned using the Set keyword; in the past, values used to be assigned using the Let keyword (I believe that still works, for compatibility reasons); that's why property setters use Let for value types, as in Public Property Let Foo(value As Integer), and Set for reference types, as in Public Property Set Foo(value As Object).
The language evolved and the Let keyword was eventually dropped for value assignations; Set remained required, for object reference assignations.
But in VBA a String is a value, like an Integer or a Boolean.
VBA does have Value Types and Reference Types, but neither Strings nor Arrays fall neatly into either category.
It's informative to look at the definitions of Value types and Reference Types:
Value Type
A data type is a value type if it holds the data within its own memory allocation.
Reference Type
A reference type contains a pointer to another memory location that holds the data.
All Objects use pointers, so they are all Reference Types, while the following store their value at their memory location, so they are all Value Types:
Boolean
Byte
Integer
Long
Single
Double
Date
Currency
But Strings and Arrays are different. They do use pointers, so technically they are Reference Types, but the VBA language semantically treats Strings and Arrays as Value Types.
As such, when working with Strings and Arrays, VBA has the following behaviors:
It is not necessary to use the Set keyword when assigning to a String or Array (unless you're assigning to a member of an Array of objects).
Assigning the value of one String or Array to another creates a copy of the value.
The equality operator for comparing Strings is the = operator.

'text' is ambiguous - ERROR (vb.net)

I am trying to make a set homepage button for my webbrowser, using this code:
Private Sub UpdateHomePage(ByVal UrlString As Text)
Form1.WebBrowser1.Url = New System.Uri(UrlString.Tostring)
IO.File.WriteAllText(Environment.SpecialFolder.ApplicationData & "\Homepage.Info", UrlString)
End Sub
On this part: Private Sub UpdateHomePage(ByVal UrlString As Text), it has an error:
'Text' is ambiguous, imported from the namespaces or types 'System, System.Drawing'.
I have been trying to solve this for days now, and this is my last resort.
The problem is:
UpdateHomePage(ByVal UrlString As Text)
The Text word is a type, which is there to indicate what UrlString is. Types can be organized into namespaces. You can have two types of the same name as long as they are in different namespaces. However, when two namespaces are imported, the compiler is confused about which Text type it should use, so you get the error you are getting. It may also be confusing it with the namespace System.Text.
But as rob pointed out in a comment, you probably didn't mean to use Text. In VB.NET, text data is represented by the String type, so this is probably what you wanted:
Private Sub UpdateHomePage(ByVal UrlString As String)
If you really meant a type of Text, you just need to fully qualify the type name with the namespace.