问题 如何在托管C ++中捕获非托管C ++异常


我正在一个大型非托管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 *),因为它是 在MCDN中推荐


10976
2017-07-27 19:26


起源

如果实例 Error 被扔了,你为什么要抓 Object*?是什么 Object 在这种情况下呢? - ildjarn
@ildjarn:在MSDN上建议使用此Object * - Arne Lund
这与C ++的托管扩展相关,而不是C ++ / CLI。两种不同的语言,给你使用 gcnew,你正在使用C ++ / CLI。 - ildjarn
@ArneLund:此外,该MSDN文章不建议捕获 Object*。它唯一说的是 Object* 是一个 警告它不能正常工作。 - Mooing Duck


答案:


以下不适合您吗?

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();
}

9
2017-07-27 20:08





我用

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

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

您可以添加自定义 catch 阻止你的 Error 上课,但因为它似乎来源于 std::exception,我给你看的代码应该没问题。

你也可能想要更具体地捕捉 std::invalid_argument 并将其翻译成 ArgumentException等,但我发现这有点过分。


4
2017-07-27 20:17





我想出来捕获大多数非托管异常的唯一可靠方法是catch(...),它不会给你任何重新抛出的信息,但会阻止大多数崩溃。甚至还有一些例外,即使没有崩溃指示器(应用程序只是消失),即使捕获(...)也不会捕获并且会使应用程序崩溃,就像一个写得不好的第三方应用程序使用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
}

2
2017-07-27 19:41