Delphi - 在运行时创建的TXMLDocument生成AV,而表单上的组件正在工作

9
我正在运行时创建一个 TXMLDocument 实例,用于加载和解析 XML 文件。您可以检查下面的代码:
    unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, xmldom, XMLIntf, msxmldom, XMLDoc, StdCtrls;

type
  Txml = class(TForm)
//    XMLDocument1: TXMLDocument;
    Memo1: TMemo;
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  xml: Txml;

implementation

{$R *.dfm}

procedure Txml.FormCreate(Sender: TObject);
var    i,j:integer;
       aNode:IXMLNode;
       ws:String;
       XMLDocument1:TXMLDocument;
begin
 Memo1.Lines.Clear;
 XMLDocument1 := TXMLDocument.Create(nil);
 try
  XMLDocument1.LoadFromFile('C:\a.xml');
  XMLDocument1.Active := true;
  aNode := XMLDocument1.ChildNodes.First;
  while aNode<>nil do
  begin
   for i := 0 to aNode.ChildNodes.Count-1 do
    begin
     if aNode.ChildNodes[i].NodeName = 'Role' then
      begin
       Memo1.Lines.Add('Tag - '+aNode.ChildNodes[i].ChildNodes['Tag'].Text);
       for j := 0 to aNode.ChildNodes[i].ChildNodes.Count-1 do
        if aNode.ChildNodes[i].ChildNodes[j].HasChildNodes then
         begin
          ws :=  VarToStr(aNode.ChildNodes[i].ChildNodes[j].ChildValues['Tag']);
          if trim(ws)<>'' then
           Memo1.Lines.Add(ws);
          ws :=  VarToStr(aNode.ChildNodes[i].ChildNodes[j].ChildValues['Value']);
          if trim(ws)<>'' then
           Memo1.Lines.Add(ws);
         end;
      end;
    end;
   aNode := aNode.NextSibling;
  end;
  XMLDocument1.Active := false;
 finally
   FreeAndNil(XMLDocument1);
 end;
end;

end.

问题在于这会产生一个AV(访问冲突)。正如您可能已经看到的那样,在组件位于表单上之前(//XMLDocument1:TXMLDocument;),代码是可以运行的。

为什么当组件在表单上时,代码能够正常工作,但当我在运行时创建它时,它却生成了AV?

LE:解决方案:根据答案/注释和Delphi帮助:

XMLDocument1 : IXMLDocument;  //not TXMLDocument

XMLDocument1 := LoadXMLDocument(...);

FreeAndNil;// must be deleted

3
使用 IXMLDocument 接口,并且使用构造函数 NewXMLDocument - TLama
AV 发生在哪里? - Kromster
1
在关闭和释放 XMLDocument1 之前,您应该在循环结束后执行 ANode:=nil; 以释放节点实例。 - Ondrej Kelle
1
关于实例化 IXMLDocument,我忽略了您正在加载文件,因此 LoadXMLDocument 是适合您的正确函数。 - TLama
@TLama - 没看到你的评论,我正在编辑问题并提供解决方案。+1 - RBA
2个回答

17

据我所知,你应该使用接口IDoc: IXMLDocument;

从官方文档可以得知:

当没有Owner创建TXMLDocument时,它的行为类似于接口对象。也就是说,当其所有接口被释放时,TXMLDocument实例会自动释放。但是,当TXMLDocument被创建为带有Owner的组件时,它的行为与其他任何组件相同,并且由其Owner释放。

换句话说,在使用nil Owner创建TXMLDocument实例时,不要对实例调用Free()FreeAndNil()方法,并且必须将对象分配给一个IXMLDocument变量,以便管理其现在活动的引用计数。


5
换句话说,当使用nil Owner创建一个TXMLDocument实例时,不要调用Free()FreeAndNil()来释放该实例,并且必须将对象分配给一个IXMLDocument变量,以便正确管理其现在活动的引用计数。 - Remy Lebeau

2
在运行时创建 TXMLDocument 时,您需要提供一个 Owner
XMLDocument1 := TXMLDocument.Create(xml);

1
是的,确实,这解决了问题,但所有这些代码将被放置在一个特殊的类中,位于一个单元内 :) +1 - RBA

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接