Avoiding security exceptions when running .NET applications from a shared drive

Something I had noticed a while ago but had never found the time to investigate the cause was why running .NET applications form a shared drive would cause the program to crash. If the same program were copied to a local drive, the program would run just fine. It turns out the cause of the crash was due to a security exception being thrown by the JIT compiler when it hit the main function of the program.  The debugging information provided by the crash report didn't have anything useful to indicate what was wrong or how to correct it.  At the time, it wasn't that big of a deal to just instruct the users of the program to copy it to a local drive in order to run it. However, it's not exactly an elegant solution. I have recently become aware of a way to catch this exception in order to provide the user with an appropriate message box, and the rest of this article explains how.

While there are ways to enable directly running the application from the shared drive, it's important for the application to provide some reasonable feedback about why it crashed in the first place. Any application that, through normal use, has the potential to throw an exception should catch that exception and provide the user with the information necessary to avoid the problem.  Even if the user has the administrative privileges required to configure the computer to run .NET applications from a shared drive, the user may very well decide it's easier to just copy it to a local drive once they read the message explaining why it's unable to start. This article is about how to provide a useful message to the user instead of a crash dialog when the application is run from a shared drive.

While looking for solutions to another problem, I encountered this blog entry: LinkDemands and InheritenceDemands Occur at JIT Time. The post describes this problem in detail, and explains how to work around it.  If it's not perfectly clear what is required to work around this problem, the following example should help.

In your C# program, you will need to make a secondary static Main function that invokes the original main function from within a try -- catch block that is configured to catch the security exception. It's quite simple, really. just use the following code:

static class ProgramWrapper { [STAThread] static void Main(string[] args) { try { Program.Main(args); } catch (System.Security.SecurityException) { MessageBox.Show("This application must be run from a secure location, such as a local disk."); } } } static class Program { ///

/// The main entry point for the application. /// [STAThread] public static void Main(string[] args) { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new BrowserSelectorForm(args)); } }

 The only other thing left to do is to instruct the compiler which static Main function you want the application to use. You do that here, using the "Startup object" combo within the Application tab of the project settings. It will list all the classes with a static Main function. In fact, if there are more than one of them the app won't build so you'll have to select it if you want your app to run at all.

Once you've done this, your app will now present the user with a friendly message indicating why they couldn't run it from the shared drive. You now have one less thing that can go wrong when users try to use your software. One thing at a time, right?