【问题标题】:.NET COM Interop -> Global exception handler.NET COM 互操作 -> 全局异常处理程序
【发布时间】:2015-05-03 10:35:00
【问题描述】:

我有一个 .NET 程序集,它通过来自 Delphi 主机的 COM 互操作调用。 我知道 .NET 代码中任何未处理的异常都将由 .net com 互操作框架处理,并且相应的 HRESULT 将返回给 COM 主机 (delphi)。但是,在此异常到 HRESULT 转换期间,堆栈信息会丢失。

问题是我们想在 .net 代码中记录所有未处理的异常,但我没有找到任何方法来注册一个在发生此类异常时实际调用的 catch-all 处理程序。

我试过了:

  • AppDomain.CurrentDomain.UnhandledException
  • Dispatcher.CurrentDispatcher.UnhandledException

但在 COM Interop 下运行时不会调用这些。

是否可以为 COM 互操作框架的未处理异常定义某种处理程序/回调?或者以某种方式挂钩将托管异常转换为 HRESULT 以便记录异常的过程?

谢谢!

【问题讨论】:

  • 我认为最好的办法是在暴露给 COM 的 C# 方法中的任何地方都使用 try { .. } catch (Exception ex) { /* save ex*/; throw; } 之类的东西。或者,您可以处理 AppDomain.CurrentDomain.FirstChanceException 并存储最后一次机会异常,您也可以将其公开给 COM。
  • @Noseratio 您的建议有效。我没有找到更好的方法。您应该将其添加为答案,以便我接受。
  • @Noseratio 不幸的是,您提出的更好的方法不适用于我的情况。然而,这是由于 Delphi 中的一个缺陷造成的。请参阅 cmets 您的答案。我最终定义了 FirstChanceExceptions 的处理程序并存储了最后一个。

标签: .net delphi com


【解决方案1】:

我认为这里最好的选择是使用类似的东西

void ComClassMethod()
{
    try { ... } 
    catch (Exception ex) 
    { 
        /* store the ex in the object */; 
        throw; 
    } 
}

C# 方法中暴露给 COM 的所有地方。

或者,您可以处理 AppDomain.CurrentDomain.FirstChanceException 并存储最后一次机会异常,您也可以将其公开给 COM。

但是,如果您的 COM 对象支持多线程(请注意,大多数 .NET COM objects are free-threaded),请特别注意。在这种情况下,您需要通过System.Threading.ThreadLocal<T> 在每个对象或全局范围内维护线程及其对应的最近异常之间的映射(确定更适合您的日志记录要求的内容)。


更新,我一直在想,必须有更好的方法来做到这一点。在 Adam Nathan 出色的“.NET 和 COM:完整的互操作性指南”一书中,确实有一个 explained here。我不确定我是否可以从受版权保护的材料中复制/粘贴准确的引用,但想法如下:

  • 所有 .NET CCW 对象都实现 ISupportErrorInfo
  • 扩展的错误信息 - 通过 IErrorInfo 对象 - 可以在 COM 端通过 GetErrorInfo API 检索。
  • 根据 Adam Nathan 的说法,该对象也本身就是 .NET 异常对象,它实现了_Exception COM 接口。
  • COM 客户端可以使用_Exception 获取所有详细信息,包括_Exception.StackTrace

这似乎正是您想要的。

【讨论】:

  • 使用 SafeCall 约定时,Delphi 将自动调用 GetErrorInfo 并引发 EOleException 类型的 delphi 异常,该异常由检索到的 IErrorInfo 对象中的值填充。不幸的是,EOleException 没有对 IErrorInfo 对象的任何引用。如果我了解 GetErrorInfo 文档。正确:“它将错误对象的所有权转移给调用者,并清除线程的错误状态。”这意味着在 Delphi 完成“魔术”后调用 GetErrorInfo 时,ErrorInfo 对象不再可用。
  • 上一条评论的空间不足。当我随后调用 GetErrorInfo 时,我无法再检索 IErrorInfo 对象。它永远失去了......
  • @santiagoIT,我明白了。我的 Delphi 知识非常有限,但我记得可以使用从 typelib 生成的原始 COM 接口,而无需智能包装器。我知道这可能不适合您。
猜你喜欢
  • 1970-01-01
  • 2014-04-17
  • 2012-12-31
  • 2011-05-19
  • 2011-08-31
  • 2010-12-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多