Delphi对象、NIL对象和接口

Delphi对象、NIL对象和接口,delphi,com,interface,null,Delphi,Com,Interface,Null,我正在寻找有关如何在使用Delphi VCL中的MS XML包装器的应用程序中调试崩溃的提示。我怀疑内存损坏,或者对象和接口之间发生了某种模糊的邪恶事件,比如引用计数错误,或者堆损坏。实际上,问题是:如何调试这样的崩溃 这段特殊的代码在内部大量使用并扩展了基本XmlIntf接口(IXMLNode)。ISomethingCustom是一个扩展IXMLNode的接口。问题发生在递归函数中的某个地方,该函数被传递一个ISomethingCustom,该函数也是(或在接口术语中也支持)IXMLNode

我正在寻找有关如何在使用Delphi VCL中的MS XML包装器的应用程序中调试崩溃的提示。我怀疑内存损坏,或者对象和接口之间发生了某种模糊的邪恶事件,比如引用计数错误,或者堆损坏。实际上,问题是:如何调试这样的崩溃

这段特殊的代码在内部大量使用并扩展了基本XmlIntf接口(IXMLNode)。ISomethingCustom是一个扩展IXMLNode的接口。问题发生在递归函数中的某个地方,该函数被传递一个ISomethingCustom,该函数也是(或在接口术语中也支持)IXMLNode

   boolean UtilityFunction( aNode: ISomethingCustom ):Boolean;
   begin
      if not Assigned(aNode) then exit; // this works. great.
      if not Assigned(aNode.ParentNode) then exit; // this DOES NOT WORK.
     // code that blows up if aNode.ParentNode is not assigned.
   end;
情况是阳极也是IXMLNode,并且IXMLNode.ParentNode值被赋值(不是nil),但它指向一个COM对象,该对象可能已被释放、破坏或以某种方式损坏。我试图弄清楚当一个接口指针看起来是有效的,但它背后的对象不知怎么被核化了时会发生什么

检查Assigned(aNode.ParentNode)返回TRUE,即使您尝试在调试器中强制转换(仅在运行时,而不是在代码中),如下所示:

  • 检查/评估阳极
  • 检查/评估TInterfacedObject(阳极)。类名 (至少在Delphi 2010中工作!)
  • 现在铸造之前的所有类别名称(阳极)
  • 在调试器中,我现在看到这是NIL。这可能意味着 神奇的“铸造界面回到” 中新增的“对象”功能 德尔福2010,是失败的
  • 我相信我正在尝试调试一个问题,其中由于引用计数问题,堆损坏,或者堆上的COM对象损坏


    我真的认为,任何人都不应该出现这样的情况:界面看起来有效,但下面的对象已被删除。我真的很想知道该做什么,以及发生了什么。

    胡乱猜测:您是否尝试将Anoder.ParentNode放入局部变量中,并在Utilityfunction的其余部分中使用它:

       function UtilityFunction(aNode: ISomethingCustom): Boolean;
       var
         lParentNode: INode;
       begin
          if not Assigned(aNode) then exit; // this works. great.
          lParentNode := aNode.ParentNode;
          if not Assigned(lParentNode) then exit;
         // code that uses lParentNode.
       end;
    

    虽然您没有在代码中显示它,但您的注释似乎表明您正在将接口变量类型转换为类类型。这是不允许的。我已经描述了原因:

    接口引用和对象引用指向的对象不相同。因此,当编译器认为您拥有另一个方法时,对其中一个方法调用该方法将产生意外的结果。您很不走运,因为代码继续运行,而不是因为访问冲突而崩溃,这将更大程度地表明您做错了什么


    我在上面的文章最后建议您使用
    JclSysUtils​.如果您有一个Delphi实现的接口,并且该接口本身不提供用于重新调用底层对象的函数,则从中获取ImplementorFinInterface
    函数。

    我的建议是确保在
    赋值(Anodel.ParentNode)
    中实际调用ParentNode函数。在Delphi中有一些令人讨厌的情况,没有参数的过程/函数不会被调用,而是在省略括号时引用它


    尝试将其更改为
    Assigned(Anode.ParentNode())
    (这应该与François的建议具有相同的效果)。

    它似乎是一个有效的非nil接口指针,但当回溯到像TXMLNode(Anode)这样的对象时,会得到nil。有时,这在调试时起作用,但在代码中不起作用(代码看不到nil,但调试器看到)。大多数Delphi版本不允许您将接口指针类型转换回对象指针。这是一个仅在Delphi 2010或XE中可用的较新功能,我忘了是哪个引入了它。在此之前,从接口指针获取对象指针的唯一方法是让接口实现一个返回实现类自身指针的方法。我们并非有意进行任何此类强制转换,只是我在调试器中进行了强制转换,发现如果您在调试器表达式求值器中找到该类的第一个类,则可以将其强制转换回该类。检查Assigned(aNode.ParentNode)返回TRUE,即使TNode(aNode.ParentNode)实际上为NIL。一定是做了什么坏了的事。在我注意到某些内容被破坏之前,我不会故意执行任何强制转换,然后我在调试器中的求值表达式中执行强制转换,只是为了看看是否可以看到接口背后的内容。:-)将接口指针类型转换回其实现类指针是Delphi 2010或XE中的一个新功能,我忘了是哪一个引入了它。我只是将其转换回对象,因为我注意到这样的转换导致了一个NIL值,并发现这很奇怪。在运行时,我实际上并没有执行这样的强制转换,除了作为调试代码,在发现您所说的内容后,我很快将其删除。它仍然崩溃,这意味着我要么是堆损坏,要么是出了问题。我几乎完全重写了我的问题,我希望它能让我的情况更加清楚。你上面的“指针”让我明白了一些我以前不理解的东西,这很好。考虑到我对情况的完全误解,我想知道这个问题是否可以解决,或者当我知道更多的事情发生时,我是否应该再次重写它。