• 再谈System.BadImageFormatException


    今天,当我们继续学习.NET异常处理系列时,我们将查看System.BadImageFormatException。System.BadImageFormatException与GIF或JPG无关,而是在.NET应用程序尝试加载与当前公共语言运行库(CLR)所需的正确格式不匹配的动态链接库(.dll)或可执行文件(.exe)时发生。
    在本文中,我们将看到System.BadImageFormatException在.NET异常层次结构中的确切位置,并查看System.BadImageFormatException的一些潜在原因,让我们开始讨论它!

    如前所述,System.BadImageFormatException发生在非常特殊的情况下:当.NET试图使用.dll或.exe时,即以某种方式与当前公共语言运行库不兼容。“不兼容的公共语言运行时”的定义可能有所不同,但通常这意味着.NET版本(1.1、2.0等)或各种编译程序集的CPU类型(32位与64位)不匹配。
    最后,System.BadImageFormatExceptions表示版本控制不兼容。对于许多现代软件应用程序,的主要版本通常包括打破兼容性问题,防止与以前版本的某些方面向后兼容。.NET程序集(.dll或.exe)基本相同,尝试使用包含不兼容项的两种不同类型的程序集通常会生成System.BadImageFormatException。
    为了说明这一点,我们将通过几个不同的例子。我已经包含了下面的完整代码示例以供参考,之后我们将更详细地探讨细节:

    using System;
    using System.Reflection;
    using Utility;
    
    namespace Airbrake.BadImageFormatException
    {
        class Program
        {
            static void Main(string[] args)
            {
                LoadingNonDotNetLibraryExample();
                Logging.Log("-----------------");
                DifferingCPUExample();
                Logging.Log("-----------------");
                OldDotNetExample();
            }
    
            private static void LoadingNonDotNetLibraryExample()
            {
                try
                {
                    // Generate path to notepad.exe.
                    string filePath = Environment.ExpandEnvironmentVariables("%windir%") + @"System32
    otepad.exe";
                    Assembly assem = Assembly.LoadFile(filePath);
                }
                catch (System.BadImageFormatException exception)
                {
                    Logging.Log(exception);
                }
            }
    
            private static void DifferingCPUExample()
            {
                try
                {
                    // Load Utility.dll, a 64-bit assembly.
                    Assembly assem = Assembly.LoadFrom(@".Utility.dll");
                    Logging.Log(assem.ToString());
                }
                catch (System.BadImageFormatException exception)
                {
                    Logging.Log(exception);
                }
            }
    
            private static void OldDotNetExample()
            {
                try
                {
                    // Load Author-1.1.dll (compiled in .NET 1.1).
                    Assembly assem = Assembly.LoadFrom(@".Author-1.1.dll");
                    Logging.Log(assem.ToString());
                }
                catch (System.BadImageFormatException exception)
                {
                    Logging.Log(exception);
                }
            }
        }
    }
    
    using System;
    using System.Diagnostics;
    
    namespace Utility
    {
        /// <summary>
        /// Houses all logging methods for various debug outputs.
        /// </summary>
        public static class Logging
        {
            /// <summary>
            /// Outputs to <see cref="System.Diagnostics.Debug.WriteLine"/> if DEBUG mode is enabled,
            /// otherwise uses standard <see cref="Console.WriteLine"/>.
            /// </summary>
            /// <param name="value">Value to be output to log.</param>
            public static void Log(object value)
            {
                #if DEBUG
                    Debug.WriteLine(value);
                #else
                    Console.WriteLine(value);
                #endif
            }
    
            /// <summary>
            /// When <see cref="Exception"/> parameter is passed, modifies the output to indicate
            /// if <see cref="Exception"/> was expected, based on passed in `expected` parameter.
            /// <para>Outputs the full <see cref="Exception"/> type and message.</para>
            /// </summary>
            /// <param name="exception">The <see cref="Exception"/> to output.</param>
            /// <param name="expected">Boolean indicating if <see cref="Exception"/> was expected.</param>
            public static void Log(Exception exception, bool expected = true)
            {
                string value = $"[{(expected ? "EXPECTED" : "UNEXPECTED")}] {exception.ToString()}: {exception.Message}";
                #if DEBUG
                    Debug.WriteLine(value);
                #else
                    Console.WriteLine(value);
                #endif
            }
        }
    }

    引发System.BadImageFormatException的第一种(也可以说是最常见的)方法是尝试使用非托管程序集时,就像它是使用.NET框架创建的程序集一样。非托管程序集是由.NET的公共语言运行库未处理和编译的代码生成的程序集。这包括许多较旧的应用程序和程序集,特别是为32位系统创建的应用程序和程序集。
    作为一个例子,这里我们试图加载一个非托管程序集—特别是位于Windows/System32目录中的众所周知的notepad.exe程序集:

    private static void LoadingNonDotNetLibraryExample()
    {
        try
        {
            // Generate path to notepad.exe.
            string filePath = Environment.ExpandEnvironmentVariables("%windir%") + @"System32
    otepad.exe";
            Assembly assem = Assembly.LoadFile(filePath);
        }
        catch (System.BadImageFormatException exception)
        {
            Logging.Log(exception);
        }
    }

    .NET对此不满意,因为notepad.exe不受管理(不是使用.NET编译的),因此引发System.BadImageFormatException:

    [EXPECTED] System.BadImageFormatException: The module was expected to contain an assembly manifest. (Exception from HRESULT: 0x80131018)
       at System.Reflection.RuntimeAssembly.nLoadFile(String path, Evidence evidence)
       at System.Reflection.Assembly.LoadFile(String path)
       at Airbrake.BadImageFormatException.Program.LoadingNonDotNetLibraryExample() in D:workAirbrake.ioExceptions.NETAirbrake.BadImageFormatExceptionProgram.cs:line 26: The module was expected to contain an assembly manifest. (Exception from HRESULT: 0x80131018)

    另一种可能引发System.BadImageFormatException的方法是尝试加载使用不同于当前在.NET上执行的CPU类型编译的程序集。
    例如,在我们的许多代码片段中,我们一直在使用包含日志类的简单实用程序名称空间,这使得在调试和测试期间输出日志信息更加容易。默认情况下,Utility.dll编译为64位程序集。但是,如果我们将当前的CPU配置切换为以x86(32位)CPU执行,则会遇到一些问题:

    private static void DifferingCPUExample()
    {
        try
        {
            // Generate path to Utility.dll, a 64-bit assembly.
            Assembly assem = Assembly.LoadFrom(@".Utility.dll");
            Logging.Log(assem.ToString());
        }
        catch (System.BadImageFormatException exception)
        {
            Logging.Log(exception);
        }
    }

    当试图加载Utility.dll程序集(64位)时,当将当前代码编译为32位时,.NET抛出System.BadImageFormatException,通知我们这些格式不匹配:

    [EXPECTED] System.BadImageFormatException: An attempt was made to load a program with an incorrect format. (Exception from HRESULT: 0x8007000B)
       at System.Reflection.RuntimeAssembly.nLoadFile(String path, Evidence evidence)
       at System.Reflection.Assembly.LoadFile(String path)
       at Airbrake.BadImageFormatException.Program.DifferingCPUExample() in D:workAirbrake.ioExceptions.NETAirbrake.BadImageFormatExceptionProgram.cs:line 40: An attempt was made to load a program with an incorrect format. (Exception from HRESULT: 0x8007000B)

    最后,如果尝试加载使用更旧版本的.NET(如.NET 1.1)编译的程序集,我们也会遇到问题:

    private static void OldDotNetExample()
    {
        try
        {
            // Load Author-1.1.dll (compiled in .NET 1.1).
            Assembly assem = Assembly.LoadFrom(@".Author-1.1.dll");
            Logging.Log(assem.ToString());
        }
        catch (System.BadImageFormatException exception)
        {
            Logging.Log(exception);
        }
    }

    在上述情况下,System.BadImageFormatException通常会在编译时抛出,而不是在运行时抛出,因为.NET编译器在试图首先执行任何代码之前都会识别出不兼容。

  • 相关阅读:
    联赛前第五阶段总结
    陶陶摘苹果 —— 线段树维护单调栈
    联赛前第三阶段总结
    联赛前第四阶段总结
    [NOIP
    超级跳马 —— 矩阵快速幂优化DP
    我的博客园美化
    Wedding —— 2-SAT
    C++运算符优先级
    water——小根堆+BFS
  • 原文地址:https://www.cnblogs.com/yilang/p/12000851.html
Copyright © 2020-2023  润新知