是否可以捕获或隐藏非托管异常窗口?

Posted

技术标签:

【中文标题】是否可以捕获或隐藏非托管异常窗口?【英文标题】:Is it possible to catch or hide an unmanaged exception window? 【发布时间】:2020-04-14 08:17:38 【问题描述】:

考虑使用本机代码(由于某些原因无法修改):

#include <cstdio>
#include <exception>

extern "C" 
    __declspec(dllexport) void terminate_me(void) 
        puts("hello from C");
        std::terminate();
        puts("bb from C");
    

从 C# 中调用(我们可以以任何我们想要的方式进行更改)

using System.Runtime.InteropServices;

class Program

    [DllImport("Project1.dll")]
    static extern void terminate_me();

    static void Main(string[] args)
    
        terminate_me();
    

这就是正在发生的事情:

我的问题是我们可以在不向用户显示此窗口的情况下使应用程序崩溃吗?我的意思是好的,非托管代码发生了一些不好的事情,只需关闭带有错误代码的应用程序,不要向用户显示任何内容。

可行吗?

【问题讨论】:

构建发布版本? 在发布时我什至没有得到Hello from C:Unhandled Exception: System.BadImageFormatException: An attempt was made to load a program with an incorrect format. (Exception from HRESULT: 0x8007000B)。 (我仔细检查了正确的目标平台) 我不明白这个问题。你的 C++ 程序没有崩溃;它调用std::terminate,它具有明确定义的行为。你最终想要完成什么? 我想改变调用外部 C++ 程序的行为。我现在发现的唯一方法是启动一个新进程,这样它就会被终止而不是我的。 【参考方案1】:

使用_CrtSetReportMode 函数,如下所示:

extern "C" 
    __declspec(dllexport) void terminate_me(void) 
        _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG); // define that anywhere in your init code, etc.
        puts("hello from C");
        std::terminate();
        puts("bb from C");
    

请注意,如果未定义 _DEBUG(因此,在发行版中),对 _CrtSetReportMode 的调用将在预处理期间删除。

您的BadImageFormatException 错误可能来自您在发布模式下选中了 .NET 项目属性中的“首选 32 位”复选框这一事实。此错误始终是 x86-x64 不匹配问题。

【讨论】:

我在上面评论说我用精确位数替换了AnyCPU,这个设置在调试/发布之间共享,你已经看到我能够在调试中运行它。回到你的答案:不幸的是我不能使用_CrtSetReportMode,因为在这个例子中我只能更改 C# 代码。我编辑了我的问题以符合我的隐含限制,对于给您带来的不便,我深表歉意。那么,问题是我们是否可以在不接触 C++ 代码的情况下处理它? (这是一个以二进制形式共享的闭源项目)。 但也许_CrtSetReportMode 是全球性的?在这种情况下,我可以从 C# 调用此函数并更改 C++ 代码行为? @AlexZhukovskiy - 是的,它是全球性的,所以你可以 p/invoke 它(类似于[DllImport(@"ucrtbased.dll")] private static extern int _CrtSetReportMode(int reportType, int reportMode);)。但取决于您的编译方式,它并不总是从同一个 .dll 导出。在我的电脑上,它是从 ucrtbase(d).dll (docs.microsoft.com/en-us/cpp/c-runtime-library/…) 导出的

以上是关于是否可以捕获或隐藏非托管异常窗口?的主要内容,如果未能解决你的问题,请参考以下文章

C#:捕获混合托管/非托管进程的所有错误/异常

.NET 外部非托管库函数引发无法捕获的异常

将托管引用存储在非托管内存中

捕获arm非托管磁盘虚拟机,并进行还原

使用 P/Invoke 在托管和非托管回调链上引发异常

是否在CLR上运行非托管Visual C ++?