再谈System.ComponentModel.Win32Exception

如名称的Win32部分所示System.ComponentModel.Win32Exception仅在处理传统样式的应用程序或代码时发生-应用程序必须调用直接操作系统调用,例如尝试执行其他应用程序。在本文中,我们将深入探讨System.ComponentModel.Win32异常。更详细地说,包括它在.NET异常层次结构中的位置。我们还将深入研究一些函数C#代码示例,以更好地说明如何System.ComponentModel.Win32Exceptions可能会在自己的编码中被抛出!

要点

  • 所有 .NET exceptions 继承自 System.Exception base class, 或者继承自inherited class.
  • System.SystemException 继承自 System.Exception class.
  • System.Runtime.InteropServices.ExternalException 直接继承自System.SystemException.
  • 最后, System.ComponentModel.Win32Exception 继承自 System.Runtime.InteropServices.ExternalException.

什么时候用它呢?

这个System.ComponentModel.Win32异常是在使用内部win32样式的操作系统调用时发生错误时在.NET应用程序中发生的最基本的异常类型。这些问题可能不同,从无效路径和文件找不到错误到网络地址问题和资源管理问题。因为System.ComponentModel.Win32Exceptions是旧形式异常的包装器,您可能遇到的每个可能的错误都有自己的NativeErrorCode属性值,它是一个32位整数,引用与引发的异常相关联的Win32错误代码值。
我们的示例代码开始。整个代码段如下所示,之后我们将更详细地讨论它:

using System.Diagnostics;
using Utility;

namespace Airbrake.ComponentModel.Win32Exception
{
    class Program
    {
        static void Main(string[] args)
        {
            StartProcessFromPath("c:/windows/notepad.exe");
            Logging.LineSeparator();
            StartProcessFromPath("c:/windows/invalid.exe");
        }

        static void StartProcessFromPath(string path)
        {
            try
            {
                // Create a new process with StartInfo.FileName set to provided path.
                var process = new Process { StartInfo = { FileName = path } };
                // Attempt to start the process using provided executable path.
                var success = process.Start();
                if (success)
                {
                    Logging.Log($"Successfully launched '{process.ProcessName.ToString()}' process!");
                    // Sleep for two seconds to allow time for window to be shown.
                    System.Threading.Thread.Sleep(2000);
                    // Kill process.
                    process.Kill();
                    Logging.Log($"Killed '{process.ProcessName.ToString()}' process.");
                }
                else
                {
                    // This code never executes since we're catching
                    // an exception from the process.Start() invocation line.
                }
            }
            catch (System.ComponentModel.Win32Exception exception)
            {
                // Indicate failure to start.
                Logging.Log($"Unable to start process with executable path '{path}'.");
                // Output caught exception.
                Logging.Log(exception);
                Logging.Log($"Native Win32 Error Code: {exception.NativeErrorCode}");
            }
        }
    }
}

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Text;

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(string 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
        }

        /// <summary>
        /// Outputs a dashed line separator to <see cref="System.Diagnostics.Debug.WriteLine"/> 
        /// if DEBUG mode is enabled, otherwise uses standard <see cref="Console.WriteLine"/>.
        /// </summary>
        public static void LineSeparator()
        {
#if DEBUG
            Debug.WriteLine(new string('-', 20));
#else
            Console.WriteLine(new string('-', 20));
#endif
        }
    }
}

我们的大多数示例都发生在StartProcessFromPath()方法中,该方法接受一个应指向可执行文件的字符串路径值。然后,我们实例化一个新进程,并尝试用.start()方法启动它。.Start()方法返回一个布尔值,指示尝试是否成功,因此我们只需使用该布尔值来执行一些额外的逻辑,例如将一些信息输出到日志以指示成功或失败,以及一个小的Sleep()周期,以便我们有时间查看新启动的窗口(如果适用)。最后我们用.Kill()方法终止进程。

static void StartProcessFromPath(string path)
{
    try
    {
        // Create a new process with StartInfo.FileName set to provided path.
        var process = new Process { StartInfo = { FileName = path } };
        // Attempt to start the process using provided executable path.
        var success = process.Start();
        if (success)
        {
            Logging.Log($"Successfully launched '{process.ProcessName.ToString()}' process!");
            // Sleep for two seconds to allow time for window to be shown.
            System.Threading.Thread.Sleep(2000);
            // Kill process.
            process.Kill();
            Logging.Log($"Killed '{process.ProcessName.ToString()}' process.");
        }
        else
        {
            // This code never executes since we're catching
            // an exception from the process.Start() invocation line.
        }
    }
    catch (System.ComponentModel.Win32Exception exception)
    {
        // Indicate failure to start.
        Logging.Log($"Unable to start process with executable path '{path}'.");
        // Output caught exception.
        Logging.Log(exception);
        Logging.Log($"Native Win32 Error Code: {exception.NativeErrorCode}");
    }
}

为了说明成功和失败,我们的Main()方法尝试启动notepad.exe 以及invalid.exe:

static void Main(string[] args)
{
    StartProcessFromPath("c:/windows/notepad.exe");
    Logging.LineSeparator();
    StartProcessFromPath("c:/windows/invalid.exe");
}
正如您可能怀疑的那样,第一个StartProcessFromPath()调用工作正常,我们看到记事本窗口弹出两秒钟,然后由于Kill()方法调用而消失。我们还可以从控制台日志输出中获得成功确认:
Successfully launched 'notepad' process!
Killed 'notepad' process.

另一方面,我们的第二个StartProcessFromPath()调用invalid.exe失败并抛出System.ComponentModel.Win32Exception我们的方式:

Unable to start process with executable path: 'c:/windows/invalid.exe'.
[EXPECTED] System.ComponentModel.Win32Exception (0x80004005): The system cannot find the file specified
Native Win32 Error Code: 2
我们还确保输出相关的Win32错误代码,方法是在System.ComponentModel.Win32Exception,因此我们可以看到win32错误代码是:2。如果我们回到Win32错误代码表,我们会发现2的值(即0x00000002)对应于Error_FILE_NOT_FOUND枚举,并说明系统找不到指定的文件。当然,这个描述与System.ComponentModel.Win32Exception输出我们收到的消息!

posted on 2020-07-09 07:58  活着的虫子  阅读(10443)  评论(0编辑  收藏  举报

导航