C#/.NET 如何在第一次机会异常 FirstChanceException 中获取比较完整的异常堆栈

FirstChangeException 事件中,我们通常只能拿到异常堆栈的第一帧,这对于我们捕捉到异常是好的,但对分析第一次机会异常可能并不利。

本文介绍如何在 FirstChangeException 事件中拿到比较完整的异常堆栈,而不只是第一帧。


第一次机会异常

.NET 程序代码中的任何一段代码,在刚刚抛出异常,还没有被任何处理的那一时刻,AppDomain 的实例会引发一个 FirstChanceException 事件,用于通知此时刚刚开始发生了一个异常。

这时,这个异常还没有寻找任何一个可以处理它的 catch 块,在此事件中,你几乎是第一时间拿到了这个异常的信息。

监听第一次机会异常的代码是这个样子的:

private void WalterlvDemo()
{
    AppDomain.CurrentDomain.FirstChanceException += OnFirstChanceException;
}

private void OnFirstChanceException(object sender, FirstChanceExceptionEventArgs e)
{
    // 在这里,可以通过 e.Exception 来获取到这个异常。
    Console.WriteLine(e.Exception.ToString());
}

只不过,在这里我们拿到的异常堆栈只有第一帧,因为这个时候,还没有任何 catch 块捕捉到这个异常。比如,我们只能拿到这个:

System.NotSupportedException: BitmapMetadata 在 BitmapImage 上可用。
   在 System.Windows.Media.Imaging.BitmapImage.get_Metadata()

一点知识Exception 实例的异常堆栈,是从第一次抛出异常的地方开始,到第一个 catch 它的地方结束,除非这个 catch 块中继续只用 throw; 抛出才继续向外延伸到下一个 catch

另外,你也可以用 ExceptionDispatchInfo 让内部异常的堆栈也连接起来,详见我的另一篇博客:

获取较完整的第一次机会异常堆栈

我们需要等到 FirstChanceException 事件中的异常被 catch 到,就能获取到第一次抛出的地方到 catch 处之间的所有帧。

所以,我们只需要稍作延迟,即可拿到较完整的异常堆栈:

private void WalterlvDemo()
{
    AppDomain.CurrentDomain.FirstChanceException += OnFirstChanceException;
}

private async void OnFirstChanceException(object sender, FirstChanceExceptionEventArgs e)
{
    // 刚刚进入第一次机会异常事件的时候,异常堆栈只有一行,因为此时还没有任何地方 catch。
    // 现在等待一点点时间,使得异常的堆栈能够延伸到 catch。等待多长不重要,关键是为了让异常得以找到第一个 catch。
    await Task.Delay(10);

    // 在这里,可以通过 e.Exception 来获取到这个异常。
    Console.WriteLine(e.Exception.ToString());
}

这样,我们可以得到:

System.NotSupportedException: BitmapMetadata 在 BitmapImage 上可用。
   在 System.Windows.Media.Imaging.BitmapImage.get_Metadata()
   在 System.Windows.Media.Imaging.BitmapFrame.Create(BitmapSource source)
   在 Walterlv.Demo.Exceptions.Foo.Take(string fileName)

这里,等待多长时间是不重要的,只要不是 0 就好。因为我们只需要当前调用堆栈中的异常处理执行完成即可。

关于等待时间,可以阅读我的另一篇博客:

如果需要对此异常进行后续的分析,可以参考我的另一篇博客:


我的博客会首发于 https://blog.walterlv.com/,而 CSDN 会从其中精选发布,但是一旦发布了就很少更新。

如果在博客看到有任何不懂的内容,欢迎交流。我搭建了 dotnet 职业技术学院 欢迎大家加入。

知识共享许可协议

本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。欢迎转载、使用、重新发布,但务必保留文章署名吕毅(包含链接:https://walterlv.blog.csdn.net/),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我联系

展开阅读全文

0x00000000 处的第一机会异常(在 LOAD_WIZARD.exe ): 0xC0000005: 执行位置 0x00000000 时发生访问冲突

04-21
VS2012编译能够成功,但是在调用的时候出现了上述问题问题,请各位指点。运行的时候一直到printf那里都是没有问题的。 调用的代码如下 ``` #include "stdafx.h" #include <stdio.h> #include <windows.h> typedef void(*MAINFUNCTION)(int Type, const char *HandleNum, const char *MiddleNum, const char *PoleNum, const char *BladeNum); int _tmain(int argc, _TCHAR* argv[]) { HMODULE hModule1 = GetModuleHandle(L"D:\\Program Files\\Siemens\\NX 10.0\\UGII\\NX10_NXOpenCPP_Wizard1.dll"); if (NULL == hModule1) { hModule1 = LoadLibraryEx(L"D:\\Program Files\\Siemens\\NX 10.0\\UGII\\tool_assenbal_external.dll", NULL, LOAD_WITH_ALTERED_SEARCH_PATH); //hModule1 = LoadLibrary(L"D:\\Program Files\\Siemens\\NX 10.0\\UGII\\NX10_NXOpenCPP_Wizard1.dll"); } MAINFUNCTION Mainfunction = (MAINFUNCTION)GetProcAddress(hModule1, "Mainfunction"); const char *HandleNum2 = "BT40-ER32-70"; const char *MiddleNum2 = "ER32-12"; const char *PoleNum2 = "D10"; const char *BladeNum2 = ""; printf("测试代码1!"); Mainfunction(2, HandleNum2, MiddleNum2, PoleNum2, BladeNum2); FreeLibrary(hModule1); getchar(); return 0; } ``` 函数体如下 ``` extern "C" DllExport void Mainfunction(int Type, const char *HandleNum, const char *MiddleNum, const char *PoleNum, const char *BladeNum) { //以下为用户代码 Handle = "D:\\Program Files\\Siemens\\NX 10.0\\SECONDARY_DEVELOPMENT\\DateBase\\ToolBase\\刀柄库\\"; Middle = "D:\\Program Files\\Siemens\\NX 10.0\\SECONDARY_DEVELOPMENT\\DateBase\\ToolBase\\夹套库\\"; Pole = "D:\\Program Files\\Siemens\\NX 10.0\\SECONDARY_DEVELOPMENT\\DateBase\\ToolBase\\刀杆库\\"; Blade = "D:\\Program Files\\Siemens\\NX 10.0\\SECONDARY_DEVELOPMENT\\DateBase\\ToolBase\\刀片库\\"; HandleBase = "D:\\Program Files\\Siemens\\NX 10.0\\SECONDARY_DEVELOPMENT\\DateBase\\ToolBase\\HandleBase.dat"; MiddleBase = "D:\\Program Files\\Siemens\\NX 10.0\\SECONDARY_DEVELOPMENT\\DateBase\\ToolBase\\MiddleBase.dat"; PoleBase = "D:\\Program Files\\Siemens\\NX 10.0\\SECONDARY_DEVELOPMENT\\DateBase\\ToolBase\\PoleBase.dat"; CompletePath = "D:\\Program Files\\Siemens\\NX 10.0\\SECONDARY_DEVELOPMENT\\DateBase\\ToolBase\\整刀库\\"; if( UF_CALL(UF_initialize()) ) { /* Failed to initialize */ return ; } printf("开始导入!\n"); //新建一个prt tag_t PartTAG = NULL_TAG; UF_CALL(UF_PART_new("D:\\Program Files\\Siemens\\NX 10.0\\SECONDARY_DEVELOPMENT\\DateBase\\Temp\\Test.prt", UF_PART_METRIC, &PartTAG)); char ToolPath[255]; if (1 == Type) { ImportHandle(HandleNum); sprintf_s(ToolPath, "%s",CompletePath, HandleNum, "+", BladeNum, ".prt"); } else if (2 == Type) { ImportHandle(HandleNum); ImportMiddle(MiddleNum); ImportPole(PoleNum); sprintf_s(ToolPath, "%s",CompletePath, HandleNum, "+", MiddleNum, "+", PoleNum,".prt"); } else { ImportHandle(HandleNum); ImportMiddle(MiddleNum); ImportPole(PoleNum); sprintf_s(ToolPath, "%s",CompletePath, HandleNum, "+", MiddleNum, "+", PoleNum, BladeNum, ".prt"); } printf("导入完成!\n"); UF_CALL(UF_PART_save_as(ToolPath)); UF_CALL(UF_PART_close(PartTAG, 0, 1)); UF_CALL(UF_terminate()); return ; } ```
©️2020 CSDN 皮肤主题: 我行我“速” 设计师: Amelia_0503 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值