.NET Matters

Stream Decorator, Single-Instance Apps

Stephen Toub

Code download available at: NETMatters0509.exe (172 KB)
Browse the Code Online

Q I'm using a method from a third-party library that expects me to pass a Stream to it. I want to be able to trace that library's activities with my Stream in order to better understand some behavior in my application. Is there a way to do this?

Q I'm using a method from a third-party library that expects me to pass a Stream to it. I want to be able to trace that library's activities with my Stream in order to better understand some behavior in my application. Is there a way to do this?

A You have several options. The first and simplest option is to make use of the classic Decorator design pattern. A decorator is an object that has the same interface as another object it contains. In object-oriented terms, it is an object that has an "is-a" and a "has-a" relationship with a specific type. Consider the CryptoStream class in the System.Security.Cryptography namespace. CryptoStream derives from Stream (it "is-a" Stream), but it also accepts a Stream in its constructor and stores that Stream internally (it "has-a" stream); that underlying stream is where the encrypted data is stored. CryptoStream is a decorator.

A You have several options. The first and simplest option is to make use of the classic Decorator design pattern. A decorator is an object that has the same interface as another object it contains. In object-oriented terms, it is an object that has an "is-a" and a "has-a" relationship with a specific type. Consider the CryptoStream class in the System.Security.Cryptography namespace. CryptoStream derives from Stream (it "is-a" Stream), but it also accepts a Stream in its constructor and stores that Stream internally (it "has-a" stream); that underlying stream is where the encrypted data is stored. CryptoStream is a decorator.

You can implement your own Stream-derived decorator class that lets you intercept and monitor each and every call to the stream. An example implementation is shown in Figure 1. The InterceptStream class derives from Stream and overrides all of the methods to be intercepted and traced. It also has a constructor that accepts a Stream as a parameter and stores the specified stream to a private member variable. Each of the overridden methods delegates to the corresponding method on the stored stream, but first makes a call to a delegate with information about the invocation, including what method was called and what the parameters to that call were. One might use InterceptStream as follows:

void DisplayStreamCall(MethodBase method, params object [] arguments)
{
    Console.WriteLine(method.Name + ":");
    foreach(object arg in arguments) Console.Write("\t" + arg);
}
...
Stream s = ... // get the stream to be monitored
s = new InterceptStream(s, new InterceptStreamHandler(
    DisplayStreamCall));

This technique is useful for more than just debugging. For example, it is also useful for tracking progress in an application. Consider an application that uses a BinaryFormatter to deserialize a very large file. Passing an InterceptStream to the formatter instead of the original stream will let you keep track of how much of the target stream has been processed by the formatter, possibly using that information to update a progress bar.

Figure 1 Decorator Pattern with Stream

public delegate void InterceptStreamHandler(
    MethodBase method, params object[]arguments);

public class InterceptStream : Stream
{
    private Stream _stream;
    private InterceptStreamHandler _callback;

    public InterceptStream(Stream s, InterceptStreamHandler callback) 
    {
        if (s == null) throw new ArgumentNullException("s");
        if (callback == null) throw new ArgumentNullException("callback");
        _stream = s; 
        _callback = callback;
    }

    public override IAsyncResult BeginRead(byte[] buffer, int offset, 
        int count, AsyncCallback callback, object state)
    {
        _callback(MethodBase.GetCurrentMethod(), buffer, offset, 
            count, callback, state);
        return _stream.BeginRead (buffer, offset, count, callback, state);
    }

    public override IAsyncResult BeginWrite(byte[] buffer, int offset, 
        int count, AsyncCallback callback, object state)
    {
        _callback(MethodBase.GetCurrentMethod(), buffer, offset, 
            count, callback, state);
        return _stream.BeginWrite (buffer, offset, count, 
            callback, state);
    }

    public override bool CanRead 
    { 
        get 
        { 
            _callback(MethodBase.GetCurrentMethod());
            return _stream.CanRead; 
        }
    }

    ... // other overrides of methods and properties on Stream

    public override string ToString()
    {
        _callback(MethodBase.GetCurrentMethod());
        return _stream.ToString();
    }

    public override void Write(byte[] buffer, int offset, int count)
    {
        _callback(MethodBase.GetCurrentMethod(), buffer, offset, count);
        _stream.Write(buffer, offset, count);
    }

    public override void WriteByte(byte value)
    {
        _callback(MethodBase.GetCurrentMethod(), value);
        _stream.WriteByte(value);
    }
}

The decorator pattern is a useful and flexible approach, though it is only appropriate when the target type is an interface or is a non-sealed type whose methods you're interested in are virtual and can be overridden. This is the case with Stream. From the client's perspective, using a decorator Stream like InterceptStream won't change the resulting functionality as long as the third-party library is only using the Stream object through the interface provided by Stream. For example, you could run into problems if the library is explicitly checking the actual type of the Stream and is then making some decisions based on that information.

Consider a library that provides some general utility with the stream, but then also performs additional functionality if the stream is a NetworkStream. If you pass to that stream an InterceptStream that wraps a NetworkStream instead of just passing in that NetworkStream, when the library checks the type of the Stream, it'll find that it's an InterceptStream and won't perform the functionality it does specially for the NetworkStream.

There's another option that solves this problem at the expense of some efficiency, and believe it or not it's .NET remoting that comes the rescue. To understand this approach, you need at least a basic understanding of the .NET remoting infrastructure, specifically of proxies. When you access an object across a remoting boundary, you're actually accessing it through at least two proxies. These proxies take the calls you make and forward them on to the target, taking care of any work necessary to properly marshal the call to and the response from the target (based on whether the target is on a different machine, in a different process, in a different application domain, and so on).

The main proxy involved in this operation is one that derives from RealProxy, which lives in the System.Runtime.Remoting.Proxies namespace. This is the proxy that is responsible for actually routing the call information to the target. It is also used to obtain the other proxy, known as a transparent proxy. This proxy is generated for you by the runtime, and through a bit of trickery it has an interface that exactly matches that of the target type. When you hold a reference to a remote object, you're actually holding a reference to a transparent proxy. Information about any invocations on that proxy (be they method calls, property gets and sets, and even field accesses) are packaged up into an internal MessageData object and are passed along to the corresponding RealProxy. The RealProxy translates that MessageData into an IMessage (a public interface that resides in the System.Runtime.Remoting.Messaging namespace) which is then passed to the RealProxy's Invoke method and shuttled off to the target object as appropriate.

I mention all of this because you can actually create your own RealProxy-derived class and explicitly use it with your own objects, even if those objects live in the same application domain as each other. Consider implementing a RealProxy that traces any invocations before and after executing the calls on the actual target object. You could then create one of these proxies to wrap the target object, use the proxy's GetTransparentProxy method to get the corresponding transparent proxy, and then cast that transparent proxy to your target type. Instead of handing out the original reference to the type, you can hand out this proxy in its stead, and any calls through that proxy reference will be traced. While this may sound complicated, the code in Figure 2 is all that's needed to create the necessary proxies.

Figure 2 InterceptionProxy

public delegate void InterceptedMessageHandler(IMessage msg);

public class InterceptionProxy : RealProxy
{
    public static MarshalByRefObject Intercept(MarshalByRefObject target, 
        InterceptedMessageHandler pre, InterceptedMessageHandler post)
    {
        if (target == null) throw new ArgumentNullException("target");
        if (pre == null && post == null) return target;
        InterceptionProxy p = new InterceptionProxy(target, pre, post);
        MarshalByRefObject proxy = (MarshalByRefObject)
            p.GetTransparentProxy();
        if (proxy == null) throw new InvalidOperationException(
            "Unable to create a proxy for " + target.GetType());
        return proxy;
    }

    private MarshalByRefObject _instance;
    private InterceptedMessageHandler _pre, _post;

    private InterceptionProxy(MarshalByRefObject target, 
        InterceptedMessageHandler pre, InterceptedMessageHandler post) : 
        base(target.GetType())
    {
        _instance = target;
        _pre = pre;
        _post = post;
    }

    public override IMessage Invoke(IMessage msg)
    {
        if (_pre != null) _pre(msg);
        msg = RemotingServices.ExecuteMessage(
            _instance, (IMethodCallMessage)msg);
        if (_post != null) _post(msg);
        return msg; 
    }
}

To use this class, you simply call InterceptionProxy.Intercept, passing in the target object and two delegates, one of which will be called before a call is passed along to the target and the other which will be called after the call has completed:

fs = (FileStream)InterceptionProxy.Intercept(fs, 
    new InterceptedMessageHandler(WritePreMessage), 
    new InterceptedMessageHandler(WritePostMessage));

Both delegates accept as a parameter an IMessage representation of information about the invocation; the former's IMessage (typically an instance of System.Runtime.Remoting.Messaging.Message) contains information about the call, while the latter's IMessage (typically an instance of System.Runtime.Remoting.Messaging.ReturnMessage) contains information about the results. Information from each of these objects can be accessed either through the IMessage.Properties collection or through the properties of the more specialized interfaces IMethodCallMessage and IMethodReturnMessage.

The static Intercept method first validates the parameters. If both of the supplied delegates are null, then there's no point in intercepting the call, so the original object is returned rather than a proxy. Assuming the arguments are all valid, a new InterceptionProxy is created to store the supplied data and to serve as the proxy for the target object (note that there's nothing to prevent you from creating two different proxies for the same object). GetTransparentProxy is then called on this real proxy and the result is returned to the caller. Whenever a call is made on this transparent proxy, it'll result in the InterceptionProxy's Invoke method being called with the relevant data stored in the IMessage. This IMessage is then passed to RemotingServices.ExecuteMessage, which takes care of delegating the call to the actual target.

Of course, this approach also has its downsides. First, there is a performance penalty involved with using real proxies for interception. As such, it would be a good idea to take some measurements to determine whether this has a noticeable impact on your solution. Second, as real and transparent proxies are part of the remoting infrastructure, they only work with types that are remotable, specifically those that are marshaled by reference. In other words, this technique only works with types derived from MarshalByRefObject (directly or indirectly). Luckily for your purposes, Stream is one such type, and there are plenty of others in the Framework. A third downside to this approach is that only calls made on the proxy are traced, so if an object hands out a non-proxied reference to itself, any calls made on that non-proxied reference will not be traced. Consider the following class:

class MyClass : MarshalByRefObject
{
    public MyClass GetThis  { get { return this; } }
}

Now consider using this class as follows:

MyClass mc = new MyClass();
mc = (MyClass)InterceptionProxy.Intercept(mc, ...);
Console.WriteLine(RemotingServices.IsTransparentProxy(mc));
Console.WriteLine(RemotingServices.IsTransparentProxy(mc.GetThis));

RemotingServices.IsTransparentProxy inspects the object passed to it and returns whether the object is a transparent proxy. The previous code snippet will thus print out "True" and "False", as the mc reference is a proxy but the reference it leaked through its GetThis property is not. Still, in many situations this technique can be a very handy tool for your code utility belt.

Q I'm writing a Windows® Forms application with Visual Basic® and would like to ensure that a user can only have one instance of it open at any one time. Additionally, if the user tries to start a new instance of that application, I'd like the currently running instance to be notified with the command-line arguments passed to the secondary instance. What's the easiest way to do this?

Q I'm writing a Windows® Forms application with Visual Basic® and would like to ensure that a user can only have one instance of it open at any one time. Additionally, if the user tries to start a new instance of that application, I'd like the currently running instance to be notified with the command-line arguments passed to the secondary instance. What's the easiest way to do this?

A Basic support for single-instance applications is fairly straightforward, and there are a variety of approaches to handling this. All of them involve some sort of shared resource that instances of the application can create and lock. If a second instance of an application is not successful in doing so, it knows that a previous instance already exists and that it should exit. The second requirement you pose of passing the command-line arguments to the initial instance is more complicated, so I'll address that later.

A Basic support for single-instance applications is fairly straightforward, and there are a variety of approaches to handling this. All of them involve some sort of shared resource that instances of the application can create and lock. If a second instance of an application is not successful in doing so, it knows that a previous instance already exists and that it should exit. The second requirement you pose of passing the command-line arguments to the initial instance is more complicated, so I'll address that later.

The most common shared resource used in managed applications for the creation of single-instance applications is a mutex. A mutex is a synchronization primitive provided by the operating system that allows for interthread and interprocess communication. A mutex is typically used to protect a shared resource, providing exclusive access to it.

When one thread acquires the mutex, no other threads will be able to acquire it until the thread that did so originally releases it. As such, applications can use a mutex to provide single-instance functionality. On startup, the application will attempt to create and acquire a mutex with a known name. If it can, then it is the first instance. If it can't, then another instance of the application has already created and acquired the mutex, thus alerting this new instance to the fact that it is a duplicate and should exit.

In the .NET Framework, a mutex is represented through the System.Threading.Mutex class. This class derives from WaitHandle and is a thin wrapper around the kernel's mutex object, which can be created using the Win32® CreateMutex function and opened using the Win32 OpenMutex function.

First, you need to come up with a name for the mutex. The use of a name allows multiple instances of the application to create or access the same mutex instance, so choosing a unique name ahead of time is important. Some typical examples of names used for this purpose include the name of the entry assembly for the application (available from [Assembly].GetEntryAssembly().FullName), the entry assembly's type library GUID (accessed with Marshal.GetTypeLibGuidForAssembly), or a predefined GUID used to uniquely identify the application. The name can also be autogenerated at runtime, but the algorithm for doing so must be created in such a way that all instances of the same application will generate the same name. With the name in hand, a mutex is instantiated using the constructor that accepts three arguments. Here is an example of using a mutex in a Visual Basic .NET application to ensure a single-instance of that application:

Sub Main()
    Dim mutexName As String = "3af65962-66bf-4135-bc5a-b0f986d8e995"
    Dim grantedOwnership As Boolean
    Dim singleInstanceMutex As Mutex = _
        New Mutex(True, mutexName, grantedOwnership)
    Try
        If Not grantedOwnership Then Return
        ... ' Main application code here
    Finally
        singleInstanceMutex.Close()
    End Try
End Sub

The first parameter to the constructor is a Boolean value that indicates whether the application wants to immediately acquire the mutex once it's created, and the third parameter is a Boolean passed by reference that upon completion of the constructor will store whether the created mutex was acquired. The second parameter is the name for the mutex. Once the mutex has been created, the grantedOwnership parameter can be checked to see whether the mutex was acquired by this instance of the application. If it was, then it is the first instance and the application should proceed normally. If it wasn't, then another instance of this application already exists, and this new instance should exit. It should be noted, however, that there is a possible denial of service (DoS) attack lurking here. Typically when one thinks of DoS attacks, images of Web applications come to mind. But a DoS attack is anything that prevents usage of a service, of any kind. In this case, a malicious party can learn the name of the mutex used to provide this single-instance functionality and can acquire the mutex first, thus forcing any instances of the application to act as if they're not the first instance and to close down. Just something to keep in mind.

That answers the part of your question about providing basic single-instance functionality, but it doesn't address how command-line arguments can be passed from a secondary instance to the primary instance. This is a harder problem as it involves more significant interprocess communication. One possibility is to use .NET remoting to communicate these parameters between instances. The primary instance can start a remoting server to listen for any other instances' command-line arguments. When another instance determines that it is not the first, it can connect to the primary's remoting server and pass to it the command-line arguments; the primary instance can then react to these command-line arguments in whatever way it sees fit.

So while basic support for single-instance applications as described earlier is fairly easy, a robust implementation is harder to come by. There are lots of issues involved: securing the connection between instances, mitigating the aforementioned DoS attack through liberal use of access control lists ( ACLs), choosing a good wait handle name, and so on. Luckily, the nice folks on the Visual Basic team have already done the hard work for you.

Figure 3 Single-Instance Windows Forms Application in Visual Basic 2005

Figure 3** Single-Instance Windows Forms Application in Visual Basic 2005 **

In Visual Basic 2005, creating a single-instance Windows Forms application is as easy as clicking a checkbox in the properties page for the application (shown in Figure 3). Then in the ApplicationEvents.vb file, you can handle the Me.StartupNextInstance event:

Namespace My
    Class MyApplication
        Private Sub MyApplication_StartupNextInstance( _
                ByVal sender As Object, _
                ByVal e As StartupNextInstanceEventArgs) _
                Handles Me.StartupNextInstance
            ... ' use e.CommandLine here
        End Sub
    End Class
End Namespace

The StartupNextInstanceEventArgs object passed to this event handler contains the command-line arguments from secondary instances of the application, and you can process them here however you see fit. And while the command-line arguments are received on a background thread, Visual Basic marshals the call to this event to the GUI thread. Under the covers, Visual Basic is using a technique similar to the one described earlier, though it is much more robust and secure.

Rather than using a mutex, Visual Basic uses an EventWaitHandle but in a similar way and with the same purpose (EventWaitHandle is the new base class in the .NET Framework 2.0 for AutoResetEvent and ManualResetEvent). The name for this wait handle is derived from the entry assembly's type library GUID and assembly version. If the instance of the wait handle does not already exist, Visual Basic sets up a remoting server and a secure channel through which to receive command-line arguments from other instances of the app. When command-line arguments are received, Visual Basic raises the StartupNextInstance event as was already described. If, however, the EventWaitHandle already exists, instead of creating a remoting server, Visual Basic connects to the existing instance's remoting server and passes to it the command-line arguments from the secondary instance. In order to enable discovery of the URI of the remoting server, the initial instance writes the URI to a memory- mapped file with a known name (similar to the name used for the event); secondary instances can then retrieve the URI from this location and correctly connect to the remoting server.

While this single-instance application functionality is easily accessible to developers using Visual Basic, the kind folks on the Visual Basic team have implemented this capability in such a way that other languages can also take advantage of it. Here I'll demonstrate how to create single-instance Windows Forms apps in C#.

All of the functionality just described is available from the WindowsFormsApplicationBase class as part of the Microsoft.VisualBasic.ApplicationServices namespace in Microsoft.VisualBasic.dll. If you examine in ildasm.exe a single-instance application created with Visual Basic, you'll find a class called MyApplication that derives from WindowsFormsApplicationBase. This class's constructor sets various protected properties on the base class, including one called IsSingleInstance. You can do the same thing in C#.

Additionally, the WindowsFormsApplicationBase class provides a public property MainForm which references the form instance to load and display at startup, and it provides the public event StartupNextInstance you've already seen used. You can put all of that together to create the class shown in Figure 4. Then, in the Main method of the application, instead of using the default code to start up the main form, as shown in the top half of Figure 5, you can use code like that in the bottom half, and you've got yourself a robust single-instance Windows Forms application in C#. Of course, you'll need to add a reference to Microsoft.VisualBasic.dll and import the appropriate namespace for this to work.

Figure 5 Using SingleInstanceApplication

Default Startup Code

static class Program
{
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.Run(new Form1());
    }
}

Single-Instance Startup Code

static class Program
{
    [STAThread]
    static void Main()
    { 
        Application.EnableVisualStyles();
        SingleInstanceApplication.Run(new Form1(), 
            StartupNextInstanceHandler);
    }

    static void StartupNextInstanceHandler(
        object sender, StartupNextInstanceEventArgs e)
    {
        // do whatever you want here with e.CommandLine...
    }
}

Figure 4 SingleInstanceApplication in C#

public class SingleInstanceApplication : WindowsFormsApplicationBase
{
    private SingleInstanceApplication()
    { 
        base.IsSingleInstance = true; 
    }
    
    public static void Run(Form f, 
        StartupNextInstanceEventHandler startupHandler)
    {
        SingleInstanceApplication app = new SingleInstanceApplication();
        app.MainForm = f;
        app.StartupNextInstance += startupHandler;
        app.Run(Environment.GetCommandLineArgs());
    }
}

Send your questions and comments to  netqa@microsoft.com.

Stephen Toub is the Technical Editor for MSDN Magazine.