Refactoring Legacy VB6 codes : Passing Data between Forms
How do most VB6 programmers pass data from one form to another?
Refactoring Legacy VB6 codes : Passing Data between Forms
How do most VB6 programmers pass data from one form to another?
The top 2 ways I’ve seen are by using Public/Global variables and direct form and control manipulation — — and it’s largely because the language and documentation of VB6 itself seem to suggest that “that’s how to do it”.
In this article I’ll show you a very common pattern in VB6 codes that you’ll see even in large production applications and in the end, how you should refactor it so it’s easier to maintain later on and for you to easily grasp the concepts / approaches in modern languages like VB Net, C#, Python, etc.
The UI Setup
We’ll use a super simple example for this. Form1 calls Form2 and the Form1 must reflect the selection from the Form2.
Here’s the UI design setup for this (note that I’ve not renamed any objects here so we can just focus on the topic and not be bogged down by unnecessary details).

Typical Coding Solutions
These are 2 of the most common patterns I see and why they’re not good.
Direct Form Control Manipulation
Form2 is shown with the dropdown menu and when the button is clicked, it directly accesses the textbox control in Form1:

This is bad, because: It tightly-coupled both Form1 and Form2 and therefore there’s almost no reusability. Form2 will always be dependent on Form1 and that Form1 must always have a textbox called Text1. You can’t reuse Form2 on other forms or basic (BAS) modules.
Another reason is accessing a form control directly from another location is generally a bad practice, especially when you go to (say) VB dot Net with threading.
Using Global / Public Variable(s)
Another common approach is creating or using a basic (BAS) module and defining a global or public variable, and this is what Form1 and Form2 works on.
In this implementation, you create this module (ex. Module1) and declare the public “plan” variable there.
In Form2, you write to this public variable when the user selects the plan. In Form1, you read from this public variable once the Form2 is dismissed.

Now, there are valid use cases for using public variables (like a global logger), but in the case where we just want to get the selection from a form, it’s not a good use. This pattern is one of the top reasons hard-to-find bugs exists especially when you introduce timers and other codes that all point to the same variable.
A Better Approach — Use Event
I’m listing this option just because it is a valid alternative to the previous approaches, but for this use case, it’s not one that I’d recommend.
I personally would use this on a long running processes or in a multi-document interface (MDI) applications where child forms need to be monitoring the main (parent) form, but not in this case.
So in this approach, Form2 creates a public event that Form1 can listen to. Form2 simply raises this event when a selection is made. Form1 handles the custom even and reacts to it.
Note that in Form1, you need to declare a module-level form prefixed with the “WithEvents” keyword so the custom event with be visible.

The Way to Do it
For our use case, make it like calling a function — — it’s specific (we ask the user to select, we process the ‘return’ value); no global variables, no unnecessary events to raise, no direct control mutation — — and reusable.
To do this, you just define a public function in Form2 (ex. “SelectPlan”) which just shows Form2 in a modal mode, waits for the user to dismiss it and then return a value like a regular function does.
We added an optional “default” value for cases where the user closes the form (didn’t click the button) or you can intercept that and return the default item — — it’s up to you really.

Why do we see these tightly-coupled patterns in VB6?
Visual Basic was marketed as “Rapid Application Development” or “RAD” when it first came out and the goal was mostly to build an app quickly, and most of these apps were small so it worked well, until it didn’t — — when the scope got larger, when more features were needed, more devs need to maintain the code base, that’s when it started failing. And this is not specific to Visual Basic, but to other languages as well.
Another reason is because of the IDE and the general notion of “visual” in Visual Basic. You almost always start a VB6 project with Form1 and when you double-click the form, it takes you to the form load event where you can just start typing logic and it just works. Click buttons, textboxes, write logic for those events, done. This environment unfortunately created this “god-form” where everything, every logic and feature is on a single form. Why? Because the language allowed you to do that and sometimes even encourages you to do it too.
Now does this still happen in Visual Basic dot Net, given that it’s a new variant, created from scratch? The answer is “Yes!”.
Does this mean VB is a bad language, because of these things?
Not really. I can make what most people consider good languages look and perform bad, by writing bad codes and bad design patterns. Languages are tools; what makes it good or bad depends on the wielder of that tool.
The other reason is that VB was solving a different problem than what other languages were solving.
The good news is, bad VB codes can be refactored to make them loosely coupled, scalable, reusable, dynamic and maintainable — — you just have to go past the notion that “VB6 is old and that’s it” cause it’s not.
Source Codes
If you want to test the codes I used in this article, you may get them from this Git repository:
메타데이터
- post_id
- 12c802407c54
- slug
- refactoring-legacy-vb6-codes-passing-data-between-forms-12c802407c54
- url
- https://medium.com/@pjonsms/refactoring-legacy-vb6-codes-passing-data-between-forms-12c802407c54
- canonical_url
- https://medium.com/@pjonsms/refactoring-legacy-vb6-codes-passing-data-between-forms-12c802407c54
- author_url
- https://medium.com/@pjonsms
- status
- ok
- fetched_at
- 2026-06-23 17:05:31