views:

79

answers:

3

I have a windows 7 x64 desktop with vs2010 and a virtual box installation of linux with mono and monodevelop. I compile the following program with vs2010 and run it in the linux virtual machine and it fails with a seemingly uncatchable FileNotFoundException. If I compile it in the virtual machine and run it in windows, it works great.

The problem seems to be that an uncatchable exception is tossed by mono before Main() when it is impossible to load a dll. Is there a way to restructure my program or coerce mono such that I can catch this exception?

I am trying to write a single program that has an interface in either WPF or GTK according to what is available at runtime.

using System;  
#if __MonoCS__  
using Gtk;  
#else  
using System.Windows;  
#endif  
using System.IO;  
using System.Runtime.CompilerServices;  
using System.Collections.Generic;  

namespace Test {

 public static class Program {

  [STAThread]
  public static void Main() {
   try {
    Main2();
   } catch (FileNotFoundException e) {
    Console.WriteLine("Caught FileNotFoundException");
    Console.WriteLine("FileName = {0}", e.FileName);
   }
  }

  [MethodImpl(MethodImplOptions.NoInlining)]
  public static void Main2() {
#if __MonoCS__  
   Application.Init();  
#else  
   Window w = new Window();  
#endif  
  }

 }

}
A: 

What DLL is not found? I'm assuming, judging from your code, it's probably WinForms. I'm not entirely familiar with the C# preprocessor, but I think #if __MonoCS__ may be more useful (or may act only) as a preprocessor define, that is, it doesn't change at runtime. You may try defining __MonoCS__ for the Mono build in the project settings and run that (I would think VS doesn't define that by default, so it's probably trying to work with WinForms anyway).

Another thing to try is commenting out the using System.Windows and all its related code (just using the GTK/Mono path) and test if that builds on Windows and runs on both. If so, then you've narrowed the possible problems down to just that include, and it should be easier to solve from there.

peachykeen
On Linux PresentationFramework is the first DLL to trigger the exception. On Windows it is GTK-Sharp. Winforms is not used in this program. The whole point of the program is to get it to throw an exception so I can see where it is appropriate to catch it, so commenting out the various code you mentioned would make the exercise impossible.If there is a better way to make a single .exe able to select between the 2 APIs at runtime I am all ears.
oxeb
Ah, so you're using the presentation framework, not forms? I don't think that changes much. To make a single EXE able to run on either, the best way is to use a crossplatform UI. GTK# comes for Windows as well, so if its not a bother, using just that should work for you. What I was originally saying was the reason you get the exception is the system isn't paying attention to the `#if`s as you expect, so changing those may be more helpful. I'm not familiar with the C# preprocessor though. You may have to just build twice, once for Windows and once for Linux, if nothing else works.
peachykeen
It is paying attention to the #ifs exactly as I expect. They are supposed to force it to always use the wrong library. I want the exception. The whole point of the program is to generate the exception to catch it. I wanted to use this technique to select from a variety of libraries under many situations. GTK and WPF are just an example. It seems to be impossible to do what I want.I do not want to force windows users to use gtk.
oxeb
A: 

You are exposing yourself to the implementation details of the JIT-compiler. The exact time it will throw the exception for the missing assembly depends on how eagerly it translates the IL into machine code. I know the Microsoft jitter is truly just-in-time, it compiles one method at a time, just before it is about to execute. Although this is affected by whether or not a debugger is attached. You're dead in the water if Mono, say, compiles the entire class. The jitter will throw before Main() can start.

Maybe it will work better if you put Main2() in another class. The best thing to do is just have an assembly available, a dummy if necessary.

Hans Passant
Putting Main2 in another class does not help. What you say makes sense, although the very notion of tossing an uncatchable exception is very frustrating to me. I am going to leave this question open for a bit longer to see if anybody has a magic answer, but it seem inevitable that I will award you the answer. Thank you.
oxeb
A: 

Instead of depending on the laziness of referenced assembly loading, I suggest you implement your platform-specific GUIs in different assemblies, perhaps implementing a common interface. The main assembly would then have no direct references to specific GUI toolkits, but would use reflection to try to load WPF or GTK from the GAC, and based on that would use reflection to load a specific GUI dll assembly and instantiate and use the GUI implementation.

Something like:

  • ProgramName.exe - contains Main entry point, IPlatformGui, and logic shared by all platforms
  • ProgramName.Gtk.dll - contains GtkGui : IPlatformGui
  • ProgramName.Wpf.dll - contains WpfGui : IPlatformGui
mhutch
I am probably going to resort to what you are saying. TBH I don't think I have any other option. I assume I cannot select more than one answer on here? I would like to credit you both.
oxeb