tags:

views:

251

answers:

3

I have a small command line program that uses the Team System API. When the correct Team System isn't installed on the machine, the program prints a traceback with System.IO.FileNotFoundException, but it also crashes and shows the standard error messasge:

XXX has encountered a problem and needs to close. We are sorry for the inconvenience.

I just want my program to print a "The program requires Team System 2008" message to the console and quit without crashing.

From what I understand this whole loading process is happening before the first line of my C# code is run. Is there any way to control this?

+1  A: 

You can try to Override CLR Assembly Probing Logic

In the .Net framework, when resolving an assembly reference, the CLR first checks the GAC, then searches the application directory in specific locations. If the assembly is not in one of those locations, CLR will fire AssemblyResolve event. You can subscribe to AssemblyResolve event and return the assembly using Assembly.LoadFrom/LoadFile, etc.

However, in your case, you can just show your messagebox and then shutdown cleanly.

Nescio
A: 

Yes. The assembly will be loaded the first time you use a type that itself references a type from the assembly to be loaded.

So the solution is to create a helper class that wraps all interaction with the API. Then wrap calls to this wrapper class in a try/catch.

Something like:

public class Program
{
    static void Main()
    {
        try
        {
            WrapperClass.CallApi(...);
        }
        catch(FileNotFoundException)
        {
            ... you can e.g. show a MessageBox and exit here ... 
        }
    }
}

internal class WrapperClass
{
    public void CallApi(...)
    {
        ... you can reference types from the Team System assembly in WrapperClass
    }
}
Joe
Thanks, but apparently the assembly is loaded before any of my code runs, I can't even get to the first line of Main.
gooli
Yes that's because you're referencing it directly in the Main method. If you reference from a separate class (or even a separate method as Marc Gravell pointed out), your Main will be executed and you can catch the exception.
Joe
+2  A: 

.NET code is JITted on a method-by-method basis. Does your "Main" method make reference to the external libraries? If so, consider:

[MethodImpl(MethodImplOptions.NoInlining)]
static int Main() { // add "args" etc if needed
    try {
        return Main2();
    } catch (Exception ex) {
        Console.Error.WriteLine(ex.Message);
        return 1;
    }
}
static int Main2() { // add "args" etc if needed
    // your real code
}

I can't guarantee it will work, but it is worth a try...

Marc Gravell
Works like a charm, thanks!
gooli