Jaa


Handling Entry Assemblies that Won't Load: Method 1

Last week, when I posted about failing to run in partial trust gracefully, the method I showed only worked if your main assembly could be loaded.  However, if it has a minimum permission request that cannot be satisfied, your main method won't ever be called, and you won't be able to fail gracefully.

For instance, the following code:

using System;
using System.Security;
using System.Security.Policy;
using System.Security.Permissions;

[assembly: PermissionSet(SecurityAction.RequestMinimum, Unrestricted = true)]

public class Test
{
    public static void Main()
    {
        Console.WriteLine("Hello World");
        return;
    }
}

If I compile this code to main.exe, and run it from a partial trust environment, the application bombs out with the following exception:

Unhandled Exception: System.IO.FileLoadException: Could not load file or assembly 'main, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. Failed to grant minimum permission requests. (Exception from HRESULT: 0x80131417 (CORSEC_E_MIN_GRANT_FAIL))File name: 'main, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' ---> System.Security.Policy.PolicyException: Required permissions cannot be acquired.

As I said above, this exception is thrown before Main ever gets to execute, so there's no way to setup a handler for this exception.  So how can you display a nicer error to your users?

One easy way is to create a shim application that will attempt to load your entry point for you.  Since your shim application won't have the declarative request on it, it should be able to load.  And once it's loaded, we can simply catch the FileLoadException that the entry point is throwing, and recover by showing the error message to the user.

We'll want to be careful however, that we don't catch every FileLoadException, since we don't want to display our message if some other assembly happens to fail to load.  One simple shim application would look something like this:

using System;
using System.IO;
using System.Reflection;

public class Shim
{
    public const int FailCode = 0;

    public static int Main()
    {
        try
        {
            return AppDomain.CurrentDomain.ExecuteAssembly("main.exe");
        }
        catch(FileLoadException e)
        {
            try
            {
                AssemblyName failedAssembly = new AssemblyName(e.FileName);
                if(failedAssembly.Name == "main")
                {
                    Console.WriteLine("Could not load main.exe, possibly due to security issues. Please copy to a local location.");
                    return FailCode;
                }
            }
            catch(ArgumentException) { /* do nothing ... this wasn't an assembly name */ }

            // if we got here, then we didn't fail to load the main assembly, so let the exception propigate on
            throw;
        }
    }
}

Now, instead of running main.exe, I run shim.exe instead.  The shim wraps main.exe with a try...catch block, which handles the exception that occurs when main fails to load.  The throw clause rethrows the exception if it wasn't a failure to load the main assembly, so that any installed unhandled exception filters (or a debugger if there are none) will get called.

There are a few problems with this approach.  Assembly.GetEntryAssembly() will return shim.exe instead of main.exe, the shim application will be at the root of every call stack, and you have to ensure that your users call the shim instead of the main application.

Tomorrow, we'll try to address some of the inadequacies of this method, and solve the problem in a better way.

Comments

  • Anonymous
    February 14, 2006
    today,I want to run a project in Microsoft Visual Studio 2005 and failed .

    And show a Error :Could not load file or assembly 'Microsoft.Practices.EnterpriseLibrary.Configuration, Version=1.1.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. Failed to grant minimum permission requests. (Exception from HRESULT: 0x80131417)

    so ,I search on net, and see you occured to same,so I ask you :How solve??

    please answer ,thank you very very much!!

    Can you sent the answer to my email(0633shj@163.com )and give me the answer in chinese ??
    Thanks.

  • Anonymous
    February 23, 2006
    I'm having the same problem - a vs2005 app that won't compile once I reference any 3rd party dll. I get the same 0x80131417 error. Help!!

  • Anonymous
    February 23, 2006
    I'm having the same problem - a vs2005 app that won't compile once I reference any 3rd party dll. I get the same 0x80131417 error. Help!!

    sfk.hooper@gmail.com

  • Anonymous
    April 14, 2006
    I'm using WINXP Pro workstations on a WIN 2003 AD domain, with roaming profiles and shared drives to store the user's data (supporting 9 computer labs).  When I logon as a Domain Administrator, everything works fine.  When I logon as a 'normal' user, I get the error message:
    [[An unhandled exception of type 'System.IO.FileLoadException' occurred in Unknown Module.
    Additional information: Could not load file or assembly 'CppForm4, Version=1.0.2294.18123, Culture=neutral, PublicKeyToken=null' or one of its dependencies. Failed to grant minimum permission requests. (Exception from HRESULT: 0x80131417)]]

    Makes me think it a permissions problem.  But where?

  • Anonymous
    April 17, 2006
    Unfortunately, that's not enough information to diagnose the problem. Have you tried attaching a debugger and seeing where the demand is triggered?

    -Shawn

  • Anonymous
    October 19, 2006
    I have the same problem; the main module won't load and it's stopped before it ever gets control.  I'm running it from a network drive.  One an XP Home machine, it works fine; from a newly-installed Pro x64 machine, it won't run. I've gone to .NET 2.0 and set the max full trust for both machine and intranet, yet I still get the same result. Can you help?  I don't know what to look at or change next? thanks, tom

  • Anonymous
    October 20, 2006
    Make sure that you've updated both the 32 bit security policy and the 64 bit policy.  On an x64 machine, those are independent of each other. -Shawn