【问题标题】:How to catch unmanaged C++ exception in managed C++如何在托管 C++ 中捕获非托管 C++ 异常
【发布时间】:2011-10-14 13:44:32
【问题描述】:

我正在一个大型非托管 C++ 库和一个大型 C# 库上开发一个瘦托管 C++ 包装器。我需要捕获源自该大型非托管 C++ 库的错误,并将它们作为 Clr 异常重新抛出。非托管库抛出以下类的实例:

Error::Error(const std::string& file, long line,
             const std::string& function,
             const std::string& message) {
    message_ = boost::shared_ptr<std::string>(new std::string(
                                  format(file, line, function, message)));
}

const char* Error::what() const throw () {
    return message_->c_str();
}

到目前为止,我想出了这个:

try{
// invoke some unmanaged code
}
catch(Object*)
{
throw gcnew System::Exception("something bad happened");
}

如何从 Error 类中提取消息并将其转换为 Clr String 类,以便将其传递给 gcnew System::Exception() 构造函数? 如果非托管代码抛出其他东西,我的 catch 块会捕获它吗?

编辑:我正在使用 catch(Object*) 因为那是 recommended in MCDN

【问题讨论】:

  • 如果Error 的实例被抛出,你为什么要捕获Object*?在这种情况下,Object 到底是什么?
  • @ildjarn: 这个 Object* 事情是在 MSDN 上建议的
  • 这与 C++ 的托管扩展相关,而不是 C++/CLI。两种不同的语言,假设您使用的是 gcnew,那么您使用的是 C++/CLI。
  • @ArneLund:另外,那篇 MSDN 文章不建议通过 Object* 捕获。它对Object* 的唯一说明是警告它不能正常工作

标签: c# .net error-handling c++-cli


【解决方案1】:

以下内容不适合您吗?

try
{
    // invoke some unmanaged code
}
catch (Error const& err)
{
    throw gcnew System::Exception(gcnew System::String(err.what()));
}

因为这肯定对我有用:

#pragma managed(push, off)
#include <string>

struct Error
{
    explicit Error(std::string const& message) : message_(message) { }
    char const* what() const throw() { return message_.c_str(); }

private:
    std::string message_;
};

void SomeFunc()
{
    throw Error("message goes here");
}

#pragma managed(pop)

int main()
{
    using namespace System;

    try
    {
        try
        {
            SomeFunc();
        }
        catch (Error const& err)
        {
            throw gcnew Exception(gcnew String(err.what()));
        }
    }
    catch (Exception^ ex)
    {
        Console::WriteLine(ex->ToString());
    }
    Console::ReadLine();
}

【讨论】:

  • visual studio 2017 无法识别 gcnew,或出现异常提示
  • @Ali :我只能假设您出于某种原因不再使用/clr 进行编译。抱歉,我目前没有安装 VS 进行测试。
【解决方案2】:

我用

#include <exception>
#include <msclr\marshal.h>

using namespace System;
using namespace msclr::interop;

try
{
    ...
}

catch (const std::exception& e)
{
    throw gcnew Exception(marshal_as<String^>(e.what()));
}

catch (...)
{
    throw gcnew Exception("Unknown C++ exception");
}

您可能希望将其放入一对宏中,因为它们会在任何地方使用。

您可以使用 Error 类添加自定义 catch 块,但由于它似乎派生自 std::exception,所以我向您展示的代码应该没问题。

您还可以更具体地捕获 std::invalid_argument 并将其翻译成 ArgumentException 等,但我觉得这有点过头了。

【讨论】:

    【解决方案3】:

    我想出的捕获大多数非托管异常的唯一可靠方法是 catch (...),它不会为您提供任何重新抛出的信息,但可以防止大多数崩溃。仍然有一些例外,即使是 catch (...) 也不会捕获并且会使您的应用程序崩溃,即使没有崩溃指示器(应用程序只是消失),例如如果一个写得不好的第 3 方应用程序使用了错误的 SetJump/LongJump错误处理或线程协议。

    如果您想尝试键入许多 C++ 异常,可以编写一长串的 catch 块,例如:

    catch (int i)
    {
      // Rethrow managed with int data
    }
    catch (double d)
    {
        // Rethrow managed with double data
    }
    ... etc
    catch (...)
    {
        // Rethrow managed "I got a general exception" error
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-24
      • 2013-01-07
      相关资源
      最近更新 更多