0

I have a C# .NET application that I'm maintaining and adding new features to. One of the new features requires the use of a third party DLL which may not always be present when the application starts. I've added the DLL as a reference to the project along with code to detect if the DLL is missing. That code notify the user about the missing DLL file BEFORE any code referencing the actual DLL is called. Unfortunately, something in the native runtime attempts to access the DLL before main() even runs and throws an exception. Here's some output from the debugger:

Your app has entered a break state, but no code is currently executing that is supported by the selected debug engine (e.g. only native runtime code is executing).

System.IO.FileNotFoundException: 'Could not load file or assembly 'FTD2XX_NET, Version=1.1.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.' 

The environment is supposed to only access the assemblies on demand. Since something in the CLR is throwing an exception before main() even runs the application has no chance to even check for the existence of the DLL. Since none of the application code has run yet why would the DLL be referenced?

Can anyone provide some insight on why the native runtime is throwing this exception and how it can be avoided? To my knowledge there is no longer functionality for delaying DLL loading. Is that the case or is there a secret way of still doing that? I'd settle for a way catch this exception so the user could be notified. Thanks in advance for any information.

Information on the system in question:

  • Window 10, x64
  • .NET Framework 4.6.1
  • Visual Studio 2019
  • I can't update to a newer version of .NET or Visual Studio.
jemiah
  • 63
  • 8
  • Note that you may embed a .dll s inside the .exe and load the DLL assembly at your convenience.. https://stackoverflow.com/questions/189549/embedding-dlls-in-a-compiled-executable – Graffito Apr 14 '23 at 22:44
  • Please show how the DLL is used. If the `Main` function calls any function that uses the DLL then it may pre-load it. – Charlieface Apr 15 '23 at 21:29
  • Please also state whether you are building for AnyCPU, x64, or something else. – Mike Nakis Apr 16 '23 at 09:54
  • I couldn't post the actual code but I'll update with a stripped-down example. – jemiah Apr 17 '23 at 13:57

1 Answers1

0

As stated by @Charlieface, the JITter is looking one function call ahead for DLLs that need to be loaded/used. In my application, the DLL which was needed was referenced by the main form of my application. It was being launched like this: (This is stripped-down, anonymized, example code)

static class Program
{
  /// <summary>
  /// The main entry point for the application.
  /// </summary>
  [STAThread]
  static void Main()
  {
     Application.EnableVisualStyles();
     Application.SetCompatibleTextRenderingDefault(false);
     Application.Run(new Form_Main());
  }
}

Run as above, the application would fail/exit without even entering Main(). The change to allow execution to enter the application code (where the missing DLL could be addressed, was to put the launch of Form_Main in a wrapper function:

static class Program
{
    static void LoadApplication()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new Form_Main());
    }
    
    static void CheckForDLL()
    {
        // Check the filesystem for the required DLL.
        // Pull it in if it's missing.
    }

    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main()
    {
        // Locate and, if necessary, pull-in the required DLL
        CheckForDLL();
        
        // Now load the application
        LoadApplication():
    }
}

For brevity I've removed all the additional try-catch blocks and application specific DLL retrieval. The key point was that, in order to prevent the JITter from throwing the System.IO.FileNotFoundException exception (before any application code was running and able to catch it) the Object that was referencing the DLL had to be nested one level deeper so Main() wasn't instantiating an object that referenced the DLL.

jemiah
  • 63
  • 8