关于xml和interface的高难度问题(200分)

  • 主题发起人 主题发起人 rypan
  • 开始时间 开始时间
R

rypan

Unregistered / Unconfirmed
GUEST, unregistred user!
小弟使用msxml解析xml文件,得到一个document,
它的子节点都是interface(比如IXMLDOMNode,IXMLDOMElement等等)。
现在我想把子节点存放到TTreeView的节点里,
使用了function AddObject(Node: TTreeNode
const S: string
Ptr: Pointer):
但最后一个参数是Pointer,于是我使用了TObject(IXMLDOMNode)把interface强行转换
成了Pointer,使的编译通过。但在取node.Data时把再次强制类型转换
IXMLDOMNode(node.Data)时出错,请各位指教。
 
接口是带引用计数的,对接口变量进行赋值,作参数传递时 Delphi 会自动帮你生成调用
接口的 _AddRef、_Release 方法的代码,使用强制转换,则 Delphi 不会生成这些代码,
就可能引起你保存的接口指针无效,因为由于引用计数为零,实现该接口的对象可能已被
释放了。你可以用一个 proxy 类来保存接口指针:
TProxy = class
private
FXMLDOMNode: IXMLDOMNode;
public
property XMLDOMNode: IXMLDOMNode read FXMLDOMNode write FXMLDOMNode;
end;
然后可以这样操作:
var
Proxy: TProxy
begin
...
Proxy := TProxy.Create;
Proxy.XMLDOMNode :- AXMLDOMNOde;
//保存到TreeView中
TreeView1.AddObject(aNode, S, Pointer(Proxy));
...
//取出接口,调用接口方法
TProxy(bNode.Data).XMLDOMNode.方法(参数...);
...
end;
其实用 Record 也行,只是要用 New, Dispose 分配和释放空间。
 
to bbkxjy: 谢谢你的回答。但我的程序里用到了非常多的接口,每个都包装一把太麻烦了。
是不是有办法可以显式的使接口的记数加一。而且我认为即使是接口释放了,
它的对象还应该存在,是不是有办法直接获得接口所代表的对象(不是类)。
 
所有接口都是从 IUnknown 继承的,因此,你可以把接口都转成 IUnknown 接口保存,取出时
再转成相应的接口.其实手工调用 _AddRef 也是可以的,如

//将 IUnknown 转成 Pointer, 并调用 _AddRef, 保证实现接口的对象不被释放
function RefIUnknown(const Intf: IUnKnown): Pointer;
begin
Intf._AddRef
//显示调用 _AddRef
Result := Pointer(Intf);
end;

//由 Delphi 自动调用 _Release, 表明不再使用
procedure ReleaseIUnkonwn(P: Pointer);
var
Intf: IUnkown;
begin
Pointer(Intf) := P
//退出过程时,Delphi 生成的代码会自动调用 Intf._Release
end;
...
可以这样使用以上函数(过程);

//保存接口指针,假设 aIXMLDOMNode 是 IXMLDOMNode 类型的接口变量
TreeView1.AddObject(aNode, S, RefIUnknown(aIXMLDOMNode));
//使用已保存的接口指针
(IUnkown(TreeView1.Selected.Data) as IXMLDOMNode).接口方法(参数列表);
//不再需要接口时释放接口指针,如 TreeView1 的 aNode 结点被删除时
ReleaseRef(aNode.Data);

记住在使用一个接口时,一般先调用它的 _AddRef 使引用计数加一,保证实现该接口的对
象不会因引用计数为零而被释放,使用完毕再调用 _Release 使引用计数减一,保证对象能
正确被释放。一般如果你不是将接口指针强制转换为无类型指针,Delphi 会自动帮你生成
这些调用代码,象你这样直接转换,则必须显示调用。
 
多人接受答案了。
 
后退
顶部