My 00000010 cents

Ponderings of a Runtime Dev

  • What reference on VB does someone who writes VB use?

    Do you ever wonder what reference a person who works on the VB product uses?  For myself, I love the work Francesco Balena did in his Programming Microsoft Visual Basic.NET book.  I got to meet Francesco while I was in Italy doing a VB tour.  I got the 2005 edition of his book (Programming Microsoft Visual Basic 2005:The Language) which is also fantastic.  The breadth and depth of his books make them one-stop shopping for me, in many cases.

    I also like to use Paul Vick's The Visual Basic .NET Programming Language.  Paul wrote our language spec and his book is another one that I keep in close reach.

  • More on extending the My Namespace

    I wrote an article  for Coding4Fun on extending the My namespace so that you can program the LEGO Mindstorm robots.  Whether you are actually interested in programming LEGO robots with the My namespace or not (it is actually pretty fun :-) it is another example of how you can go about extending the My namespace. 

  • Splash Screens in VB 2005

    One of the things we provided in the application model for VB is the ability to easily integrate a splash screen into your application.  We take care of displaying it, making sure it displays for at least some user specifiable period of time, and taking it down once your application's main form is ready to display.

    One of the things that throws people is how to set the minimum amount of time for the splash screen to display.  Admittedly, we have some work to do to make this easier. 

    For now, if you don't like the default two second minimum, you can specify your own minimum in milliseconds by overriding the OnInitialize method on the MyApplication class.  Here's how you do it (and note that all of this presupposes that you have the application model enabled in the first place):

    Go to the project designer by double-clicking the 'My Project' node in your solution.  Once you've specified which form is to be your splash screen, click the View Application Events button.  You'll see a MyApplication class inside the My namespace.  Go in that class and add an override to OnInitiliaze like this:

    Protected Overrides Function OnInitialize(ByVal commandLineArgs As System.Collections.ObjectModel.ReadOnlyCollection(Of String)) As Boolean
      Me.MinimumSplashScreenDisplayTime = 5000
      Return MyBase.OnInitialize(commandLineArgs)
    End Function

    Now the splash screen will stay up a minimum of five seconds.

    The splash screen displays early on in your applications startup.  The idea is to have that displaying until your main form is ready to display.  Then we take it down unless you've specified a minimum 'face time' that you want for your splash screen.  Once the minimum splash time expires we take the splash screen down.  Just set it to zero if you want it taken down automatically once your main form has completed loading.

    All of this exposes you to a variety of things going on behind the scenes.  Next time I'll write about the application model and what the sequence of events is when an app that uses the new application model starts up.

  • Single-Instance Console Apps

    A question was posted on a MSDN VB forum about how to get single-instance behavior in a Whidbey app when your startup object isn't a form.  The IDE application designer doesn't accommodate this scenario.  But you can get single-instance behavior in situations like this by writing against the application model base class yourself.

    Here's an example of a VB8 (Whidbey) console application that exhibits single-instance behavior:

    Option Explicit On
    Option Strict On

    Module Module1
        Sub Main(ByVal args() As String)
            Dim App As New Application
            App.Run(args) 'passing args in enables App.CommandLineArgs
        End Sub
    End Module

    Class Application
        Inherits Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase

        Sub New()
            'If you are setting your own custom principal instead of using
            'the windows principal, pass AuthenticationMode.ApplicationDefined
            'so we don't run it over in the ctor.  The default ctor puts the
            'windows principal on the main thread.
            MyBase.New()
            Me.IsSingleInstance = True 'Turns on the single-instance behavior
        End Sub

        Protected Overrides Sub OnRun()'Put your code that you'd have place in Main(), here.
            Console.WriteLine("Running as " & My.User.Name & ". Press a key to exit") 
            While Not System.Console.KeyAvailable
                DoEvents() 'pumps messages so StartupNextInstance() gets called
            End While
        End Sub

        Private Sub MyApplication_StartupNextInstance(ByVal sender As Object, _
            ByVal e As Microsoft.VisualBasic.ApplicationServices.StartupNextInstanceEventArgs) _ 
            Handles Me.StartupNextInstance
           
            MsgBox("An attempt to launch an additional instance was made.")
        End Sub
    End Class

    When you first run this app you'll get the message that it is running and it will just hang out waiting for a key press.  If you launch it again while the first instance is still running, the first instance will display the dialog about an attempt to launch another instance.  The subsequent attempt to launch will just return without launching a new instance.  You now have a single-instance console application.

    I am utilizing the single-instance behavior logic which lives in the Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase class.  Note that in the ctor for Application that I call MyBase.New() without any arguments.  This will result in the windows principal being put on the main thread.  My.User will then reflect the windows account that is running this app.  If you are setting your own custom principal, pass in AuthenticationMode.ApplicationDefined instead so that your principal doesn't get run over when the class initializes.

    I use Main() simply to create my application object and start it up.  I put my startup logic, i.e. the code that would traditionally be in Main(), inside Application.OnRun(). 

    You'll notice that I'm pumping events in OnRun().  Pumping events is only necessary if you want to use the application model events, such as StartupNextInstance().  WindowsApplicationBase uses the message pump to marshal events onto the main thread.  So if you aren't yielding control to windows you'll need to pump messages in your app if you want the app model events.  If you don't care about handling the application model events then you can safely ignore that part.

    Note that you also get access to the other application model events such as the Shutdown event.  You won't get the UnhandledException() event because it isn't getting hooked up.  Getting that to work is a subject for another post someday if there is interest in that.

    By the way, if you are curious you can see the code generated by the IDE for Windows Forms apps.  Just create a windows forms app, turn on single-instance in the application page of the project designer, turn on 'view all files' in the solution explorer, and then look at the hidden file Application.Designer.vb which is under the MyProject/Application.MyApp node.

  • Single-Instance Applications and C#

    In response to a question about C# and single-instance apps I thought I'd show how to create a single-instance app in C# using the VB app model class.  The VB app model class does the heavy lifting for a number of things, including single-instance behavior.  The model was designed by the VB team and consequently has the VB customer primarily in mind.  So the VB project designer does a lot of the leg work for you if you are building a VB windows forms app and makes it easy to configure, handle the app model events, etc.  C# doesn't natively support the application model but that doesn't mean you can't use C# to enjoy the benefits--it just means you have to do a bunch of stuff manually.  Here's a bare bones single-instance C# application.  I started with a new C# Windows forms app and replaced the contents of program.cs with the following (note that you'll also need a reference to Microsoft.VisualBasic.dll):

    using System;
    using System.Collections.Generic;
    using System.Windows.Forms;

    namespace WindowsApplication1
    {
        static class Program
        {
            /// <summary>
            /// The main entry point for the application.
            /// </summary>
            [STAThread]
            static void Main(string[] commandLine)
            {
                Application.SetCompatibleTextRenderingDefault(false);
                App myApp = new App();
                myApp.Run(commandLine);
            }
        }

        /// <summary>
        ///  We inherit from WindowsFormApplicationBase which contains the logic for the application model, including
        ///  the single-instance functionality.
        /// </summary>
        class App : Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase
        {
            public App()
            {
                this.IsSingleInstance = true; // makes this a single-instance app
                this.EnableVisualStyles = true; // C# windowsForms apps typically turn this on.  We'll do the same thing here.
                this.ShutdownStyle = Microsoft.VisualBasic.ApplicationServices.ShutdownMode.AfterMainFormCloses; // the vb app model supports two different shutdown styles.  We'll use this one for the sample.
            }

            /// <summary>
            /// This is how the application model learns what the main form is
            /// </summary>
            protected override void OnCreateMainForm()
            {
                this.MainForm = new Form1();
            }

            /// <summary>
            /// Gets called when subsequent application launches occur.  The subsequent app launch will result in this function getting called
            /// and then the subsequent instances will just exit.  You might use this method to open the requested doc, or whatever
            /// </summary>
            /// <param name="eventArgs"></param>
            protected override void OnStartupNextInstance(Microsoft.VisualBasic.ApplicationServices.StartupNextInstanceEventArgs eventArgs)
            {
                base.OnStartupNextInstance(eventArgs);
                System.Windows.Forms.MessageBox.Show("An attempt to launch another instance of this app was made");
            }
        }
    }

    In the code sample above I could have handled the myApp.StartupNextInstance event instead of overriding OnStartupNextInstance().  No biggy either way, I just went for the easy override here.  Whether you override or handle the event you'll get called on the main thread.  If you do override OnStartupNextInstance() you'll want to defer to the base class as in addition to firing the StartupNextInstance event it also sets the focus to your original instance.

    When you launch this app the first time you'll see Form1.  If you launch it again while the first instance is running you'll see the message about a subsequent instance being launched as OnStartupNextInstance() gets called.  The subsequent instance will just quietly exit while the original instance keeps running.

    You can get a feel for other things you can do with the app model by looking at how VB configures it.  Create a new VB windows app and go to the project designer via the solution explorer by double-clicking the "My Project" node.  If you show all files in the solution explorer, you can also examine the Application.Designer.VB file which is under the My Project / Application.myapp node.

    Legal blather: Use of included script samples are subject to the terms specified at http://www.microsoft.com/info/cpyright.htm

  • Single-Instance Applications

    So what's a Single-Instance application?  Imagine launching an application where additional attempts to launch the app while the first one is running doesn't actually launch a new instance of the app.  Instead the original instance of the app gets notified that another launch attempt occurred.  When we introduced an application model for Visual Basic in VB 2005, one of the things we wanted to do is make it drop-dead easy to create single-instance applications.

    It's easier to understand single-instance apps with an example.  I don't know for certain that Word is a single-instance app but it seems to behave like one.  If you crank up the task manager and launch Word you'll see WinWord.exe show up.  But if you launch it again while an instance of Word is already running, you won't see another WinWord.exe show up in the task manager.  You can see the memory footprint of Word go up but it only goes up a little.  I assume that is memory needed just for the new document.  How Word manages its single-instance behavior is frankly not something I know anything about so I'm only guessing at what it is doing based on watching the task manager.  But it has the tale-tale signs of a single-instance app.

    Single-Instance apps are useful in situations where you don't want to have multiple instances of the app running.  Maybe you can only have one running on the machine at any given time.  Or maybe you have a scenario where you have an app that can manage multiple documents.  In that case a single-instance app would provide a nice way to avoid loading multiple copies of your exe just to manage one more document.  Instead, the currently running app could just be told to load another document. Less memory consumption, faster subsequent document load times.  It's goodness.

    You can find code samples on the internet to create single-instance apps.  Previously you had to hunt down the code, wire it into your own startup code, and then decide whether it used a technique that you think is robust enough or secure enough for your purposes.  We decided we wanted to provide a robust/secure single-instance capability that you could just turn on by clicking on a checkbox.  This switch lives on the application page in the project designer under Windows application framework properties and is called:  Make single instance application.  That's a lot of intro for the issue I want to talk about.''

    One of the questions that comes up is: So how do we determine whether a subsequent instance of an application has launched?  Do we key off of the path where the app was launched from, or what?

    We don't key off of the path where the app was launched from.  Single-Instance apps have a single-instance application identity.   When a single-instance app launches, it checks to see if an app with the same identity is already running.  If it is, we call that app's StartupNextInstance() event (which will be raised on the main thread of the original instance) and pass it the command line.  The subsequent instance then just exits; leaving the original instance to decide what it wants to do about the fact that somebody tried to launch another instance of itself.  A common thing to do would be to examine the command line passed into the StartupNextInstance() event and try to load the document specified.

    What does this single-instance application identity look like?  It is comprised of the assembly guid and the assembly (not file) major and minor version number.  You can see the assembly guid and assembly version information by selecting the Assembly Information button on the application page in the project designer.  Taken together these three pieces of information identify the identity of the single-instance application.

    There are some ramifications from all of this.  Different versions of an application won't act as single instances against each other.  For instance, if you launch version 1.0 of Foo.exe, and then launch version 1.1 of Foo.exe, you won't get the single instance behavior.  You'll have two versions of foo.exe running.

    If you have two copies of foo.exe on the machine in c:\foo1 and c:\foo2, and then launch c:\foo1\foo.exe followed by c:\foo2\foo.exe, you will get single-instance behavior between the two.  That is, you'll only get one instance of foo.exe running, the one in c:\foo1\foo.exe.  Launching c:\foo2\foo.exe will simply raise the event on the first and then terminate.  The application startup directory is not part of the single-instance application identity so it has no bearing on whether an application thinks another instance of itself is already running.

    This means that you can't easily contrive a situation where c:\foo1\foo.exe only exhibits single instance behavior when foo.exe is launched from c:\foo1 instead of c:\foo2 merely because they are in different directories.  If you wanted c:\foo2\foo.exe to be considered a different app then c:\foo1\foo.exe, you'd have to differentiate the two foo.exes by either changing the assembly version number or assembly guid of one of them.

    Currently there is no user facing way of setting the single-instance identity.  In practice do people find that this is terribly limiting?


© 2009 Microsoft Corporation. All rights reserved. Terms of Use  |  Trademarks  |  Privacy Statement
Microsoft
Page view tracker