[Editor's Update - 1/20/2006: This article refers to a beta version of Visual Studio 2005. An updated version of the article, reflecting features found in the final release of Visual Studio 2005, can be found at Visual Basic: Navigate The .NET Framework And Your Projects With The My Namespace.]
Navigate the .NET Framework and Your Projects with "My"
This article was based on a pre-release version of Microsoft Visual Studio 2005, formerly code-named "Whidbey." All information contained herein is subject to change.
This article discusses:
|This article uses the following technologies:
Visual Basic 2005 and the .NET Framework
Code download available at:VB2005.exe(134 KB)
My.Computer and My.User
Exposing Settings, Resources, and More From Your Project
Iset out to write this article about Visual Basic® 2005, but that left too many things to choose from. I could wander through the entire feature list, giving you a bit of information on cool IDE features like Edit and Continue, IntelliSense® Code Snippets, or the Exception Assistant; skim over the advanced language enhancements like generics, partial classes, and unsigned types; and barely touch on all the cool Microsoft® .NET Framework enhancements around Windows® Forms, data binding, ClickOnce deployment, and more. While these are all interesting features, I'm going to dig into one of the coolest features of Visual Basic 2005, the namespace called My.
One of the biggest issues that programmers run into is the sheer breadth of .NET, which means that finding the best class for a particular task can be quite daunting. I have read many newsgroup postings from developers working very hard to call a Win32® API function from their Visual Basic .NET or C# code, when that exact function already exists in .NET. Why are they trying to call the API? They didn't find, notice, or perhaps understand how they could use existing parts of the Framework. My provides an intuitive navigation hierarchy that exposes existing .NET functionality through easily understood root objects, targeting the practical tasks and concepts that you grapple with on a regular basis.
Wow, that sounds great, but what does it mean? To quickly illustrate the benefit of My, consider a very common question from the forums on GotDotNet: "How do I read the entire contents of a text file into a string?" The answer for the .NET Framework 1.1 is this:
Dim sr As New IO.StreamReader("c:\mytextfile.txt") contents = sr.ReadToEnd sr.Close()
It doesn't require a lot of code, but it certainly isn't intuitive. For many people, the path to StreamReader would have led them through the Stream class, the FileStream class, and more before ending up with that code snippet. That exact same code will work just fine in Visual Basic 2005, but by using My I can get to the same information much more quickly by writing this:
contents = My.Computer.FileSystem.ReadAllText("c:\mytextfile.txt")
The My.Computer.FileSystem class is just one of many classes included in the My language extensions, so the first thing to do is get familiar with what is available.
My is best described as a speed-dial for the .NET Framework. This type of simplification—making it easier to find and execute the right operation—is a common practice in programming. When I run into a multistep process that will be used repeatedly by me or by my development team, I generally create a helper function. The helper function is usually just a simple call that takes in the parameters that matter for the most common usage and then performs the multistep process under the covers, smoothing the development process. Most software development shops build such helper functions, and it is quite a common practice to combine groups of them into some set of code snippets or form of shared library such as MyCompany.Utilities or Duncan.NetworkUtilities.
There is a lot of duplication of effort going on in the creation of these libraries though, as many functions would be useful to almost any development group. My takes this idea of helper functions to a whole new level because they include so much functionality and because they are being shipped with Visual Basic. Just think of it as a library full of productivity-enhancing code that you don't have to write.
My exposes several distinct classes which organize a variety of functions into one of seven general areas: My.Application, My.Computer, My.Forms, My.Resources, My.Settings, My.User, and My.WebServices.
In general, the classes within My provide easy access to information in one of two categories, either the underlying .NET Framework or elements of the current project. My.Application, My.Computer, and My.User are all focused on Framework functionality, while My.Forms, My.Resources, My.Settings, and My.WebServices all deal with the contents of your current project. As I walk through each of these classes, starting with those that are focused on the underlying Framework, I will provide quick samples along with information on the properties and classes they contain.
As I mentioned earlier, it can sometimes be difficult to find the exact functionality that you need when you're working with the .NET Framework, but finding it isn't the only issue you need to be aware of. In some particular circumstances, even after you have found the class you need, the specific steps and constructor parameters needed to get it ready can take several lines of code and can be difficult to understand. The My classes focused on the Framework (My.Application, My.Computer, and My.User) are designed to help you navigate directly to the class you need, and to set it up so that you are ready to do your work.
My.Application provides developers with an intuitive grouping of application information and services. Individual nodes under My.Application include AssemblyInfo (the application's copyright, title, description, and so on), OpenForms (a collection of all Forms currently open in the project), Log (a feature-rich, highly configurable logging facility that is integrated with the System.Diagnostics classes), and more.
Using the My.Application.Log class, logging exceptions is easier than it probably should be. How are developers supposed to feel like true code warriors when they can write code like this:
Dim winINIFile As String Try winINIFile = My.Computer.FileSystem.ReadText("c:\windows\wind.ini") Catch ex As IO.FileNotFoundException My.Application.Log.WriteException(ex, "Error Accessing INI File") End Try
One of the more common feature requests that have come out of discussions with users of Visual Basic 6.0 and earlier has been answered with the addition of the OpenForms collection. This collection, which was available through the keyword Forms in Visual Basic 6.0, provides you with an easy way to loop through all of the currently open forms in your application, without the hassle of maintaining your own global list, as shown here:
For Each f As Form In My.Application.OpenForms Debug.WriteLine(f.Text) f.WindowState = FormWindowState.Minimized Next
My.Computer and My.User
My.Computer allows you to navigate to services and data related to the host computer. The functionality in this class alone deserves its own article, but I'll discuss a few of the highlights.
The FileSystem classes provide a very simple API for working with and inquiring about files; this should banish any lingering yearning for the FileSystemObject library. The following code uses the FileSystem class to copy all of the pictures from the current user's My Pictures folder to a new folder (C:\Desktop Wallpaper), displaying a progress bar if the file copy takes more than a few moments to complete:
Dim myPics As String = _ My.Computer.FileSystem.SpecialFolders.MyPictures.Path My.Computer.FileSystem.CopyFolderContents( _ "C:\Desktop Wallpaper", myPics, False, True) MsgBox( My.Computer.FileSystem.GetFiles( _ myPics, "*.jpg", "*.bmp").Count)
To accomplish the same file copy in the .NET Framework 1.1 would require quite a bit more code (see Figure 1), and that is without including the ability to show a progress dialog, which you would have to create yourself.
Figure 1 Copying Files in the .NET Framework 1.1
Dim myPics As String = Environment.GetFolderPath( _ Environment.SpecialFolder.MyPictures) Dim pictureFiles As String() = IO.Directory.GetFiles(myPics) Dim targetDirectory As String = "C:\Desktop Wallpaper" Dim newPath As String Dim jpgAndbmpCount As Integer For Each pic As String In pictureFiles newPath = IO.Path.Combine(targetDirectory, pic) IO.File.Copy(IO.Path.Combine(myPics, pic), newPath, False) If IO.Path.GetExtension(pic) = "jpg" Or _ IO.Path.GetExtension(pic) = "bmp" Then jpgAndbmpCount += 1 End If Next MsgBox(jpgAndbmpCount)
My.Computer.Ports (which is not available in the PDC preview of Visual Studio® 2005) turns reading and writing to a serial port into a simple process. This is one of the most common and difficult tasks to perform using the current version of the .NET Framework. The snippet shown here previously took an entire article to build! (See SERIAL COMM: Use P/Invoke to Develop a .NET Base Class Library for Serial Device Communications.)
Dim comport As IO.Ports.SerialPort comport = My.Computer.Ports.OpenSerialPort("COM1") AddHandler comport.ReceivedEvent, AddressOf DataReceived
The My.Computer.Audio class allows you to play user-defined or system sounds, putting an end to the practice of P/Invoking the PlaySound API, as shown here:
Dim musicFile As String musicFile = My.Computer.FileSystem. _ GetFiles("C:\WINDOWS\Media", "*.wav")(0).Path My.Computer.Audio.Play(musicFile)
My.Computer.Network makes a wide variety of networking calls easy to use, including receiving and sending Pings to a remote machine, uploading or downloading a file, determining if you are currently connected, and quite a bit more.
If My.Computer.Network.IsConnected Then If My.Computer.Network.Ping("www.duncanmackenzie.net") Then Debug.WriteLine("Site Available") My.Computer.Network.DownloadFile( _ "http://www.duncanmackenzie.net/Articles/", _ My.Computer.FileSystem.SpecialFolders.MyDocuments, _ ShowProgress:=True) End If End If
My.Computer.Printer works together with the new Printing classes in the Windows Forms namespace to make printing a cinch. As an example, producing the report shown in Figure 2 can be created with code familiar to those of you who've programmed with GDI+. Here are the first few lines of code:
With My.Computer.Printers.DefaultPrinter .HorizontalAlignment = HorizontalAlignment.Center .WriteLine("Document Title") .WriteImage(New Bitmap("z:\msdn-logo.gif")) .HorizontalAlignment = HorizontalAlignment.Left .Write("Company Name") .HorizontalAlignment = HorizontalAlignment.Right .WriteLine("Report Title") .WriteHorizontalLine(0.05) .WriteLine() •••
If you are wondering what's involved in producing the same type of report using version 1.1 of the Framework, you can check out my printing article on MSDN® Online at Printing Reports in Windows Forms.
Figure 2** Creating Reports with My **
There are quite a few more classes that I am not going to even start describing, including My.Computer.Keyboard, My.Computer.Registry, and My.Computer.Screen. I encourage you to explore these on your own.
There is so much functionality exposed through the My.Computer section of My that its object model is going to be one of the first bits of documentation I look at as each new beta and Community Drop of Visual Studio 2005 is released.
My.User is one of the simplest classes in My, but don't let its simplicity fool you; it provides access to quite a few useful bits of information about the current user of the app. This info includes properties such as DisplayName, UserName, and DomainName, along with methods for querying role membership, and status functions like IsAuthenticated:
If My.User.IsAuthenticated Then If My.User.IsInRole("BUILTIN\Administrators") Then MsgBox("tsk, tsk... running as Admin are we?") End If End If
Note that the My.User properties and methods use Windows authentication by default, but will work seamlessly with custom security infrastructures as well, keeping the coding model the same regardless of the type of authentication you use.
Exposing Settings, Resources, and More From Your Project
The project-focused classes in My include Settings, Resources, WebServices, and Forms. The first two deal with your project's associated data while the clearly named Forms and WebServices classes provide direct access to forms and Web services that you have added to your project.
Figure 3** Settings Designer **
Working through the IDE of Visual Studio 2005, you can set up a variety of resource elements and a strongly typed group of user or application-level settings for your application (through the designer interface shown in Figure 3).
Figure 4** Resource Editing **
In both cases, you have to configure the settings or resources before the corresponding classes will become available through My, but once they have been added to your project, the My.Resources and My.Settings classes (respectively) make it easy for you to interact with either type of information. The following routine retrieves and modifies the value of a stored user setting, then uses the My.Resources class to retrieve a localized string (created using the IDE tools shown in Figure 4) for use in a message box:
Dim lastRun As Date lastRun = My.Settings.LastRun My.Settings.LastRun = Now() Dim myMessage As String = _ String.Format(My.Resources.LastRunMessage, _ lastRun.ToShortDateString) MsgBox(myMessage)
In addition to the two areas just described, all of the forms in your project are available through My.Forms and any Web services you have referenced in your project are exposed through the My.WebServices class. For Web services, this means you have the option of referencing them directly without manually creating an instance. So, after adding a reference to the TemperatureService from xmethods.com, you can retrieve the current temperature using the following code:
Dim tempService As New net.xmethods.www.TemperatureService() MsgBox(tempService.getTemp("98052"))
This can be expressed more simply as:
My.Forms is different from the My.Application.OpenForms collection that I discussed earlier because My.Forms exposes a default instance of each of your Form classes, not the currently open instances of those classes. If you have a background in programming in Visual Basic 6.0 or earlier, then these default instances will be extremely useful to you as they enable you to show, hide, or otherwise access your forms using the Form's class name directly:
Private Sub showForm2_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles showForm2.Click My.Forms.Form2.Show() End Sub Private Sub updateForm2_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles updateForm2.Click My.Forms.Form2.Text = "Updated..." End Sub
This was standard behavior in Visual Basic before the release of the .NET Framework, and it will be a welcome restoration to developers who became familiar with that style of programming in Visual Basic 6.0.
My in Visual Basic 2005 provides a quick and easy method for accessing some of the deeper areas of functionality in the .NET Framework without preventing you from using the Framework directly in any way you choose. In addition to exposing Framework functionality, some areas of My, such as the Forms collection, bring back familiar and convenient programming concepts from earlier versions of Visual Basic. Try it out in the available builds of Visual Studio 2005, and I'm confident that you will find it useful.
Duncan Mackenzie is the Visual Basic and C# Content Strategist for MSDN Online, author of MSDN's Coding 4 Fun column and the author of a variety of books and articles on Visual Basic and .NET. You can contact Duncan at http://www.duncanmackenzie.net.