我正在寻找有关如何在使用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;
情况是aNode也是IXMLNode,IXMLNode.ParentNode值被赋值(不是nil),但它指向一个可能以某种方式被释放,破坏或损坏的COM对象。我试图弄清楚当接口指针看起来有效时会发生什么,但它背后的对象已经被某种方式破坏了。
Checking Assigned(aNode.ParentNode)返回TRUE,即使你在调试器中尝试强制转换(仅在运行时,而不是在代码中),如下所示:
我认为我正在尝试调试堆已损坏的问题,或者堆上的COM对象已损坏,因为引用计数问题。
我真的认为没有人会遇到界面显示有效的情况,但下面的对象已被删除。我真的很想知道该怎么做,以及发生了什么。
答案 0 :(得分:9)
虽然您没有在代码中显示它,但您的注释似乎表明您正在将接口变量压缩为类型。这是不允许的。我已经描述了原因:
接口引用和对象引用不指向相同的东西。因此,当编译器认为您拥有另一个时,调用一个方法将产生意外结果。你运气不好,因为代码继续运行而不是因访问冲突而崩溃,这可能是你做错事的一个更大的迹象。
上面的文章最后建议你使用JCL中的JclSysUtils.GetImplementorOfInterface
函数,如果你有一个Delphi实现的接口,并且接口不提供它自己的功能来揭示底层对象。
答案 1 :(得分:0)
狂野猜测:您是否尝试将aNode.ParentNode放在局部变量中并在其他功能函数中使用它:
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;
答案 2 :(得分:0)
我的建议是确保在Assigned(aNode.ParentNode)
中实际调用了ParentNode函数。在Delphi中有一些令人讨厌的角落情况,其中没有参数的过程/函数没有被调用,而是当你省略括号时它被引用。
尝试将其更改为Assigned(Anode.ParentNode())
(其效果与François建议相同)。