The My Namespace

This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production.

The reference material consulted while preparing these pages is listed in the section bibliography.

This page is written against Visual Basic 17.13 on .NET 10 (SDK 10.0.402) and was checked on 2026-10-19. The examples that start with Option Strict On and print results are complete console programs that were built with warnings treated as errors and run in the .NET 10 SDK container (Linux, arm64). The examples that need Windows Forms were built with EnableWindowsTargeting on the same container and were not run; they are labelled "built, not run". Where an example is meant to fail, the compiler messages shown are the ones the SDK printed. Every console example here has the root namespace ShelfApp, because the CLR and compiler messages include it.

My is the Visual Basic feature that most often surprises people who come from books, blog posts and Stack Overflow answers written for .NET Framework: code such as My.Computer.Name or My.Settings.PageSize compiled in every project there, and on .NET it compiles only in some project types. This page explains what My is, how the project decides what it contains, what every part of it does, what to use instead where it is missing, and how to add your own members to it. The runtime library behind My, with the functions that exist in every project, is on The Visual Basic Runtime Library; the project-level setting MyType also appears in Visual Basic and .NET.

What My is

My is a namespace that sits in your project’s root namespace, together with a small amount of code that the compiler generates for you. It was introduced with Visual Basic 2005 as a set of shortcuts ("speed-dial for the framework") to the objects an application usually needs: the application and its information, the computer and its devices, the current user, application settings, embedded resources and the forms of a Windows Forms program. Nothing in My is magic and nothing in it cannot be written by hand: each shortcut is a property that returns an object from the Microsoft.VisualBasic runtime or from the BCL.

Member What it gives you Defined by

My.Application

information about the assembly (Info), the command line, the culture, the log, and in Windows Forms programs the Application Framework: startup and shutdown events, single-instance behaviour, the main form

generated class MyApplication, which inherits one of the ApplicationBase classes of the runtime

My.Computer

the machine and its devices: Audio, Clipboard, Clock, FileSystem, Info, Keyboard, Mouse, Name, Network, Registry, Screen

generated class MyComputer, which inherits Microsoft.VisualBasic.Devices.Computer

My.User

the current user’s name and roles

Microsoft.VisualBasic.ApplicationServices.User

My.Settings

typed application and user settings

a class that the Settings designer generates in your project (it is not generated by the compiler)

My.Resources

typed access to the project’s embedded resources

a module that the Resources designer generates in your project

My.Forms

one default instance of each form of the project

generated class MyForms, only when the project type is a Windows Forms one

My.WebServices

default instances of generated web-service proxies

generated class MyWebServices, which is empty on .NET

My.Request, My.Response, My.Log

the ASP.NET request, response and trace log

ASP.NET Web Forms project type on .NET Framework; not available on .NET

Two facts explain nearly everything else on this page. First, the compiler decides what My contains from the project’s MyType property, so the same My.Computer.Name can compile in one project and fail in the next. Second, the types behind My.Computer, My.User and My.Application are not in the part of the runtime that every .NET program has; on .NET they are in Microsoft.VisualBasic.Forms, which ships with the Windows Desktop runtime. The next two sections show both facts with real output.

MyType decides what exists

The compiler receives the project property as the conditional-compilation constant _MyType (the SDK passes MyType into the constants list, which is why you can also test it with #If _MyType = "Console" Then; see Conditional Compilation and Directives). The compiler then adds a hidden source file to the compilation, in which Namespace My contains the pieces that the value asks for. The SDK’s Visual Basic targets file sets MyType to Empty for every target that is not .NET Framework, and its own comment says that project templates are responsible for choosing a non-empty value when it makes sense. The SDK templates for Windows Forms and WPF projects do so; the console template does not.

The results of building a class library for net10.0-windows (with UseWindowsForms on) once for each value, and then inspecting the generated types with reflection, are:

MyType MyApplication inherits Generated members of My Result on a plain net10.0 project

Empty (SDK default)

not generated

nothing: Namespace My exists but is empty

compiles

Console

ConsoleApplicationBase

My.Application, My.Computer, My.User, My.WebServices

does not compile: BC30002, the types are missing

Windows

ApplicationBase

My.Application, My.Computer, My.User, My.WebServices

does not compile: BC30002

WindowsForms

WindowsFormsApplicationBase

the same, plus My.Forms, and Main for an executable

does not compile: BC30002

WindowsFormsWithCustomSubMain

ConsoleApplicationBase

the same as WindowsForms but no generated Main (you write Sub Main)

does not compile: BC30002

Web

not applicable

ASP.NET objects

does not compile on any .NET target: BC30002 for WebUser, AspLog and System.Web.HttpRequest

Custom

not generated

only MyProject.ThreadSafeObjectProvider(Of T)

compiles

(The base classes in the second column were read from the compiled assembly with MetadataLoadContext; the "does not compile" results were produced by building the same project with -p:MyType=... on net10.0.) The practical rules are:

  • A console application or a class library keeps MyType=Empty. My.Computer, My.Application, My.User, My.Settings, My.Resources and My.Forms do not exist there, and writing them gives BC30456. The program below uses every one of them:

Option Strict On

Module Program
    Sub Main()
        Console.WriteLine(My.Application.Info.Version.ToString())
        Console.WriteLine(My.Computer.Name)
        Console.WriteLine(My.User.Name)
        Console.WriteLine(My.Settings.ToString())
        Console.WriteLine(My.Resources.ToString())
        Console.WriteLine(My.Forms.ToString())
        Console.WriteLine(My.WebServices.ToString())
        Console.WriteLine(My.Request.ToString())
        Console.WriteLine(My.Response.ToString())
        Console.WriteLine(My.Log.ToString())
    End Sub
End Module

The compiler prints (root namespace ShelfApp, with warnings as errors off so only the My problems appear):

Program.vb(5,27): error BC30456: 'Application' is not a member of 'ShelfApp.My'.
Program.vb(6,27): error BC30456: 'Computer' is not a member of 'ShelfApp.My'.
Program.vb(7,27): error BC30456: 'User' is not a member of 'ShelfApp.My'.
Program.vb(8,27): error BC30456: 'Settings' is not a member of 'ShelfApp.My'.
Program.vb(9,27): error BC30456: 'Resources' is not a member of 'ShelfApp.My'.
Program.vb(10,27): error BC30456: 'Forms' is not a member of 'ShelfApp.My'.
Program.vb(11,27): error BC30456: 'WebServices' is not a member of 'ShelfApp.My'.
Program.vb(12,27): error BC30456: 'Request' is not a member of 'ShelfApp.My'.
Program.vb(13,27): error BC30456: 'Response' is not a member of 'ShelfApp.My'.
Program.vb(14,27): error BC30456: 'Log' is not a member of 'ShelfApp.My'.
  • Setting MyType to Console in a plain net10.0 project does not give a console project its My, because the generated code names types from Microsoft.VisualBasic.Forms. A program with only Console.WriteLine(My.Computer.Name) and <MyType>Console</MyType> fails with:

vbc : error BC30002: Type 'Global.Microsoft.VisualBasic.ApplicationServices.ConsoleApplicationBase' is not defined.
vbc : error BC30002: Type 'Global.Microsoft.VisualBasic.ApplicationServices.User' is not defined.
vbc : error BC30002: Type 'Global.Microsoft.VisualBasic.Devices.Computer' is not defined.
  • Web is a leftover of ASP.NET Web Forms on .NET Framework. Building with MyType set to Web on net10.0-windows printed:

vbc : error BC30002: Type 'Global.Microsoft.VisualBasic.ApplicationServices.WebUser' is not defined.
vbc : error BC30002: Type 'Global.Microsoft.VisualBasic.Logging.AspLog' is not defined.
vbc : error BC30002: Type 'Global.System.Web.HttpRequest' is not defined.
  • Custom turns the generated parts off while keeping the ThreadSafeObjectProvider helper. On .NET Framework it was the setting for a project that wanted to supply its own My; today Empty does the same.

  • A Windows Forms or WPF project on net10.0-windows must set MyType itself when it wants My. The SDK’s winforms template writes its own Sub Main and does not set MyType, so in a freshly generated project My.Computer is empty until you add <MyType>WindowsForms</MyType> (or WindowsFormsWithCustomSubMain when you keep your own Sub Main).

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>WinExe</OutputType>
    <TargetFramework>net10.0-windows</TargetFramework>
    <UseWindowsForms>true</UseWindowsForms>
    <RootNamespace>ShelfDesktop</RootNamespace>
    <MyType>WindowsForms</MyType>
    <OptionStrict>On</OptionStrict>
  </PropertyGroup>
</Project>

Where the My types live on .NET

The generated My.Computer, My.Application and My.User are thin classes over runtime types. On .NET Framework they were all in Microsoft.VisualBasic.dll. On .NET they are split. The part that does not need a UI toolkit is in Microsoft.VisualBasic.Core, which every project references: its exported types are in only three namespaces, Microsoft.VisualBasic, Microsoft.VisualBasic.CompilerServices and Microsoft.VisualBasic.FileIO. The rest of the My machinery is in Microsoft.VisualBasic.Forms, part of the Windows Desktop targeting pack. Loading that assembly’s public surface with MetadataLoadContext shows what is Windows-only:

Microsoft.VisualBasic
  AudioPlayMode
Microsoft.VisualBasic.ApplicationServices
  ApplicationBase, ApplyApplicationDefaultsEventArgs, ApplyApplicationDefaultsEventHandler, AssemblyInfo,
  AuthenticationMode, CantStartSingleInstanceException, ConsoleApplicationBase, NoStartupFormException,
  ShutdownEventHandler, ShutdownMode, StartupEventArgs, StartupEventHandler, StartupNextInstanceEventArgs,
  StartupNextInstanceEventHandler, UnhandledExceptionEventArgs, UnhandledExceptionEventHandler, User,
  WindowsFormsApplicationBase
Microsoft.VisualBasic.CompilerServices
  HostServices, IVbHost
Microsoft.VisualBasic.Devices
  Audio, Clock, Computer, ComputerInfo, Keyboard, Mouse, Network, NetworkAvailableEventArgs,
  NetworkAvailableEventHandler, ServerComputer
Microsoft.VisualBasic.Logging
  DiskSpaceExhaustedOption, FileLogTraceListener, Log, LogFileCreationScheduleOption, LogFileLocation
Microsoft.VisualBasic.MyServices
  ClipboardProxy, FileSystemProxy, RegistryProxy, SpecialDirectoriesProxy
Microsoft.VisualBasic.MyServices.Internal
  ContextValue`1

Notable consequences, all read from that listing:

  • Microsoft.VisualBasic.Devices and Microsoft.VisualBasic.ApplicationServices (the whole My.Computer and My.Application machinery) are in the Forms assembly, so they exist only for net*-windows targets with the Windows desktop pack.

  • Computer has exactly Audio, Clipboard, Keyboard, Mouse and Screen; its base class ServerComputer has Clock, FileSystem, Info, Name, Network and Registry. There is no Ports: My.Computer.Ports (serial ports) from .NET Framework books does not exist on .NET; use System.IO.Ports.SerialPort from the System.IO.Ports package.

  • The file-system operations that My.Computer.FileSystem wraps live in Microsoft.VisualBasic.FileIO.FileSystem in the Core assembly, so they work in a console program and on Linux (see "Replacements outside a Windows project" below).

  • Microsoft.VisualBasic.Logging.Log and FileLogTraceListener are in the Forms assembly as well.

  • The User class sits in the Forms assembly; it has CurrentPrincipal, IsAuthenticated, IsInRole and Name.

The generated code

For a Windows Forms project (MyType=WindowsForms), reflection over the compiled assembly shows what the compiler generated for My:

ShelfDesktop.My.MyApplication : WindowsFormsApplicationBase
ShelfDesktop.My.MyComputer : Computer
ShelfDesktop.My.MyProject : Object
    Application, Computer, Forms, User, WebServices, MyForms, MyWebServices, ThreadSafeObjectProvider`1,
    and private fields (m_AppObjectProvider, m_ComputerObjectProvider, m_MyFormsObjectProvider, ...)
ShelfDesktop.My.MyProject+MyForms : Object
    one property per Form class (Form1, ...), Create__Instance__, Dispose__Instance__
ShelfDesktop.My.MyProject+MyWebServices : Object
    no members apart from Create__Instance__ and Dispose__Instance__
ShelfDesktop.My.MyProject+ThreadSafeObjectProvider`1 : Object
    GetInstance, m_ThreadStaticValue

The pieces you should know:

  • MyProject is a module (hidden from IntelliSense with HideModuleName), which is why you write My.Application and not My.MyProject.Application. Each property returns a lazily created, per-thread instance through ThreadSafeObjectProvider(Of T), whose GetInstance method keeps its value in a thread-static field (m_ThreadStaticValue). Two threads therefore see two different My.Forms.Form1 objects and two My.Computer objects.

  • MyApplication and MyComputer are Partial Friend Class types. A second part, written by you, can add members, handlers and overrides; this is how My.Computer.ShelfFolder in the example below is made.

  • MyForms has one property per Form subclass in the project; the property creates the form on first use and again after it was disposed.

  • MyWebServices contains nothing but the infrastructure: there is no way to add a web-service reference on .NET that fills it.

  • The generated Main (MyApplication.Main) is what the entry point of a WindowsForms project calls. It creates the application, wires the Application Framework and calls Run.

My.Application

My.Application is an instance of the generated MyApplication class. It has these parts in a Windows project.

Member Purpose

Info

AssemblyName, CompanyName, Copyright, Description, DirectoryPath, LoadedAssemblies, ProductName, StackTrace, Title, Trademark, Version, WorkingSet — read from the assembly attributes (AssemblyCompany, AssemblyProduct …​)

CommandLineArgs

the command-line arguments as a read-only collection of strings (without the program name)

Culture, UICulture

the current culture of the thread; ChangeCulture(name) and ChangeUICulture(name) change them for the current thread

GetEnvironmentVariable(name)

reads an environment variable, throws if it is missing (unlike Environ)

Log

a Microsoft.VisualBasic.Logging.Log: WriteEntry, WriteException, TraceSource and DefaultFileLogWriter (a FileLogTraceListener that writes <program>.log files)

OpenForms

the collection of open forms (Windows Forms only)

MainForm, SplashScreen, ApplicationContext

protected or Windows-Forms-specific; the main form is set in OnCreateMainForm

Run, DoEvents, Shutdown, HideSplashScreen

the application life cycle

The attributes behind Info are ordinary assembly attributes, which the SDK writes from project properties. The program below reads the same data without My, from a console project that sets Version, AssemblyTitle, Company, Product, Description and Copyright; it is the replacement to use in a console program and the mapping to remember when Info shows an unexpected value. The other objects are covered by the same program, which prints one block for each My area:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net10.0</TargetFramework>
    <RootNamespace>ShelfApp</RootNamespace>
    <OptionStrict>On</OptionStrict>
    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
    <NuGetAudit>false</NuGetAudit>
    <Version>1.2.0</Version>
    <AssemblyTitle>Shelf catalogue</AssemblyTitle>
    <Company>Shelf Club</Company>
    <Product>Shelf</Product>
    <Description>A small library catalogue</Description>
    <Copyright>Copyright 2026 Shelf Club</Copyright>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="System.Configuration.ConfigurationManager" Version="10.0.0" />
  </ItemGroup>
</Project>

(The System.Configuration.ConfigurationManager package in that project file is for the settings example further down.)

Option Strict On

Imports System.Globalization
Imports System.IO
Imports System.Net.NetworkInformation
Imports System.Reflection
Imports System.Runtime.InteropServices

Module AlternativesDemo
    Sub Main(args As String())
        Dim asm As Assembly = Assembly.GetEntryAssembly()

        Console.WriteLine("-- My.Application.Info")
        Console.WriteLine("AssemblyName : " & asm.GetName().Name)
        Console.WriteLine("Version      : " & asm.GetName().Version.ToString())
        Console.WriteLine("Title        : " & asm.GetCustomAttribute(Of AssemblyTitleAttribute)().Title)
        Console.WriteLine("Company      : " & asm.GetCustomAttribute(Of AssemblyCompanyAttribute)().Company)
        Console.WriteLine("ProductName  : " & asm.GetCustomAttribute(Of AssemblyProductAttribute)().Product)
        Console.WriteLine("Description  : " & asm.GetCustomAttribute(Of AssemblyDescriptionAttribute)().Description)
        Console.WriteLine("Copyright    : " & asm.GetCustomAttribute(Of AssemblyCopyrightAttribute)().Copyright)
        Console.WriteLine("Info. version: " & asm.GetCustomAttribute(Of AssemblyInformationalVersionAttribute)().InformationalVersion)
        Console.WriteLine("DirectoryPath: " & (AppContext.BaseDirectory = Path.GetDirectoryName(asm.Location) & Path.DirectorySeparatorChar).ToString())
        Console.WriteLine("-- My.Application.CommandLineArgs / Culture")
        Console.WriteLine("Args         : " & args.Length.ToString())
        Console.WriteLine("Culture      : " & CultureInfo.CurrentCulture.DisplayName & " / UI " & CultureInfo.CurrentUICulture.DisplayName)
        Console.WriteLine("-- My.Computer.Name / Info / Clock")
        Console.WriteLine("Machine name set: " & (Environment.MachineName.Length > 0).ToString())
        Console.WriteLine("OS           : " & RuntimeInformation.OSDescription)
        Console.WriteLine("Architecture : " & RuntimeInformation.OSArchitecture.ToString())
        Console.WriteLine("UTC offset   : " & TimeZoneInfo.Local.GetUtcOffset(Date.UtcNow).ToString())
        Console.WriteLine("Tick count   : " & (Environment.TickCount64 > 0).ToString())
        Console.WriteLine("-- My.Computer.Network")
        Console.WriteLine("IsAvailable  : " & NetworkInterface.GetIsNetworkAvailable().ToString())
        Console.WriteLine("-- My.User")
        Console.WriteLine("User name    : " & Environment.UserName)
        Console.WriteLine("-- My.Computer.Registry / Clipboard / Audio")
        Console.WriteLine("Windows only : " & OperatingSystem.IsWindows().ToString())
        Console.WriteLine("-- My.Computer.FileSystem.SpecialDirectories")
        Console.WriteLine("Temp         : " & Path.GetTempPath())
        Console.WriteLine("MyDocuments  : " & Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments))
        Console.WriteLine("AppData      : " & Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData))
    End Sub
End Module

Run as dotnet run — one two in the .NET 10 container (the container’s current culture is the invariant culture, and it has no Documents folder, which is why those values are empty):

-- My.Application.Info
AssemblyName : ShelfApp
Version      : 1.2.0.0
Title        : Shelf catalogue
Company      : Shelf Club
ProductName  : Shelf
Description  : A small library catalogue
Copyright    : Copyright 2026 Shelf Club
Info. version: 1.2.0
DirectoryPath: True
-- My.Application.CommandLineArgs / Culture
Args         : 2
Culture      : Invariant Language (Invariant Country) / UI Invariant Language (Invariant Country)
-- My.Computer.Name / Info / Clock
Machine name set: True
OS           : Ubuntu 24.04.5 LTS
Architecture : Arm64
UTC offset   : 00:00:00
Tick count   : True
-- My.Computer.Network
IsAvailable  : True
-- My.User
User name    : root
-- My.Computer.Registry / Clipboard / Audio
Windows only : False
-- My.Computer.FileSystem.SpecialDirectories
Temp         : /tmp/
MyDocuments  :
AppData      :

The mapping from a My expression to its replacement is collected in the table below the sections on each object (see "Replacements outside a Windows project").

The Application Framework

In a WindowsForms project My.Application also is the Windows Forms Application Framework. Its options are set in the constructor of MyApplication, and its life cycle is exposed as events. Visual Studio writes the options into a designer file (Application.Designer.vb) that you edit through the project’s Application page. On .NET with no designer you can write the same constructor yourself; an explicit Sub New replaces the one the compiler generates, and the build above shows that it compiles without a duplicate-definition error.

Option (protected property) Effect

IsSingleInstance

when True, a second start-up hands its command line to the first instance (the StartupNextInstance event) and exits

EnableVisualStyles

calls Application.EnableVisualStyles before the first form is created

SaveMySettingsOnExit

calls My.Settings.Save() when the application ends

ShutdownStyle

ShutdownMode.AfterMainFormCloses (the default) or ShutdownMode.AfterAllFormsClose

MinimumSplashScreenDisplayTime

milliseconds that a splash screen stays visible

AuthenticationMode (constructor argument)

Windows makes My.User use the Windows identity, ApplicationDefined leaves My.User to your own principal

Event When it is raised

ApplyApplicationDefaults

before the first form is created; its ApplyApplicationDefaultsEventArgs lets you set Font, HighDpiMode, ColorMode and MinimumSplashScreenDisplayTime for the whole application. It is the .NET replacement for the old project-page options

Startup

after the framework is initialised, before the main form; set e.Cancel = True to stop the start-up; e.CommandLine has the arguments

StartupNextInstance

a second instance was started (needs IsSingleInstance); e.CommandLine and e.BringToForeground

UnhandledException

an exception reached the top of the UI thread; e.ExitApplication decides whether the program ends

NetworkAvailabilityChanged

the network came up or went down; e.IsNetworkAvailable

Shutdown

after the main form closed, before the process ends

The complete Windows tour project that is used in the rest of this page (built, not run; EnableWindowsTargeting was on, the container is Linux) has this project file:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>WinExe</OutputType>
    <TargetFramework>net10.0-windows</TargetFramework>
    <UseWindowsForms>true</UseWindowsForms>
    <EnableWindowsTargeting>true</EnableWindowsTargeting>
    <RootNamespace>ShelfDesktop</RootNamespace>
    <MyType>WindowsForms</MyType>
    <OptionStrict>On</OptionStrict>
    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
    <NuGetAudit>false</NuGetAudit>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="System.Configuration.ConfigurationManager" Version="10.0.0" />
  </ItemGroup>
</Project>

and this MyApplication.vb. The class is declared in Namespace My with the same name that the compiler uses, so the two parts merge:

Option Strict On

Imports System.Drawing
Imports System.Windows.Forms
Imports Microsoft.VisualBasic.ApplicationServices
Imports Microsoft.VisualBasic.Logging

Namespace My
    Partial Friend Class MyApplication
        ' The Application Framework options. Visual Studio writes the same lines into
        ' Application.Designer.vb; on .NET an explicit constructor replaces the generated one.
        Public Sub New()
            MyBase.New(AuthenticationMode.Windows)
            IsSingleInstance = True
            EnableVisualStyles = True
            SaveMySettingsOnExit = True
            ShutdownStyle = ShutdownMode.AfterMainFormCloses
        End Sub

        Protected Overrides Sub OnCreateMainForm()
            MainForm = My.Forms.MainForm
        End Sub

        Private Sub MyApplication_ApplyApplicationDefaults(sender As Object, e As ApplyApplicationDefaultsEventArgs) Handles Me.ApplyApplicationDefaults
            e.Font = New Font("Segoe UI", 10.0F)
            e.HighDpiMode = HighDpiMode.SystemAware
            e.MinimumSplashScreenDisplayTime = 0
            e.ColorMode = SystemColorMode.System
        End Sub

        Private Sub MyApplication_Startup(sender As Object, e As StartupEventArgs) Handles Me.Startup
            Log.DefaultFileLogWriter.Location = LogFileLocation.ExecutableDirectory
            Log.WriteEntry("Started with " & e.CommandLine.Count.ToString() & " argument(s)", TraceEventType.Information)
            If e.CommandLine.Contains("--reset") Then My.Settings.Reset()
        End Sub

        Private Sub MyApplication_StartupNextInstance(sender As Object, e As StartupNextInstanceEventArgs) Handles Me.StartupNextInstance
            e.BringToForeground = True
            Log.WriteEntry("Second instance with " & e.CommandLine.Count.ToString() & " argument(s)")
        End Sub

        Private Sub MyApplication_UnhandledException(sender As Object, e As UnhandledExceptionEventArgs) Handles Me.UnhandledException
            Log.WriteException(e.Exception, TraceEventType.Critical, "Unhandled")
            MessageBox.Show(e.Exception.Message, Info.Title, MessageBoxButtons.OK, MessageBoxIcon.Error)
            e.ExitApplication = False
        End Sub

        Private Sub MyApplication_NetworkAvailabilityChanged(sender As Object, e As Microsoft.VisualBasic.Devices.NetworkAvailableEventArgs) Handles Me.NetworkAvailabilityChanged
            Log.WriteEntry("Network available: " & e.IsNetworkAvailable.ToString())
        End Sub

        Private Sub MyApplication_Shutdown(sender As Object, e As EventArgs) Handles Me.Shutdown
            Log.WriteEntry("Shutdown")
        End Sub
    End Class
End Namespace

Built, not run. Notes on the listing:

  • Handles Me.Startup works because MyApplication inherits WindowsFormsApplicationBase; in a Console project the base class has no such events.

  • The Startup handler resets the settings when --reset is on the command line, which is a common use of e.CommandLine.

  • OnCreateMainForm sets MainForm to the default instance My.Forms.MainForm. A project that has no Sub Main must set it, or the framework has no form to run and raises NoStartupFormException (a type in the Forms assembly).

  • UnhandledException is the framework’s safety net for the UI thread only. Exceptions on other threads or in async Sub handlers do not arrive here; see Windows Forms Applications for the other handlers.

  • ColorMode = SystemColorMode.System compiled without an experimental-API diagnostic on this SDK; the dark-mode behaviour itself should be checked on a real machine.

Logging with My.Application.Log

My.Application.Log wraps a TraceSource with a default FileLogTraceListener. WriteEntry(message, severity) and WriteException(ex, severity, details) write lines with a timestamp and the severity; the listener has Location (for example LogFileLocation.ExecutableDirectory, the Startup handler above sets it), BaseFileName, Append, AutoFlush, MaxFileSize, ReserveDiskSpace, LogFileCreationSchedule and DiskSpaceExhaustedBehavior. It is a file logger only; for an application with structured logs and levels, use Microsoft.Extensions.Logging (see Debugging and Diagnostics). My.Log for ASP.NET (AspLog) does not exist on .NET.

My.Computer

My.Computer is the machine. Each child is a different small class; the table lists the child, its members as read from the reference assembly, and the cross-platform replacement for use in a console project or a library.

Object Members (from the reference assembly) Replacement without My

Name

computer name

Environment.MachineName

Info (ComputerInfo)

AvailablePhysicalMemory, AvailableVirtualMemory, InstalledUICulture, OSFullName, OSPlatform, OSVersion, TotalPhysicalMemory, TotalVirtualMemory

RuntimeInformation.OSDescription, RuntimeInformation.OSArchitecture, GC.GetGCMemoryInfo() for memory figures

Clock

GmtTime, LocalTime, TickCount

DateTime.UtcNow, DateTime.Now, Environment.TickCount64; inject TimeProvider for tests (see Dates, Times and Formatting)

FileSystem (FileSystemProxy)

CopyDirectory, CopyFile, CreateDirectory, DeleteDirectory, DeleteFile, DirectoryExists, FileExists, FindInFiles, GetDirectories, GetFiles, GetFileInfo, GetDriveInfo, MoveDirectory, MoveFile, OpenTextFieldParser, OpenTextFileReader, OpenTextFileWriter, ReadAllBytes, ReadAllText, RenameDirectory, RenameFile, WriteAllBytes, WriteAllText, CombinePath, GetName, GetParentPath, SpecialDirectories, CurrentDirectory, Drives

Microsoft.VisualBasic.FileIO.FileSystem (same methods, any platform), or System.IO

Network

DownloadFile, UploadFile, Ping, IsAvailable, NetworkAvailabilityChanged

HttpClient (see Web, HTTP and Services), System.Net.NetworkInformation.Ping, NetworkInterface.GetIsNetworkAvailable()

Registry (RegistryProxy)

ClassesRoot, CurrentConfig, CurrentUser, LocalMachine, PerformanceData, Users, GetValue, SetValue

Microsoft.Win32.Registry (Windows only), guarded with OperatingSystem.IsWindows()

Clipboard (ClipboardProxy)

Clear, ContainsText, ContainsImage, ContainsAudio, ContainsFileDropList, ContainsData, GetText, GetImage, GetAudioStream, GetFileDropList, GetData, GetDataObject, SetText, SetImage, SetAudio, SetFileDropList, SetData, SetDataAsJson, SetDataObject, TryGetData

System.Windows.Forms.Clipboard or System.Windows.Clipboard (WPF)

Audio

Play, PlaySystemSound, Stop

System.Media.SoundPlayer, System.Media.SystemSounds (Windows)

Keyboard

AltKeyDown, CapsLock, CtrlKeyDown, NumLock, ScrollLock, ShiftKeyDown, SendKeys

Control.ModifierKeys, Keyboard.Modifiers (WPF), Control.IsKeyLocked

Mouse

ButtonsSwapped, WheelExists, WheelScrollLines

SystemInformation (Windows Forms), SystemParameters (WPF)

Screen

the primary System.Windows.Forms.Screen

Screen.PrimaryScreen, Screen.AllScreens

Ports

does not exist on .NET

System.IO.Ports.SerialPort

Two points are easy to miss. Network.DownloadFile and UploadFile are the older, user-interface-oriented download API; new code should use HttpClient. And FileSystem is the only part of My.Computer that a console program can use through a public type: Microsoft.VisualBasic.FileIO.FileSystem is the same code. The program below drives it on Linux:

Option Strict On

Imports Microsoft.VisualBasic.FileIO

Module FileSystemDemo
    Sub Main()
        Dim root As String = IO.Path.Combine(IO.Path.GetTempPath(), "shelf-fs-demo")
        If FileSystem.DirectoryExists(root) Then FileSystem.DeleteDirectory(root, DeleteDirectoryOption.DeleteAllContents)
        FileSystem.CreateDirectory(IO.Path.Combine(root, "notes", "archive"))

        Dim notes As String = FileSystem.CombinePath(root, "notes")
        Dim dune As String = FileSystem.CombinePath(notes, "dune.txt")
        FileSystem.WriteAllText(dune, "Dune, Herbert" & vbLf, False)
        FileSystem.WriteAllText(dune, "Arrakis" & vbLf, True)
        FileSystem.WriteAllText(FileSystem.CombinePath(FileSystem.CombinePath(notes, "archive"), "emma.txt"), "Emma, Austen" & vbLf, False)

        Console.WriteLine("-- ReadAllText")
        Console.Write(FileSystem.ReadAllText(dune))

        Console.WriteLine("-- GetFiles (all sub-directories, *.txt)")
        For Each f In FileSystem.GetFiles(root, SearchOption.SearchAllSubDirectories, "*.txt").OrderBy(Function(x) x)
            Console.WriteLine(IO.Path.GetRelativePath(root, f))
        Next

        Console.WriteLine("-- FindInFiles")
        For Each f In FileSystem.FindInFiles(root, "Austen", True, SearchOption.SearchAllSubDirectories)
            Console.WriteLine(IO.Path.GetRelativePath(root, f))
        Next

        Console.WriteLine("-- CopyDirectory and GetParentPath")
        Dim backup As String = FileSystem.CombinePath(root, "backup")
        FileSystem.CopyDirectory(notes, backup)
        Console.WriteLine(FileSystem.GetFiles(backup).Count.ToString() & " file(s) in backup")
        Console.WriteLine(IO.Path.GetRelativePath(root, FileSystem.GetParentPath(FileSystem.CombinePath(backup, "dune.txt"))))

        Console.WriteLine("-- DeleteDirectory")
        FileSystem.DeleteDirectory(root, DeleteDirectoryOption.DeleteAllContents)
        Console.WriteLine("exists after delete: " & FileSystem.DirectoryExists(root).ToString())
    End Sub
End Module
-- ReadAllText
Dune, Herbert
Arrakis
-- GetFiles (all sub-directories, *.txt)
notes/archive/emma.txt
notes/dune.txt
-- FindInFiles
notes/archive/emma.txt
-- CopyDirectory and GetParentPath
1 file(s) in backup
backup
-- DeleteDirectory
exists after delete: False

Notes: CombinePath takes exactly two arguments (a three-argument call is BC30057), the search methods take the SearchOption before the patterns, FindInFiles takes (directory, text, ignoreCase, searchOption). The calls that show dialogs and recycle-bin deletes (UIOption.AllDialogs, RecycleOption.SendToRecycleBin) are Windows behaviour and belong to Files, Directories and Streams.

Extending My.Computer

Because the generated MyComputer is Partial, you can add members to My.Computer. The example below (part of the Windows tour, built, not run) adds a ShelfFolder property that creates and returns a per-user data folder. It uses the inherited FileSystem and SpecialDirectories children:

Option Strict On

Imports System.IO

Namespace My
    ' MyComputer is generated as a partial class, so a second part can add members to My.Computer
    Partial Friend Class MyComputer
        Public ReadOnly Property ShelfFolder As String
            Get
                Dim folder As String = Path.Combine(FileSystem.SpecialDirectories.CurrentUserApplicationData, "Shelf")
                FileSystem.CreateDirectory(folder)
                Return folder
            End Get
        End Property
    End Class
End Namespace

My.User

My.User is a Microsoft.VisualBasic.ApplicationServices.User with Name, IsAuthenticated, IsInRole(role) and CurrentPrincipal. With AuthenticationMode.Windows (the default of the generated constructor) the principal is the Windows identity, so Name is DOMAIN\user; with ApplicationDefined you assign CurrentPrincipal yourself, which is how a program with its own log-in uses it. IsInRole("BUILTIN\Administrators") tests Windows group membership; the BuiltInRole enumeration of .NET Framework is not in the .NET assembly (the reference listing above has no such type), so pass the group name as a string. In a console program the replacement is Environment.UserName, or System.Security.Principal.WindowsIdentity.GetCurrent() on Windows.

My.Settings

My.Settings gives typed, persisted settings. It rests on System.Configuration.ApplicationSettingsBase from the System.Configuration.ConfigurationManager package, and the Visual Studio Settings designer writes the class you see below. Two scopes exist:

Scope Attribute Behaviour

User

UserScopedSetting

read and write; saved with Save() to a user.config file in the user’s profile; each user has their own value

Application

ApplicationScopedSetting

read-only at run time; the default comes from the application’s .config file next to the program; shared by all users

The class and the My.Settings property are ordinary code (the settings designer generates exactly this shape; the property is a module in Namespace My, which is how a member is added to My). Written by hand, it works in a console program too, because only the System.Configuration.ConfigurationManager package is needed. The program writes a user setting and reads it back in the next process:

Option Strict On

Imports System.Configuration

Namespace My
    <Global.System.Runtime.CompilerServices.CompilerGenerated()>
    Partial Friend NotInheritable Class MySettings
        Inherits ApplicationSettingsBase

        Private Shared ReadOnly defaultInstance As MySettings =
            CType(Synchronized(New MySettings()), MySettings)

        Public Shared ReadOnly Property [Default] As MySettings
            Get
                Return defaultInstance
            End Get
        End Property

        <UserScopedSetting()>
        <DefaultSettingValue("20")>
        Public Property PageSize As Integer
            Get
                Return CInt(Me("PageSize"))
            End Get
            Set(value As Integer)
                Me("PageSize") = value
            End Set
        End Property

        <ApplicationScopedSetting()>
        <DefaultSettingValue("shelf.db")>
        Public ReadOnly Property DatabaseFile As String
            Get
                Return CStr(Me("DatabaseFile"))
            End Get
        End Property
    End Class

    <Global.Microsoft.VisualBasic.HideModuleName()>
    Friend Module MySettingsProperty
        Friend ReadOnly Property Settings As MySettings
            Get
                Return MySettings.Default
            End Get
        End Property
    End Module
End Namespace

Module SettingsDemo
    Sub Main()
        Console.WriteLine("PageSize (default)  : " & My.Settings.PageSize.ToString())
        Console.WriteLine("DatabaseFile        : " & My.Settings.DatabaseFile)
        My.Settings.PageSize = 50
        My.Settings.Save()
        Dim cfg As Configuration = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.PerUserRoamingAndLocal)
        Console.WriteLine("user file exists    : " & IO.File.Exists(cfg.FilePath).ToString())
        Console.WriteLine("user file path      : " & cfg.FilePath)
        My.Settings.Reload()
        Console.WriteLine("PageSize (reloaded) : " & My.Settings.PageSize.ToString())
    End Sub
End Module

Run twice in the same container (the project sets Version, Company and AssemblyTitle as above; the long folder name contains a hash that identifies the program, and /root is the container’s home):

--- first run
PageSize (default)  : 20
DatabaseFile        : shelf.db
user file exists    : True
user file path      : /root/.local/share/Shelf_Club/ShelfApp_Url_jgfpubpizyjaxpv0hqug1xdjy2ec1pco/1.2.0.0/user.config
PageSize (reloaded) : 50
--- second run
PageSize (default)  : 50
DatabaseFile        : shelf.db
user file exists    : True
user file path      : /root/.local/share/Shelf_Club/ShelfApp_Url_jgfpubpizyjaxpv0hqug1xdjy2ec1pco/1.2.0.0/user.config
PageSize (reloaded) : 50

What the output shows and what to remember:

  • The first run starts with the default 20 from DefaultSettingValue, saves 50, and the second process starts with 50. The value is stored per company, product-and-path hash and version (1.2.0.0 in the path): a new assembly version starts with the defaults unless you call My.Settings.Upgrade() (guard it with an UpgradeRequired setting, the usual pattern).

  • Save() is explicit. In a Windows Forms project SaveMySettingsOnExit = True (the generated default) saves when the application ends; a console program has no such hook, so call Save() yourself.

  • Reload() discards unsaved changes, Reset() restores the defaults.

  • An application-scoped setting is read-only. Assigning to it, a wrong type or a missing name are all compile-time errors with Option Strict On. With the module below (added after the MySettings class above):

Module SettingsDemo
    Sub Main()
        My.Settings.DatabaseFile = "other.db"
        My.Settings.PageSize = "many"
        My.Settings.Missing = 1
    End Sub
End Module

the compiler printed (line numbers count the class that precedes the module in the file):

Program.vb(51,9): error BC30526: Property 'DatabaseFile' is 'ReadOnly'.
Program.vb(52,32): error BC30512: Option Strict On disallows implicit conversions from 'String' to 'Integer'.
Program.vb(53,9): error BC30456: 'Missing' is not a member of 'MySettings'.
  • The settings file is XML that is not meant to be shared, signed or secret: do not store passwords or tokens in it. See Security and Cryptography.

  • For new .NET code that is not Windows Forms, the usual alternatives are appsettings.json with Microsoft.Extensions.Configuration (read-only, layered, environment-aware) for configuration, and a small JSON file (see Serialization: JSON and XML) written to Environment.SpecialFolder.ApplicationData for user preferences.

My.Resources

My.Resources exposes the entries of the project’s Resources.resx as typed properties. As with settings, the property group is a module in Namespace My.Resources, which the Resources designer (a custom tool) generates; the compiler does not. The module below has the same shape as the generated file, and the .resx files next to it are compiled into the assembly by the SDK (the default file Resources.resx and the Spanish satellite Resources.es.resx). The resource name is the root namespace plus the file name, ShelfApp.Resources:

Option Strict On

Imports System.Globalization
Imports System.Resources

Namespace My.Resources
    ' The same shape as the file that Visual Studio generates for a project's Resources.resx
    <Global.Microsoft.VisualBasic.HideModuleName()>
    Friend Module Resources
        Private ReadOnly manager As New ResourceManager("ShelfApp.Resources", GetType(Resources).Assembly)

        Friend ReadOnly Property ResourceManager As ResourceManager
            Get
                Return manager
            End Get
        End Property

        Friend ReadOnly Property Greeting As String
            Get
                Return manager.GetString("Greeting", CultureInfo.CurrentUICulture)
            End Get
        End Property

        Friend ReadOnly Property BookCount As String
            Get
                Return manager.GetString("BookCount", CultureInfo.CurrentUICulture)
            End Get
        End Property
    End Module
End Namespace

Module ResourcesDemo
    Sub Main()
        Console.WriteLine(My.Resources.Greeting)
        Console.WriteLine(String.Format(My.Resources.BookCount, 2))

        CultureInfo.CurrentUICulture = New CultureInfo("es")
        Console.WriteLine(My.Resources.Greeting)
        Console.WriteLine(String.Format(My.Resources.BookCount, 2))
    End Sub
End Module
Welcome to the shelf
2 books on the shelf
Bienvenido a la estanteria
2 books on the shelf

The second Greeting comes from the satellite resource for es, and BookCount falls back to the neutral resource because the Spanish file does not define it, which is the normal resource fallback. Typed properties exist for strings, images (System.Drawing.Bitmap), icons, byte arrays and streams. Remember that CurrentUICulture (not CurrentCulture) selects the satellite assembly.

My.Forms and default instances

In a Windows Forms project My.Forms has a property for each form, and Visual Basic lets you use the class name as that property: BookForm.Show() means My.Forms.BookForm.Show(). This is the default instance. The form is created on first use, and a new one is created after it has been closed and disposed. The rule of the compiler is: when a name denotes a class that has a default instance and it is used where an instance is required, it is replaced by the My.Forms property.

It exists to ease migration from VB6, where Form1.Show worked without creating a form. Its costs are the usual ones of hidden global state: two parts of the program talk to the same hidden object, there is one instance per thread, Me is not always what you expect when the form is also created with New, and unit tests cannot replace it. Prefer creating forms with New BookForm() and passing them where they are needed. The compiler does not generate default instances for classes that are not forms.

When the project type has no MyForms, using the class name as an instance is an ordinary error. In a project with MyType=Windows the program below

Option Strict On

Imports System.Windows.Forms

Public Class BookForm
    Inherits Form
End Class

Module Program
    Sub Main()
        BookForm.Show()
        My.Forms.BookForm.Show()
    End Sub
End Module

does not compile:

Program.vb(11,9): error BC30469: Reference to a non-shared member requires an object reference.
Program.vb(12,9): error BC30456: 'Forms' is not a member of 'ShelfDesktop.My'.

In the Windows tour project the main form is shown with MainForm = My.Forms.MainForm and the second form with BookForm.Show(); both appear in the listings below. WPF projects have no form default instances; My.Forms is a Windows Forms concept.

Unsupported on .NET

  • My.WebServices. The class is generated, but there is no ASMX/WCF proxy generator that fills it on .NET. Use HttpClient or a generated gRPC/OpenAPI client.

  • My.Request, My.Response, My.Log (ASP.NET) belong to MyType=Web and System.Web; they do not exist on .NET. In ASP.NET Core use HttpContext and ILogger. See Web, HTTP and Services.

  • My.Computer.Ports does not exist (see above).

  • MyType=Web does not compile (BC30002 for WebUser, AspLog and HttpRequest).

  • Windows-only members of the supported objects: everything in the Forms assembly runs on Windows only; My.Computer.Registry, Audio, Keyboard, Mouse, Screen and Clipboard depend on Windows Forms. A program that must also run on Linux or macOS should not use My.* at all, and uses the replacements in the next section.

Replacements outside a Windows project

The program in "My.Application" printed the replacements for Info, Culture, Name, Info, Clock, Network, User and the special directories. In summary:

My expression Replacement that works in any project

My.Application.Info.Version

Assembly.GetEntryAssembly().GetName().Version

My.Application.Info.Title, .CompanyName, .ProductName, .Description, .Copyright

GetCustomAttribute(Of AssemblyTitleAttribute)() and the matching Assembly...Attribute classes

My.Application.Info.DirectoryPath

AppContext.BaseDirectory

My.Application.CommandLineArgs

the args parameter of Sub Main(args As String()), or Environment.GetCommandLineArgs()

My.Application.Culture / UICulture

CultureInfo.CurrentCulture / CurrentUICulture

My.Application.Log

Microsoft.Extensions.Logging, TraceSource

My.Computer.Name

Environment.MachineName

My.Computer.Info.OSFullName

RuntimeInformation.OSDescription

My.Computer.Clock.LocalTime / GmtTime

DateTime.Now / DateTime.UtcNow (or an injected TimeProvider)

My.Computer.FileSystem.*

Microsoft.VisualBasic.FileIO.FileSystem or System.IO.File, Directory, Path

My.Computer.FileSystem.SpecialDirectories.Temp

Path.GetTempPath()

My.Computer.FileSystem.SpecialDirectories.MyDocuments

Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)

My.Computer.Network.IsAvailable

NetworkInterface.GetIsNetworkAvailable()

My.User.Name

Environment.UserName

My.Settings

your own ApplicationSettingsBase class as above, or JSON/IConfiguration

My.Resources

a ResourceManager, or Assembly.GetManifestResourceStream for files

MsgBox and InputBox need Windows Forms

MsgBox and InputBox are functions of the runtime library (Microsoft.VisualBasic.Interaction), not of My, but they are reached for in the same programs. They compile in any project, and calling them fails unless Windows Forms is available, because they show a Windows Forms dialog. Some neighbouring functions are Windows-only in a different way: the compiler’s platform analyzer (CA1416) flags Beep, GetSetting, SaveSetting, StrConv, Dir, Rename and others (which are annotated as supported on Windows only), and with warnings as errors the build fails.

The program below calls them from a console program on Linux. CA1416 is turned off in this one project with <NoWarn>$(NoWarn);CA1416</NoWarn>, because the point of the program is to show what happens at run time (without that line the build fails with error CA1416: This call site is reachable on all platforms. 'Public Overloads Sub Beep()' is only supported on: 'windows'. and the same for GetSetting and SaveSetting):

Option Strict On

Module DialogsDemo
    Private Sub Attempt(label As String, action As Action)
        Try
            action()
            Console.WriteLine(label & ": returned")
        Catch ex As Exception
            Console.WriteLine(label & ": " & ex.GetType().FullName & " - " & ex.Message)
        End Try
    End Sub

    Sub Main()
        Attempt("MsgBox", Sub() MsgBox("Saved", MsgBoxStyle.Information, "Shelf"))
        Attempt("InputBox", Sub() Console.WriteLine(InputBox("Title?", "Shelf", "Dune")))
        Attempt("Interaction.MsgBox", Sub() Interaction.MsgBox("Saved"))
        Attempt("Beep", Sub() Beep())
        Attempt("GetSetting", Sub() Console.WriteLine(GetSetting("Shelf", "Window", "Left", "0")))
        Attempt("SaveSetting", Sub() SaveSetting("Shelf", "Window", "Left", "10"))
    End Sub
End Module
MsgBox: System.PlatformNotSupportedException - Method requires System.Windows.Forms.
InputBox: System.PlatformNotSupportedException - Method requires System.Windows.Forms.
Interaction.MsgBox: System.PlatformNotSupportedException - Method requires System.Windows.Forms.
Beep: System.PlatformNotSupportedException - Operation is not supported on this platform.
GetSetting: System.NullReferenceException - Object reference not set to an instance of an object.
SaveSetting: System.NullReferenceException - Object reference not set to an instance of an object.

The failures differ: MsgBox and InputBox throw PlatformNotSupportedException with the text "Method requires System.Windows.Forms."; Beep throws PlatformNotSupportedException; GetSetting and SaveSetting throw NullReferenceException (they use the Windows registry, which is not present). The SaveSetting/GetSetting pair stores values under the registry key HKEY_CURRENT_USER\Software\VB and VBA Program Settings; use My.Settings or a JSON file in new code. In a console program ask the user with Console.ReadLine; see Console Applications. In a Windows Forms program prefer MessageBox.Show, which has the same buttons and icons. The mapping of MsgBoxStyle and MsgBoxResult values is in The Visual Basic Runtime Library.

Extending My with your own members

Any code in Namespace My of the project becomes part of My. The two usual forms are a module whose properties become My.X (as My.Settings and My.Resources do), and a partial class (MyApplication, MyComputer, MySettings) when the type already exists. A module needs HideModuleName so that IntelliSense offers My.Shelf and not the module name. The program below adds a My.Shelf service backed by a Lazy(Of T) and shows that it is an ordinary member:

Option Strict On

Namespace My
    ' Your own service, reachable as My.Shelf
    Friend NotInheritable Class ShelfService
        Private ReadOnly titles As New List(Of String) From {"Dune", "Emma"}

        Public ReadOnly Property Count As Integer
            Get
                Return titles.Count
            End Get
        End Property

        Public Sub Add(title As String)
            titles.Add(title)
        End Sub

        Public Function Latest() As String
            Return titles(titles.Count - 1)
        End Function
    End Class

    <Global.Microsoft.VisualBasic.HideModuleName()>
    Friend Module MyShelfExtension
        Private ReadOnly instance As New Lazy(Of ShelfService)(Function() New ShelfService())

        Friend ReadOnly Property Shelf As ShelfService
            Get
                Return instance.Value
            End Get
        End Property
    End Module
End Namespace

Module ExtendMyDemo
    Sub Main()
        My.Shelf.Add("Ulysses")
        Console.WriteLine("count  : " & My.Shelf.Count.ToString())
        Console.WriteLine("latest : " & My.Shelf.Latest())
        ' The module name is hidden from IntelliSense but is still a valid qualifier
        Console.WriteLine("same   : " & Object.ReferenceEquals(My.Shelf, My.MyShelfExtension.Shelf).ToString())
        Console.WriteLine("type   : " & My.Shelf.GetType().FullName)
        Console.WriteLine("namespace: " & GetType(My.ShelfService).Namespace)
    End Sub
End Module
count  : 3
latest : Ulysses
same   : True
type   : ShelfApp.My.ShelfService
namespace: ShelfApp.My

Rules and cautions, all of them checked above:

  • The program runs on a console project (MyType=Empty), so this is the way to get a My-style entry point everywhere.

  • HideModuleName only hides the module from IntelliSense; My.MyShelfExtension.Shelf is still valid and is the same object as My.Shelf.

  • The types sit in ShelfApp.My, the project’s root namespace plus My. A library that defines Namespace My does not export it to its consumers as their My: each project has its own.

  • A name that collides with a generated one (Application, Computer, User, Forms, Settings, Resources, WebServices) is an error in projects that generate it; give custom members distinctive names.

  • A per-thread instance, as ThreadSafeObjectProvider gives, is a deliberate choice; a Lazy(Of T) as above is shared by every thread, so the object must be thread-safe.

  • Treat My extensions as a convenience for the application project. Shared libraries should take their dependencies as parameters.

The Windows tour

The rest of the tour project ties the objects together. It is a Windows Forms program (built, not run), the same program of which MyApplication.vb and MyComputerExtension.vb were shown above. MySettings.vb is the settings class with an added System.Drawing.Point setting:

Option Strict On

Imports System.Configuration

Namespace My
    ' What the Settings designer generates: user-scoped settings are read/write and saved per user,
    ' application-scoped ones are read-only and come from the application's .config file
    <Global.System.Runtime.CompilerServices.CompilerGenerated()>
    Partial Friend NotInheritable Class MySettings
        Inherits ApplicationSettingsBase

        Private Shared ReadOnly defaultInstance As MySettings = CType(Synchronized(New MySettings()), MySettings)

        Public Shared ReadOnly Property [Default] As MySettings
            Get
                Return defaultInstance
            End Get
        End Property

        <UserScopedSetting()>
        <DefaultSettingValue("20")>
        Public Property PageSize As Integer
            Get
                Return CInt(Me("PageSize"))
            End Get
            Set(value As Integer)
                Me("PageSize") = value
            End Set
        End Property

        <UserScopedSetting()>
        <DefaultSettingValue("100, 100")>
        Public Property WindowLocation As Drawing.Point
            Get
                Return CType(Me("WindowLocation"), Drawing.Point)
            End Get
            Set(value As Drawing.Point)
                Me("WindowLocation") = value
            End Set
        End Property

        <ApplicationScopedSetting()>
        <DefaultSettingValue("shelf.db")>
        Public ReadOnly Property DatabaseFile As String
            Get
                Return CStr(Me("DatabaseFile"))
            End Get
        End Property
    End Class

    <Global.Microsoft.VisualBasic.HideModuleName()>
    Friend Module MySettingsProperty
        Friend ReadOnly Property Settings As MySettings
            Get
                Return MySettings.Default
            End Get
        End Property
    End Module
End Namespace

Resources.vb is the resources module (with the string resource of the Resources.resx shown earlier), and BookForm.vb is the second form that uses the file system, the resources and the default instance:

Option Strict On

Imports System.Globalization
Imports System.Resources

Namespace My.Resources
    <Global.Microsoft.VisualBasic.HideModuleName()>
    Friend Module Resources
        Private ReadOnly manager As New ResourceManager("ShelfDesktop.Resources", GetType(Resources).Assembly)

        Friend ReadOnly Property Greeting As String
            Get
                Return manager.GetString("Greeting", CultureInfo.CurrentUICulture)
            End Get
        End Property
    End Module
End Namespace
Option Strict On

Imports System.Windows.Forms

Public Class BookForm
    Inherits Form

    Public Sub New()
        Text = "Book"
        Dim path As String = My.Computer.FileSystem.CombinePath(My.Computer.ShelfFolder, "books.txt")
        If My.Computer.FileSystem.FileExists(path) Then Text = My.Computer.FileSystem.ReadAllText(path)
        Dim greeting As String = My.Resources.Greeting
        Text = greeting
    End Sub
End Class

and MainForm.vb is the main form, which touches the other objects of My.Computer:

Option Strict On

Imports System.Windows.Forms

Public Class MainForm
    Inherits Form

    Private WithEvents AboutButton As New Button() With {.Text = "About", .Dock = DockStyle.Top}
    Private WithEvents CopyButton As New Button() With {.Text = "Copy ISBN", .Dock = DockStyle.Top}
    Private WithEvents HelpButton2 As New Button() With {.Text = "Open second form", .Dock = DockStyle.Top}
    Private ReadOnly output As New TextBox() With {.Multiline = True, .Dock = DockStyle.Fill, .ReadOnly = True}

    Public Sub New()
        Controls.Add(output)
        Controls.Add(HelpButton2)
        Controls.Add(CopyButton)
        Controls.Add(AboutButton)
        Text = My.Application.Info.Title & " " & My.Application.Info.Version.ToString()
        Location = My.Settings.WindowLocation
        StartPosition = FormStartPosition.Manual
    End Sub

    Private Sub AboutButton_Click(sender As Object, e As EventArgs) Handles AboutButton.Click
        With My.Application.Info
            output.Text = .ProductName & " " & .Version.ToString() & " by " & .CompanyName & Environment.NewLine &
                .Copyright & Environment.NewLine &
                "Working set: " & .WorkingSet.ToString() & " bytes" & Environment.NewLine &
                "Loaded assemblies: " & .LoadedAssemblies.Count.ToString() & Environment.NewLine &
                "Directory: " & .DirectoryPath
        End With
        output.AppendText(Environment.NewLine & "Computer: " & My.Computer.Name &
                          " / " & My.Computer.Info.OSFullName & " " & My.Computer.Info.OSVersion &
                          Environment.NewLine & "RAM: " & (My.Computer.Info.TotalPhysicalMemory \ 1048576UL).ToString() & " MB" &
                          Environment.NewLine & "Screen: " & My.Computer.Screen.Bounds.Width.ToString() & "x" & My.Computer.Screen.Bounds.Height.ToString() &
                          Environment.NewLine & "User: " & My.User.Name & ", authenticated: " & My.User.IsAuthenticated.ToString() &
                          Environment.NewLine & "Admin: " & My.User.IsInRole("BUILTIN\Administrators").ToString() &
                          Environment.NewLine & "Now (local/UTC): " & My.Computer.Clock.LocalTime.ToString("s") & " / " & My.Computer.Clock.GmtTime.ToString("s") &
                          Environment.NewLine & "Network: " & My.Computer.Network.IsAvailable.ToString() &
                          Environment.NewLine & "Caps lock: " & My.Computer.Keyboard.CapsLock.ToString() &
                          Environment.NewLine & "Mouse wheel: " & My.Computer.Mouse.WheelExists.ToString() &
                          Environment.NewLine & "Culture: " & My.Application.Culture.Name & " / " & My.Application.UICulture.Name)
    End Sub

    Private Sub CopyButton_Click(sender As Object, e As EventArgs) Handles CopyButton.Click
        My.Computer.Clipboard.SetText("9780306406157")
        If My.Computer.Clipboard.ContainsText() Then output.Text = My.Computer.Clipboard.GetText()
    End Sub

    Private Sub HelpButton2_Click(sender As Object, e As EventArgs) Handles HelpButton2.Click
        ' Default instance: the class name acts as a variable that creates the form on first use
        BookForm.Show()
        ' The same object, spelled explicitly
        My.Forms.BookForm.Text = "Book (" & My.Settings.PageSize.ToString() & " per page)"
        My.Computer.Audio.PlaySystemSound(Media.SystemSounds.Asterisk)
    End Sub

    Protected Overrides Sub OnFormClosing(e As FormClosingEventArgs)
        My.Settings.WindowLocation = Location
        My.Settings.PageSize = 30
        My.Settings.Save()
        My.Computer.Registry.SetValue("HKEY_CURRENT_USER\Software\Shelf", "LastRun", Date.Now.ToString("s"))
        Dim last As Object = My.Computer.Registry.GetValue("HKEY_CURRENT_USER\Software\Shelf", "LastRun", "never")
        My.Application.Log.WriteEntry("Closing; last run " & CStr(last))
        MyBase.OnFormClosing(e)
    End Sub
End Class

All of it built with TreatWarningsAsErrors and no warning on the .NET 10 SDK; none of it was run because the container is Linux. Points worth noting in the listings:

  • My.Computer.Info.TotalPhysicalMemory is a ULong, so the division uses \ 1048576UL.

  • My.User.IsInRole("BUILTIN\Administrators") uses the group name because the enumeration overload is missing on .NET.

  • HelpButton2_Click creates the form through its default instance and then sets its title through My.Forms.BookForm: the same object, spelled two ways.

  • OnFormClosing saves the window position through My.Settings, writes the registry through My.Computer.Registry.SetValue with a full key path (the first argument starts with the hive name) and logs through My.Application.Log.

Differences from C# and from .NET Framework

  • C# has no My. The same functions are called as Microsoft.VisualBasic.FileIO.FileSystem, Microsoft.VisualBasic.Interaction and so on from C# when a reference to Microsoft.VisualBasic is added; the Application Framework, default instances and My.Settings have no C# counterpart (C# Windows Forms uses Application.Run(new MainForm()), Properties.Settings.Default and Properties.Resources). See Interop with C# and Other .NET Languages.

  • On .NET Framework every project type had My, MyType defaulted by project template, My.Computer.Ports and My.WebServices worked, and the designer pages of the project (Application, Settings, Resources) were the normal way to configure them. On .NET only the Windows Forms and WPF projects have a non-empty My.

  • My.Settings and My.Resources come from the project designer in Visual Studio; without the designer you write the two small files by hand, as shown.

Where the books are outdated

Older Visual Basic books and tutorials use My freely and assume that it is always there. Check these points before copying their code:

Book habit Today on .NET

My.Computer.FileSystem.ReadAllText("file.txt") in a console example

does not compile in a console project (BC30456); use File.ReadAllText or Microsoft.VisualBasic.FileIO.FileSystem

My.Computer.Ports.SerialPortNames

no Ports; use SerialPort.GetPortNames()

My.Settings.Save() in a console tool

needs the System.Configuration.ConfigurationManager package and a settings class; no designer, no SaveMySettingsOnExit

MsgBox("Hello") as the first program

a console program throws PlatformNotSupportedException; Console.WriteLine is the first program (see Getting Started)

InputBox for console input

throws on a console project; use Console.ReadLine

Form1.Show() in a freshly generated project

needs MyType=WindowsForms for the default instance; the template’s own Sub Main creates the form with New

My.Application.Info.DirectoryPath for resources

works only in MyType projects; AppContext.BaseDirectory works everywhere

My.Request, My.Response in Web Forms

ASP.NET Web Forms is .NET Framework only; see ASP.NET Web Forms

Error and warning reference

Diagnostic Meaning (messages are the compiler’s, shown above)

BC30456

'Computer' is not a member of 'ShelfApp.My' — the object is not generated for this MyType, or a custom member is misspelled

BC30002

Type 'Global.Microsoft.VisualBasic.Devices.Computer' is not defined — MyType asks for types of Microsoft.VisualBasic.Forms, which a plain net10.0 project does not reference

BC30469

Reference to a non-shared member requires an object reference — a form class name used as a default instance in a project without MyForms

BC30526

Property 'DatabaseFile' is 'ReadOnly' — an application-scoped setting was assigned

BC30512

Option Strict On disallows implicit conversions — a setting assigned a value of the wrong type

BC30057

Too many arguments — for example three arguments to FileSystem.CombinePath

CA1416

a runtime-library member is annotated as Windows-only and the call site is reachable on other platforms

Pitfalls checklist

  • Do not assume My exists: check the MyType of the project before using My.* in an answer, a library or a console tool.

  • My.Settings and My.Resources are not generated by the compiler; if they are missing, the designer files are missing.

  • My.Forms and default instances are per thread; touching a form from another thread through the default instance creates a second form.

  • Do not put secrets in user.config.

  • Settings are keyed by version and path: a new version starts with the defaults unless you upgrade.

  • A My extension in a library is private to the library’s own project.

  • Anything in Microsoft.VisualBasic.Forms is Windows-only, including Log and My.User.

  • Prefer explicit objects (a HttpClient, an ILogger, a form created with New) over My in code that has to be tested.