Are dynamically created controls in VB.net created on the heap or the stack? - vb.net

I'm experimenting with a Goal Tracking application that generates a list of goals the user has set. I'm currently just using labels as placeholders for whatever I'll use later on. My question is, as I populate this form with the labels, are they being created on the heap or the stack?
The generation loop is running every time the form is loaded, so I can't really deduce for myself. (edit: numberOfGoals is a global variable in a separate module file that the whole project has access to.) If the objects were being created on the heap, does that mean that there is a more efficient way of populating the form? Maybe keeping a global list of goals generated in a similar way and when this form is loaded just load from that list onto the stack?
I apologize if the question seems ambiguous. I'm new to both VB.net and programming in general. Thank you everyone for your time.
Private Sub Tracker_Load(sender As Object, e As EventArgs) Handles MyBase.Load
If numberOfGoals > 0 Then
For counter As Integer = 0 To numberOfGoals Step 1
Dim newLabel As New Label
'Set control settings
With newLabel
.Name = "Label" & counter
.Text = "Label " & counter + 1
.Visible = True
.Location = New Point(20, 10 + 25 * counter)
End With
'Activate form and add control
Me.Activate()
ActiveForm.Controls.Add(newLabel)
Next
ElseIf numberOfGoals = 0 Then
Dim newLabel As New Label
With newLabel
.Text = "You have no goals set yet."
.Location = New Point(20, 35)
.AutoSize = True
End With
Me.Activate()
ActiveForm.Controls.Add(newLabel)
End If
End Sub

Those labels are being created on the heap. The concept of memory-management and optimization in the .NET Framework is actually pretty fascinating; I've included a link below. Basically, objects in the .NET Framework tend to be very expensive. At the very least, I would include some type of user-check to prevent the creation of too many goals. This obviously has practical benefits too, as chances of success tend to increase proportionality with focus (:.
As for the second part of your question, I'm guessing you're referring to storing a reference to each dynamically-created control and going through and deleting each one in your clean up. Depending on how long your application is running, this might not be a bad idea. This is actually sort of how early implementations of memory management were built.
Essentially, two linked lists were created. The first linked list included all of the dynamically created objects. The second list was populated by analyzing what objects could be accessed through the active pointers. If they were reachable they were added to the list. If the weren't reachable, this meant that they were no longer being used (or they couldn't be used, since there was no way to access them). The second list was compared with the first and whatever objects where on the first list but not on the second were then 'garbage collected', as it were. So in essence, you've arrived at the primitive implementation of garbage collection, congrats!
Here is a great article about the .NET Framework's memory system, specifically the overheard that stems from the creation of items: (https://www.simple-talk.com/dotnet/net-framework/object-overhead-the-hidden-net-memory-allocation-cost/)

Related

I want my Database to not fill the RAM. What to do with images that are currently not being viewed?

What does my program do?
As at 05 May 2021
This program was developed with the language VB.Net, the .NET framework 4.8 and with Visual Studio 2019 CE. The point of this program is to run a rudimentary database. The view is similar to a classic Internet forum—there are threads, in the threads there are different numbers of postings and in each post there are different numbers of pictures and long texts. If the thread is selected using the ComboBox, all posts with their images and texts are displayed one below the other. When you click on a specific post, only its images are displayed. Since the database is only intended for the company's products, it was decided not to use categories (e.g. images vs. videos vs. offtopic because it doesn't make any sense) and sub-categories (e.g. electrical vs. wood products).
When the program is closed, you will be asked whether the data should be saved. (still in the beta version). These data are read in when the program is loaded. If images are not found, their paths will be displayed in a window.
The user also has the option of searching through all threads and viewing the results with various sorting options. In this case, only the posts found are listed in the ListBox, and here, too, the user can select individual posts and have them displayed enlarged.
The program reads in the user data when it starts. A user can log in and, depending on his role, has certain power to make decisions. A “normal” user can create threads and posts, but only an administrator or moderator can edit and delete posts; and block a user. If you are not logged in or if you are locked, you can only read threads and posts.
The number of contributions is counted for each user. In the future, it should be possible to give a user stars.
About the classes
There is the Form1.vb class, and three other important classes: Class_Forum, Class_Post and Class_Thread. There is also the Class_User class. If a new post is created, this instance of Class_Post is added to a List(of Class_Post), which is located in Class_Thread (“The thread knows which posts it has”). Class_Post has a member ‘Made_by’, which is an instance of the Class_Users (“Every post knows which user made it”). Class_Post contains the member ‚Bilder‘ (=Images), which is a List(Of Bitmap). That is, every instance of class_post has got a List(of Bitmap).
There are also several forms for 1) editing, deleting posts, 2) for blocking or unblocking users, 3) for displaying enlarged images, 4) for logging in, 5) for displaying when images are not loading found, 6) to open the thread, 7) to post.
When the program is started, i.e. when data is read in, the thread instances and post instances are created.
To do list:
1.)
I would like, however, that only the images are in the RAM, which belong to the thread selected with the combobox1. My question is: Do I have to dispose all unnecessary images and read them in again when required? Do we get that built in?
This is my Code to load the data from the formatted txt file. I have a feeling, somewhere in here, or immediately after here, I have to do something.
Private Sub Daten_laden()
Dim Pfad As String 'file path
Using OFD1 As New CommonOpenFileDialog
OFD1.Title = "Textdatei auswählen"
OFD1.Filters.Add(New CommonFileDialogFilter("Textdatei", ".txt"))
OFD1.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)
Dim Result As CommonFileDialogResult
Me.Invoke(Sub() Result = OFD1.ShowDialog())
If Result = CommonFileDialogResult.Ok Then
Pfad = OFD1.FileName
Else
Return
End If
End Using
Dim Pruef_Anzahl_Posts_in_dem_Thread As Integer = 0 'Check number of posts in the thread
Dim Liste_mit_den_Pfaden As List(Of String) 'List with file paths
Dim Liste_mit_den_Bildern As List(Of System.Drawing.Bitmap)
'read all Text
Dim RAT() As String = System.IO.File.ReadAllLines(Pfad, System.Text.Encoding.UTF8)
Pfade_von_nicht_gefundenen_Bildern = New List(Of String) ' Paths of not found images
For i As Integer = 3 To RAT.Length - 2 Step 1
Liste_mit_allen_Threads.Add(New Class_Thread(RAT(i)))
Me.Invoke(Sub() RaiseEvent Es_wurde_ein_neuer_Thread_eroeffnet()) 'A new thread has been opened
Pruef_Anzahl_Posts_in_dem_Thread = CInt(RAT(i + 1))
For j As Integer = (i + 2) To RAT.Length - 2 Step 1
Liste_mit_den_Pfaden = New List(Of String)
Liste_mit_den_Bildern = New List(Of Bitmap)
Dim Index As Integer
Dim Die_ID_des_Nutzers_der_den_Post_erstellt_hat As ULong = CULng(RAT(j + 4)) 'The ID of the user who created the post
For u As Integer = 0 To alle_Nutzer_Liste.Count - 1 Step 1
If alle_Nutzer_Liste(u).ID = Die_ID_des_Nutzers_der_den_Post_erstellt_hat Then
Index = u
Exit For
End If
Next
Dim neuerPost As New Class_Post(RAT(j), RAT(j + 1), CUShort(RAT(j + 2)), Liste_mit_den_Bildern, CDate(RAT(j + 3)), Liste_mit_den_Pfaden, alle_Nutzer_Liste(Index))
'how many threads are there already
Dim wie_viele_Threads_gibt_es_bereits As Integer = Liste_mit_allen_Threads.Count
Liste_mit_allen_Threads(wie_viele_Threads_gibt_es_bereits - 1).Posts_in_diesem_Thread.Add(neuerPost)
' Set the index to the last possible one in the ComboBox. This causes the program to run into the Selected Index event and SI becomes the selected index.
Me.Invoke(Sub() ComboBox1.SelectedIndex = Liste_mit_allen_Threads.Count - 1)
j += 5
Do
Liste_mit_den_Pfaden.Add(RAT(j))
If System.IO.File.Exists(RAT(j)) Then
Liste_mit_den_Bildern.Add(New Bitmap(RAT(j)))
Else
Pfade_von_nicht_gefundenen_Bildern.Add(RAT(j))
End If
j += 1
Loop Until RAT(j) = "#" ' Marker: a post is over
If RAT(j + 1) = "" AndAlso RAT(j + 2) = "" Then ' A new thread is marked with 2 blank lines one below the other.
i = (j + 2)
Exit For
End If
Next
Next
Me.Invoke(Sub() alle_Posts_in_diesem_Thread_anzeigen()) 'show all posts in this thread
If Pfade_von_nicht_gefundenen_Bildern.Count > 0 Then ' In Case something went wrong
Using FBNG As New Form_Bild_nicht_gefunden
FBNG.Datei_anzeigen(Pfade_von_nicht_gefundenen_Bildern)
FBNG.ShowDialog()
End Using
End If
End Sub
On this image, the thread is being switched using the combobox which changes the variable SI which I use often. In this example, the thread Caucasian contains 1 post which contains 2 images. Which means, (still in this moment) I don't need images form shepherds thread
It is not wise to keep all data in RAM. When your database grows, there will be a time that there is too much data.
To overcome this problem, people invented databases: the data is saved on a disk, and only the data that you request is put into memory. Smart databases will keep important data and often used values in memory, to minimize the request time.
If I look at your program, it seems that you only have to change the display after operator input. Operator input is relatively slow: you're a good typist if you can type more than 3 character per second. Usually the response time after operator input is not a problem: if you get the data within half a second, no one will complain.
For a modern computer half a second is enough time to examine a million records. In your application a database won't be a problem.
So my advice would be: start using a database and load only the data that is needed right now, instead of reading all data at startup. Only if you experience long request times, consider to load data that you expect you will need very soon.
Alas, to use a database you will need to learn something new: at least how to structure a databases. If I look at your tables, I have the impression that you already mastered this. Furthermore you'll have to learn how to add / query / update / remove data. This is usually done using SQL or software that supports LINQ, like entity framework.
It seems to me that your queries are quite limited in number: you won't have hundreds of different queries. If you already know SQL, and you don't think you need to know entity framework in the near future, I would go for accessing the database using SQL.
If you don't know SQL very much, or if you need to do an awful lot of different queries, consider to access the database using LINQ. This requires entity framework.
If you haven't got a database already, my first shot would be to use SQLight: a database in one file, fast enough for your application.
If you hide properly that you use SQLight, migrating to a smarter database if the need arises won't require a big change in your application.
class Repository
{
public long AddPost(Post post) {...} // add Post to the database, returns the Id
public long AddUser(User user) {...}
...
// fetch all Posts of a User:
public User FetchUserWithHisPosts(int userId);
// fetch Posts of a User after a certain data:
public User FetchUserWithHisPosts(int userId, DateTime startDate);
...
}
A Repository is some kind of warehouse: all you know is that you can store items in it, and later retrieve them, even after your computer is restarted.
The Repository hides how it does this: the constructor might load everything in memory (like your current application), it could also be that the repository uses SQLight, or a smarter database, or even Entity Framework.
A good way to migrate would be to first translate your current application such that everyone only accesses the data using the Repository. The Repository accesses your "in-memory data" which is in a separate class that is loaded at startup.
Later you can change the repository such that it doesn't use the "in-memory data" anymore, but accesses the database: users of your repository won't have to change.
About loading pictures
No, you don't have to load all pictures at startup. It will be fast enough to load the pictures only when shown: after all, you won't be showing 1000 pictures on the screen at once.
As a picture uses a lot of memory, it is wise to Dispose() the picture as soon as you don't need it anymore:
Image GetImage(long imageId)
{
Repository repository = new Repository();
return repository.GetImageById(imageId);
}
void DisposeImage(Image image)
{
image.Dispose();
}
You hide how you Load the image, and how you free up memory after an Image is not needed anymore. This makes it easier to change this, might the need arise later. It also makes your code easier to read and to unit test.
Hello #Harald Coppoolse,
I thank you for your detailed and understandable answer. Admittedly, I have to look at and learn those SQL (Light) and Entity procedures.
For now, I've temporarily made sure that I only load the pictures that are shown and dispose all the others. I coded this as follows:
Private Sub ComboBox1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ComboBox1.SelectedIndexChanged
If ComboBox1.SelectedIndex <> (-1) Then
SI = ComboBox1.SelectedIndex
If Programm_fertig_geladen Then
Load_the_pictures_only_when_shown_and_free_up_memory_after_an_Image_is_not_needed()
End If
alle_Posts_in_diesem_Thread_anzeigen()
End If
End Sub
Private Sub Load_the_pictures_only_when_shown_and_free_up_memory_after_an_Image_is_not_needed()
For g As Integer = 0 To Liste_mit_allen_Threads.Count - 1 Step 1
If g <> SI Then 'Diese Bilder verwerfen
For i As Integer = 0 To Liste_mit_allen_Threads(g).Posts_in_diesem_Thread.Count - 1 Step 1
For j As Integer = 0 To Liste_mit_allen_Threads(g).Posts_in_diesem_Thread(i).Bilder.Count - 1 Step 1
Liste_mit_allen_Threads(g).Posts_in_diesem_Thread(i).Bilder(j).Dispose()
Liste_mit_allen_Threads(g).Posts_in_diesem_Thread(i).BoolArray(j) = False
Next
Dim CNT As Integer = Liste_mit_allen_Threads(g).Posts_in_diesem_Thread(i).Bilder.Count
For z As Integer = (CNT - 1) To 0 Step -1
Liste_mit_allen_Threads(g).Posts_in_diesem_Thread(i).Bilder.RemoveAt(z)
Next
Next
Else 'Diese Bilder laden
'für jeden Post
For i As Integer = 0 To Liste_mit_allen_Threads(g).Posts_in_diesem_Thread.Count - 1 Step 1
'die Bilder in dem Post
For j As Integer = 0 To Liste_mit_allen_Threads(g).Posts_in_diesem_Thread(i).Pfade_der_Bilder.Count - 1 Step 1
Dim neu_geladenes_Bild As New Bitmap(Liste_mit_allen_Threads(g).Posts_in_diesem_Thread(i).Pfade_der_Bilder(j))
If Liste_mit_allen_Threads(g).Posts_in_diesem_Thread(i).BoolArray(j) = False Then
Liste_mit_allen_Threads(g).Posts_in_diesem_Thread(i).Bilder.Add(neu_geladenes_Bild)
Liste_mit_allen_Threads(g).Posts_in_diesem_Thread(i).BoolArray(j) = True
End If
'End Using
Next
Next
End If
Next
End Sub
I built a Boolean array into the Class_Post, which has as many members as there are images and paths in the post. The purpose of this is to make sure that I remember which pictures are there and which are not.
When disposing of the images of a post, the respective array member is set to false.
When reloading the images of a post, the respective array member is set to True.
Dispose alone is not enough, because funnily enough, the place in the List(of Bitmap) remains occupied. You also have to completely delete the picture with RemoveAt, but in a backward running for loop, because the list gets smaller during the deletion. ;)
Using cannot not be used.

VB.NET - Dynamically created controls and how to manipulate them

If I create a control like so:
Dim fb As New Label
With fb
.Name = "newLabel"
.text = "some text"
<etc.>
Me.Controls.Add(fb)
End With
Now, if I wanted to change the text on that label during run time, I would normally do:
newLabel.text = "some other text"
Unfortunately, Visual Studio won't let me do that as 'newLabel' isn't defined until run time.
So, my question is: How do I reference a control created in such a way? (The only way I can think of is to loop through all controls until I find the one I'm looking for, but that seems a tad inefficient to me.)
'newLabel' isn't defined until run time"
That isn't really accurate. You are confusing the object with a variable used to reference the object. When you add a control to a form in the designer, VS generates code to create and configure that control. It's much the same as the code you wrote and posted. You can see it in the designer code file, which you can access if you click the 'Shoe All Files' button in the Solution Explorer. That code includes a member variable to which the created object is assigned. You then use that member variable to refer to that object in code.
If you're creating controls at run time then you generally can't declare a member variable for each one to be assigned to because you don't know how many there will be. If you do know how many there will be then you probably ought to be adding them at design time. That means that you have two options:
Declare a single member variable that will refer to a collection of controls created at run time and then access then via name or index from that.
Access them by name from the Controls collection of the form or other container control that you must add them to in order for them to be displayed.
Option 2 requires that you provide a unique name for each control when you create it. Option 1 doesn't require a name at all, although it doesn't preclude one.
Option 1 might look like this:
At the class level:
Private labels As New List(Of Label)
In a method somewhere:
For i = 0 To 9
Dim lbl As New Label
labels.Add(lbl)
Controls.Add(lbl)
Next
Later:
Dim lbl = labels(recordIndex)
Option 2 might look like this:
In a method somewhere:
For i = 0 To 9
Dim lbl As New Label With {.Name = "titleLabel" & i}
Controls.Add(lbl)
Next
Later:
Dim lbl = DirectCast(Controls("titleLabel" & recordIndex), Label)

How to set a listview FocusedItem programatically

How can I set the FocusedItem property programatically?
I've tried this so far with no success:
If lvw.FocusedItem Is Nothing Then
If lvw.Items.Count > 0 Then
lvw.Focus()
lvw.HideSelection = False
lvw.Items(0).Selected = True
lvw.Items(0).Focused = True
lvw.FocusedItem = lvw.Items(0)
lvw.Select()
End If
End If
btw the form where the listview is has not called the ShowDialog method yet.
Can this be the reason for this not to work?
You have to understand that each control on the Form and the Form itself is a window and for the window to have focus it must first be created and assigned a handle.
For a basic description of this, I refer you to: All About Handles in Windows Forms The following excerpts are from the referenced article.
What is a Handle?
A handle (HWND) is the return value from CreateWindowEx which the Windows Operating System uses to identify a window. A "window" in win32 is a much broader concept than you may think - each individual button, combobox, listbox etc comprises a window. (For more information see About Window Classes ) NOTE: there are other things known as "Handles" in the Framework - e.g. GDI Handles from a Bitmap or Handles to Device Contexts (HDCs) - this article discusses HWNDs only.
...
When does a Control create its handle? (When does a control call CreateWindowEx?)
A control tries as much as possible to defer creating its handle. This is because setting properties forces chatty interop between the CLR and user32.
Typically the handles for all the controls are created before the
Form.Load event is called. Handles can also be created if the "Handle"
property is called and the handle has not yet been created, or
CreateControl() is called.
So a window's handle is not immediately created when you instantiate a control. However, you can force a control to create its handle by referencing its Handle property.
So if you first get the ListView to create its handle, then when you set those properties that you wanted.
Dim f2 As New Form2
' you do not need this condition, it is here only for demonstration purposes
' so that you can step through the code in the debugger and observe the
' code execution.
If Not f2.ListView1.IsHandleCreated Then
' retrieval of the Handle will cause a handle to be created
' if it has not yet been created
' if you delete the If-Then block, you will need to retain the
' following statement
Dim h As IntPtr = f2.ListView1.Handle
End If
f2.ListView1.FocusedItem = f2.ListView1.Items(2)
f2.ListView1.Items(2).Selected = True
f2.ListView1.Items(2).Focused = True
f2.ActiveControl = f2.ListView1
f2.ShowDialog()
As others have commented, your code should work as written. If all you need is to programmatically access the focused item in your code, you shouldn't be experiencing any difficulties. (If you are, please describe them.)
If you are looking for a visual effect (the row being highlighted), my guess is that your code is in another control's event and the focus is being set back to that control automatically the instant after your code runs. More than likely your code needs to be where it is and trying to move it elsewhere to prevent this issue would be a waste of time.
However, there are other ways to set a row apart visually. When a list view isn't likely to stay focused, my preferred method is to distinguish the selected item with a different fore/back color. (You can use the focused item if you prefer, but I find the selected item more useful. Your call.)
Here is an example which visually highlights the selected row, regardless of focus:
Private Sub lvw_SelectedIndexChanged(sender As Object, e As EventArgs) Handles lvw.SelectedIndexChanged
If lvw.Items Is Nothing Then Exit Sub
For Each lvi As ListViewItem In lvw.Items
If lvi.Selected = True Then
lvi.ForeColor = Color.DarkGray
lvi.BackColor = Color.LightCyan
Else
lvi.ForeColor = Color.Black
lvi.BackColor = Color.White
End If
Next
End Sub
EDIT:
In response to the added information that this form is being displayed using ShowDialog, yes, that is likely the source of your problem.
ShowDialog creates a new instance of the form. Therefore, if you have set any properties of a form or its controls, and later call ShowDialog to display that form, the form displayed is a new copy of the original form and will not reflect the changes you made programatically.
Imagine you sit down at a computer where a blank Word document is already open. You type something in it and then open a new document. The text you typed in the first document is not copied to the second. I think this is the root of your troubles here.

Creating VB.Net forms via code instead of in design mode

I'm using netzero hardware to manage the contents of a number of monitors. My present solution creates a form in VB.Net that has a pixel offset corresponding to where I've placed the Monitors in display management in the control panel. Each monitor has a dedicated form, and in each form are various objects.
The annoyance is that each form must be individually created (so far as I know) at design time. I can't make an array of forms, coupled with an array of offsets and assign all the properties through code.
There ought to be a way to do this...it would simplify my coding and project management.
What I see on MSDN is either over my head or not helpful.
I haven't tested this in hardware yet, but it does compile w/o error:
Public Sub makeform()
Dim MonitorForm(21) As Form
Dim MPictureBoxes(21) As PictureBox
Dim a As Integer
For i As Integer = 0 To n 'up to 21
MonitorForm(i) = New Form
MonitorForm(i).Name = "Form" & (i + 1)
MonitorForm(i).Text = "Form" & (i + 1)
MonitorForm(i).Controls.Add(MPictureBoxes(i))
MonitorForm(i).Location= new Point (x(i), y(i))
With MPictureBoxes(i)
.Name = "Picture Box " & Convert.ToString(i)
.Image = Image.FromFile(CurrentPic(i))
.Location = New System.Drawing.Point(0, 0)
.Size = New Size(1920, 1080)
' Note you can set more of the PicBox's Properties here
End With
Next
End Sub
Where I had gone wrong in my attempts at this was trying to do it this way
Dim Monitor(21) as New Form
That doesn't work, and the difference between Dim Monitor(21) as Form followed by monitor(i)= new Form
was simply too subtle for my present understand of classes, namespaces etc.
.
Well, I've had to give up on this approach and go back to creating n forms at design time (which means that they have names of form2...form22, putting each of them at manual start positions in design mode. There just doesn't seem to be a way to do this with an array of forms. So the code I have built around the messiness of forms2...forms22 works just fine, it's just going to be messy to maintain and elaborate on.
The solution to this may lie in system.screen classes, but the documentation on this is too advanced for me and I'm not finding good code examples for anything other than extracting data about how many screens there are - nothing about writing to them.
This is very easy in code. You want to make many instances of the same form. In this case, I have created a form in the designer called frmTest and I create many instances in code called frmNew:
Public Sub Main()
For x = 100 To 400 Step 100
For y = 100 To 700 Step 200
Dim frmNew As New frmTest
frmNew.Show()
frmNew.Top = x
frmNew.Left = y
frmNew.Height = 100
frmNew.Width = 200
Next
Next
End Sub
I have just used two loops to increment x and y values, but you could do this from a database or config file easily enough.

McAfee deletes code from VBA module

I am trying to program an Excel module where it dynamically inserts code in new objects in a form that is created at design time.
I am using this code where "Code" contains a string with the actual code that should go into the DstrFiles object.
Dim DstrFiles As Object
Set DstrFiles = ThisWorkbook.VBProject.VBComponents("DistributeFiles")
With DstrFiles.CodeModule
.InsertLines .CountOfLines + 1, Code
End With
My problem is that when I use the .InsertLines, McAfee removes the entire Code from my module, is there a way to work around this?
First I create the label with:
Form1.Controls.Add("Forms.Label.1", "Label1", True)
Then I use the .InsertLines to create some code to go with the Label.
For instance, I want the background color of the label to turn red when someone clicks on it. This has been very easy to accomplish with the ".InsertLines".
An ugly way to work around this is to just create a bunch of code beforehand that is ready in the background and then limit the amount of labels that may be created on the fly. - I hope it won't come to that.
I have been googeling around, and this seems to be a known problem with McAfee.
Do anyone know a way to create a dynamic user form that can add code to new labels or button that are added with the Contrls.Add method?
You should not be generating new labels by writing code that creates the controls.
You should be using the .Add method on the Controls collection to create new labels.
For example:
UserForm1.Controls.Add("Forms.Label.1", "foo", True)
You can use WithEvents to get the events.
For example, in UserForm1,
Public WithEvents a As MSForms.Label
Private Sub a_Click()
MsgBox "label clicked"
End Sub
Private Sub CommandButton1_Click()
Set a = UserForm1.Controls.Add("Forms.Label.1", "foo", True)
a.Visible = True
a.Caption = "Hi There"
End Sub
If you want to make a dynamic array of newly added controls, you'll need to create a little wrapper class. Sample code for that is here.
If possible I would recommend against dynamic generation of code (smells like a self-modifying program?).
It's maybe hard to say without knowing your specific problem but I bet there is a better solution using a function with the necessary parameters.
You might be able to workaround this version of McAfee. But the next version of the data-files, or another malware blocker might block you anyhow.
So you can create code like this to run on you development machine, but it will never (or only temporary) work when distributed to customers.