我有一个用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中似乎很难?
答案 0 :(得分:2)
这在C ++ / CX中很难,因为确定堆栈中的函数需要代码来解析调试符号。在C#中,CLR确实在运行时工作以记住堆栈中的哪些方法,但在C ++ / CX中,函数的名称不会记录在生成的二进制文件中。换句话说,您在C#中获得的堆栈跟踪取决于C#功能:reflection。
此外,调用代码是一个普通的COM API,而不是C ++ / CX API,可能会导致异常。在这种情况下,异常是从下面的错误HRESULT
返回代码生成的,而不是在抛出异常时生成的。 (实际上,这是跨越组件边界时发生的事情;即使操作的两端都是C ++ / CX,也可以使用普通COM处理)因此,跟踪所需的堆栈不再可用。
C ++异常不记录堆栈跟踪。从好的方面来说,本机程序可以在发生未处理的异常时收集一个小型转储,如果需要,可以使用调试器查看堆栈。
答案 1 :(得分:1)
请记住,C ++ / CX程序是纯粹的非托管C ++代码。 CX语言扩展只使您可以轻松地在C ++代码中使用WinRT类型,它隐藏了COM实现细节。因此它得到了代码优化器的全面处理。哪个不尝试确保可以安全地执行堆栈遍历。特别是在不抛出异常的叶函数中。它将很容易省略设置EBP寄存器,EBP寄存器是指示堆栈激活帧基础的重要寄存器。
在托管代码中不是这种情况,例如C#。堆栈遍历在垃圾收集的运行时环境中非常重要。垃圾收集器必须执行它们以在收集垃圾时查找对象引用。代码访问安全性还取决于堆栈遍历。一个令人愉快的副作用是现在也很容易为异常生成堆栈跟踪。它甚至在框架api中公开,StackTrace类允许您在自己的代码中遍历堆栈。
没有简单的解决方法,你需要调试符号来拍摄它。和来自DbgHelp api的StackWalk64。由于程序在Windows功能的某些地方崩溃,你仍然无法到达任何地方。速度胜过C ++的便利性。