I am writing a range of VBA functions / subs that can be reused in a number of projects. The issue I have is that these functions are listed in the suggested formula functions when using sheets.
Making the functions private will prevent this, but what it will also do is remove the handy hints showing the parameters for the functions when called from a module other than where the function is stored.
Does anyone know of a way to prevent the suggestion of custom functions without making them private?
Parameterless Public members of a standard module are one of two things:
Sub procedures and they're exposed as macros.
Function procedures and they're exposed as UDF's.
Note that members are implicitly Public if no access modifier is specified.
A Sub that has parameters can't be executed as a macro, so it won't show up as an available macro.
A Function that has side-effects (e.g. mutates some module/global state, or changes other cells' value) is bad code, and a UDF can't change another cell's value anyway.
Making the functions private will prevent this, but what it will also do is remove the handy hints showing the parameters for the functions when called from a module other than where the function is stored.
Making it Private not only "removes the handy hints", it makes the function inaccessible to other modules, and your code won't compile.
If your code has UDF's, put them all in the same standard module, e.g. UserFunctions, and make them explicitly Public for readability's sake.
If your code has macros, put them all in the same standard module, e.g. Macros, and make them explicitly Public for readability's sake.
If your code has functions and procedures that need to be Public (e.g. they're accessed from UDF's and/or macros), make them explicitly Public for readability's sake, and put them in standard modules named appropriately (i.e. avoid Helper and Manager modules, they inevitably become a dumping bag of whatever doesn't quite fit anywhere, and grow to a mess).
Then put this at the top:
Option Explicit
Option Private Module
That option (Private Module) prevents all public/exposed members from being picked up as macros and UDF's. Option Explicit should just be there anyway.
Another way is to implement logic in class modules; members of a class module can't be accessed without an instance of that class (i.e. an object), and therefore won't be exposed as macros/UDF's.
As it says on msdn:
Both classes and modules are reference types that encapsulate the items defined within, but they differ in how items are accessed from other procedures.
How is it possible to use a Module inside a Class? How would I access its members and use them?
EDIT #1
I tried to access this module in all possible ways,
Dim memman as MemoryModule
but it gives me an error, Module 'MemoryModule' cannot be used as a type.
From your comment on the question...
Dim memman as MemoryModule
This is incorrect. Modules aren't classes, they can't be instantiated as objects. You can essentially think of a module as being a collection of Shared helper functions. And you'd access those like any other Shared function:
MemoryModule.SomeFunction()
So, for example, if your module looks like this:
Module MemoryModule
Sub PerformAnOperation()
' some function logic
End Sub
End Module
Then any class which can see that module can invoke that function:
MemoryModule.PerformAnOperation()
If logically your "memory module" should be an object capable of separate instances, then it shouldn't be a Module. Instead, you'd want to make it a Class and implement it with instance members instead of Shared members. It's important to structure your code according to the logic and concepts it represents.
Currently in a Win Form application, im using a Global Variable Class which contains variables that are used to to share data. My question is, what other ways are there to achieve this? Best practises? and why?
Globals are bad for many reasons, but probably the most glaring reason is because, ideally speaking, every time you call the same method, passing it the same parameters, it should always do the same thing with the same results. Globals brake that rule. Suddenly your code starts behaving in unpredictable ways because something wasn't initialized properly somewhere else, or some global got modified incorrectly.
The best way I've found to get rid of the need for globals is to adhere to the principles of dependency injection (DI). There is much material on the topic online, but in a nutshell, rather than having classes reach out to create or find their dependencies on their own, they should simply request that the dependencies be provided to them, often in the constructor. Anything that you are accessing via global variables would, by definition, be considered dependencies of the classes that access them. Therefore, instead of, for instance, having a global settings object, like this:
Global settings As New Settings()
And then a class that uses it like this:
Public Class MyClass
Public Sub DoSomething()
If settings.SomethingEnabled Then
' ...
End If
End Sub
End Class
You would instead, do it like this:
Public Class MyClass
Public Sub New(settings As Settings)
_settings = settings
End Sub
Private _settings As Settings
Public Sub DoSomething()
If _settings.SomethingEnabled Then
' ...
End If
End Sub
End Class
This makes your code much cleaner, more flexible, and more reliable. It also makes the code far more testable too, which is a great added benefit.
Data should be shared according to how it is going to be used. If a variable is required across the entire application then it can be seen to have global scope and a global variable concept (e.g. public static shared) may well be appropriate.
Often this is not the case however as global variables should really be avoided (check out here and here for more reasoning)
Data should be encapsulated at the level it is required - for example if a form has data / variables within it that are applicable to it's function but where other forms need to now the value, this would be the ideal case for a public readonly property on the form, which would mask the actual detail of the variable from the rest of the aplication.
How do I declare a global variable in Visual Basic?
These variables need to be accessible from all the Visual Basic forms. I know how to declare a public variable for a specific form, but how do I do this for all the forms in my project?
There is no way to declare global variables as you're probably imagining them in VB.NET.
What you can do (as some of the other answers have suggested) is declare everything that you want to treat as a global variable as static variables instead within one particular class:
Public Class GlobalVariables
Public Shared UserName As String = "Tim Johnson"
Public Shared UserAge As Integer = 39
End Class
However, you'll need to fully-qualify all references to those variables anywhere you want to use them in your code. In this sense, they are not the type of global variables with which you may be familiar from other languages, because they are still associated with some particular class.
For example, if you want to display a message box in your form's code with the user's name, you'll have to do something like this:
Public Class Form1: Inherits Form
Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Load
MessageBox.Show("Hello, " & GlobalVariables.UserName)
End Sub
End Class
You can't simply access the variable by typing UserName outside of the class in which it is defined—you must also specify the name of the class in which it is defined.
If the practice of fully-qualifying your variables horrifies or upsets you for whatever reason, you can always import the class that contains your global variable declarations (here, GlobalVariables) at the top of each code file (or even at the project level, in the project's Properties window). Then, you could simply reference the variables by their name.
Imports GlobalVariables
Note that this is exactly the same thing that the compiler is doing for you behind-the-scenes when you declare your global variables in a Module, rather than a Class. In VB.NET, which offers modules for backward-compatibility purposes with previous versions of VB, a Module is simply a sealed static class (or, in VB.NET terms, Shared NotInheritable Class). The IDE allows you to call members from modules without fully-qualifying or importing a reference to them. Even if you decide to go this route, it's worth understanding what is happening behind the scenes in an object-oriented language like VB.NET. I think that as a programmer, it's important to understand what's going on and what exactly your tools are doing for you, even if you decide to use them. And for what it's worth, I do not recommend this as a "best practice" because I feel that it tends towards obscurity and clean object-oriented code/design. It's much more likely that a C# programmer will understand your code if it's written as shown above than if you cram it into a module and let the compiler handle everything.
Note that like at least one other answer has alluded to, VB.NET is a fully object-oriented language. That means, among other things, that everything is an object. Even "global" variables have to be defined within an instance of a class because they are objects as well. Any time you feel the need to use global variables in an object-oriented language, that a sign you need to rethink your design. If you're just making the switch to object-oriented programming, it's more than worth your while to stop and learn some of the basic patterns before entrenching yourself any further into writing code.
Pretty much the same way that you always have, with "Modules" instead of classes and just use "Public" instead of the old "Global" keyword:
Public Module Module1
Public Foo As Integer
End Module
Okay. I finally found what actually works to answer the question that seems to be asked;
"When needing many modules and forms, how can I declare a variable to be public to all of them such that they each reference the same variable?"
Amazingly to me, I spent considerable time searching the web for that seemingly simple question, finding nothing but vagueness that left me still getting errors.
But thanks to Cody Gray's link to an example, I was able to discern a proper answer;
Situation;
You have multiple Modules and/or Forms and want to reference a particular variable from each or all.
"A" way that works;
On one module place the following code (wherein "DefineGlobals" is an arbitrarily chosen name);
Public Module DefineGlobals
Public Parts As Integer 'Assembled-particle count
Public FirstPrtAff As Long 'Addr into Link List
End Module
And then in each Module/Form in need of addressing that variable "Parts", place the following code (as an example of the "InitForm2" form);
Public Class InitForm2
Private Sub InitForm_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Parts = Parts + 3
End Sub
End Class
And perhaps another Form;
Public Class FormX
Sub CreateAff()
Parts = 1000
End Sub
End Class
That type of coding seems to have worked on my VB2008 Express and seems to be all needed at the moment (void of any unknown files being loaded in the background) even though I have found no end to the "Oh btw..." surprise details. And I'm certain a greater degree of standardization would be preferred, but the first task is simply to get something working at all, with or without standards.
Nothing beats exact and well worded, explicit examples.
Thanks again, Cody
Make it static (shared in VB).
Public Class Form1
Public Shared SomeValue As Integer = 5
End Class
Public variables are a code smell - try to redesign your application so these are not needed. Most of the reasoning here and here are as applicable to VB.NET.
The simplest way to have global variables in VB.NET is to create public static variables on a class (declare a variable as Public Shared).
A global variable could be accessible in all your forms in your project if you use the keyword public shared if it is in a class. It will also work if you use the keyword "public" if it is under a Module, but it is not the best practice for many reasons.
(... Yes, I somewhat repeating what "Cody Gray" and "RBarryYoung" said.)
One of the problems is when you have two threads that call the same global variable at the same time. You will have some surprises. You might have unexpected reactions if you don't know their limitations. Take a look at the post Global Variables in Visual Basic .NET and download the sample project!
small remark: I am using modules in webbased application (asp.net).
I need to remember that everything I store in the variables on the module are seen by everyone in the application, read website. Not only in my session.
If i try to add up a calculation in my session I need to make an array to filter the numbers for my session and for others.
Modules is a great way to work but need concentration on how to use it.
To help against mistakes: classes are send to the
CarbageCollector
when the page is finished. My modules stay alive (as long as the application is not ended or restarted) and I can reuse the data in it.
I use this to save data that sometimes is lost because of the sessionhandling by IIS.
IIS Form auth
and
IIS_session
are not in sync, and with my module I pull back data that went over de cliff.
All of above can be avoided by simply declaring a friend value for runtime on the starting form.
Public Class Form1
Friend sharevalue as string = "Boo"
Then access this variable from all forms simply using Form1.sharevalue
You could just add a new Variable under the properties of your project
Each time you want to get that variable you just have to use
My.Settings.(Name of variable)
That'll work for the entire Project in all forms
The various answers in this blog seem to be defined by SE's who promote strict adherence to the usual rules of object-oriented programming (use a Public Class with public shared (aka static), and fully-qualified class references, or SE's who promote using the backward-compatibility feature (Module) for which the compiler obviously needs to do the same thing to make it work.
As a SE with 30+ years of experience, I would propose the following guidelines:
If you are writing all new code (not attempting to convert a legacy app) that you avoid using these forms altogether except in the rare instance that you really DO need to have a static variable because they can cause terrible consequences (and really hard-to-find bugs). (Multithread and multiprocessing code requires semaphores around static variables...)
If you are modifying a small application that already has a few global variables, then formulate them so they are not obscured by Modules, that is, use the standard rules of object-oriented programming to re-create them as public static and access them by full qualification so others can figure out what is going on.
If you have a huge legacy application with dozens or hundreds of global variables, by all means, use Modules to define them. There is no reason to waste time when getting the application working, because you are probably already behind the 8-ball in time spent on Properties, etc.
The first guy with a public class makes a lot more sense. The original guy has multiple forms and if global variables are needed then the global class will be better. Think of someone coding behind him and needs to use a global variable in a class you have IntelliSense, it will also make coding a modification 6 months later a lot easier.
Also if I have a brain fart and use like in an example parts on a module level then want my global parts I can do something like
Dim Parts as Integer
parts = 3
GlobalVariables.parts += Parts '< Not recommended but it works
At least that's why I would go the class route.
You can pipe the variable in to a file in the output directory and then load that file in the variable.
Imports System.IO
This code writes the file.
Dim somevariable = "an example"
Dim fs As FileStream = File.Create("globalvars/myvar1.var")
Dim filedata As Byte() = New UTF8Encoding(True).GetBytes(somevariable)
fs.Write(filedata, 0, filedata.Length)
fs.Close()
This loads the file in another form.
Dim form2variable
Dim fileReader As String
fileReader = My.Computer.FileSystem.ReadAllText("globalvars/myvar1.var")
form2variable = filereader
Public Class Form1
Public Shared SomeValue As Integer = 5
End Class
The answer:
MessageBox.Show("this is the number"&GlobalVariables.SomeValue)
In VB6/VBA, you can declare module-level variables outside of a specific Sub or Function method. I've used Private and Public before inside modules and understand them like so:
Public - visible to all code inside the module and all code outside the module, essentially making it global.
Private - visible only to code inside the module.
I've noticed that you can use Dim and Global as modifiers for modular variables. Are Dim and Global different from Private and Public, respectively, when used as access modifiers on modular fields? If so, how are they different?
Dim and Private work the same, though the common convention is to use Private at the module level, and Dim at the Sub/Function level. Public and Global are nearly identical in their function, however Global can only be used in standard modules, whereas Public can be used in all contexts (modules, classes, controls, forms etc.) Global comes from older versions of VB and was likely kept for backwards compatibility, but has been wholly superseded by Public.