1

我有一个用 C++/CX 编写的 Windows 应用商店应用程序(适用于 Windows 8),并且我已经将一大块代码包装在一个 try/catch 块中。

catch 块正在工作并捕获异常,但到目前为止,我似乎只能打印出异常的“消息”部分,而不是完整的异常堆栈:

try
{
...
}
catch(Exception^ e)
{
   LogMessage("Exception caught: " + e->ToString());
}

当异常被捕获时,LogMessage 仅输出以下文本:

"Exception caught: The object already exists"

我尝试过 e->ToString() 和 e->Message,但两者都产生相同的输出,并且不包括完整的异常堆栈。

在 C# 中,输出完整的异常堆栈似乎真的很容易,所以我不确定为什么在 C++/CX 中看起来很困难?

4

2 回答 2

2

这在 C++/CX 中很困难,因为确定堆栈中的函数需要代码来解析调试符号。在 C# 中,CLR 确实在运行时工作以记住堆栈中的方法,但在 C++/CX 中,函数的名称不会记录在生成的二进制文件中。换句话说,您在 C# 中获得的堆栈跟踪取决于 C# 功能:反射。

此外,调用纯 COM API 而非 C++/CX API 的代码可能会导致异常。在这种情况下,异常是从HRESULT下面的错误返回代码生成的,而不是在引发异常的时候。(事实上​​,每当跨越组件边界时都会发生这种情况;即使操作的双方都是 C++/CX,也可以使用普通 COM 处理)因此,跟踪所需的堆栈不再可用。

C++ 异常不记录堆栈跟踪。从好的方面来说,当发生未处理的异常时,您可以从本机程序收集一个小型转储,如果需要,您可以使用调试器查看堆栈。

于 2013-03-22T02:10:37.677 回答
1

请记住,C++/CX 程序是纯非托管 C++ 代码。CX 语言扩展只使在 C++ 代码中使用 WinRT 类型变得容易,它隐藏了 COM 实现细节。所以它得到了代码优化器的全面处理。这并没有尝试确保可以安全地执行堆栈遍历。在不抛出异常的叶函数中尤其如此。它将很容易地省略设置 EBP 寄存器,该寄存器指示堆栈激活帧的基数。

在托管代码(如 C#)中,情况并非如此。堆栈遍历在垃圾收集的运行时环境中非常重要。垃圾收集器在收集垃圾时必须执行它们以查找对象引用。代码访问安全性也依赖于堆栈遍历。一个令人高兴的副作用是,现在为异常生成堆栈跟踪也变得非常容易。它甚至暴露在框架 api 中,StackTrace 类允许您在自己的代码中遍历堆栈。

对此没有简单的解决方法,您需要调试符号才能对其进行尝试。以及来自 DbgHelp api 的 StackWalk64。由于程序在 Windows 函数内部的某个地方崩溃了,因此您可能仍然无处可去。在 C++ 中,速度胜过便利性。

于 2013-03-22T03:05:16.353 回答