再谈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"); }
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