3

我有一个 C# 应用程序App A,它通过 P/Invoke 调用 C++ (Qt) DLL App B。假设我不能以任何方式编辑App B,但我知道这是在一组条件下App B抛出一个我可以复制但在将输入从to传递之前无法准确测试的条件。此异常不会对任何威胁构成任何威胁,如果可以以某种方式“重置”,则可以将其忽略,但是当崩溃时,它会调用这反过来会导致的运行时终止。Out of Memory ExceptionApp AApp BApp AApp BApp Babort()App A

我怎样才能防止App B不可避免的、不可预测的和通常平凡的崩溃影响App A

笔记:

  • UnhandledExceptionHandler抛出此错误时将忽略已实现。
  • App B由于 QtWebkit 中的错误而崩溃,可以App B通过删除过大的对象并返回 null 来处理该错误。
  • App A不会报告为内存不足,并且机器有足够的内存来多次执行's 操作,无论错误如何,但无论出于何种原因,App B显然都没有分配此内存。App B
4

2 回答 2

3

您创建一个 shim 进程,其唯一目的是加载 App B 并使用某种 IPC 机制与 App A 通信。应用 A 生成 shim,如果 shim 崩溃,则应用 A 采取适当的操作(重新生成,向用户传达错误, ETC。)。

于 2013-02-06T19:19:10.397 回答
1

您可以处理来自非托管代码的 SIGABRT,但它有点混乱。有可能它可以完全在 C# 中完成,但我的方法需要一个 C++/CLI 程序集才能使其工作(至少它在一个过程中)。

步骤 1:创建一个 C++/CLI 类库项目,在 *.h 文件中放入以下函数

namespace ClassLibrary1 {

    public ref class Class1
    {
    public:
        static void callaborter();
    };
}

第2步:在cpp文件中输入以下代码:

// This is the main DLL file.

#include "stdafx.h"
#include <csetjmp>
#include <csignal>
#include <cstdlib>
#include <iostream>
#include "ClassLibrary1.h"
#include "..\Win32Project1\Win32Project1.h"


#pragma managed(push, off) 
jmp_buf env;

void on_sigabrt (int signum)
{
    longjmp (env, 1);
}

void run()
{
    if (setjmp (env) == 0) {
            signal(SIGABRT, &on_sigabrt);
            fnWin32Project1();
    }
    else {
            std::cout << "aborted\n";
    }
}

#pragma managed(pop)

void ClassLibrary1::Class1::callaborter()
{
    run();
}

我将我的类库和类的名称保留为默认值,我的中止函数是调用 fnWinProject1()。您需要将有问题的 DLL 直接链接到该项目(就像在 C++ 中一样)

在您的 C# 类中,包含对 C++/CLI 程序集的引用并调用“callaborter”方法。

运行中的代码将为 SIGABRT 设置一个捕获器(由 abort() 调用)并在 on_sigabrt() 中对其进行处理,这将导致整个函数退出。然后,您可以清理并重试。

我将把它作为 OP 选择有用名称的练习。

注意:在 Debug 中,您仍然会看到 abort 对话框,只需按 Ignore 继续。在 Release 中,您将看不到该对话框。

PS我应该提到我基于这个stackoverflow问题建立了我的回复:如何处理SIGABRT信号?

于 2013-02-06T20:25:22.937 回答