Delphi 不知怎的,COM对象实例丢失了

Delphi 不知怎的,COM对象实例丢失了,delphi,com,Delphi,Com,我有一个主应用程序和一个类型库包含2个COM对象,一个是IFile,一个是IFiles。IFiles创建IFile,并将其存储在TLIST中,并具有标准方法,如添加、删除等。IFile和IFiles都是TAutoObject IFiles中的“Add”方法工作正常,它只创建IFile对象[Code 1],并将其添加到TList。问题是IFile对象实例以一种非常奇怪的方式丢失。见[守则2] [守则一] function IFiles.Add(AFilename: String): IFile;

我有一个主应用程序和一个类型库包含2个COM对象,一个是IFile,一个是IFiles。IFiles创建IFile,并将其存储在TLIST中,并具有标准方法,如添加、删除等。IFile和IFiles都是TAutoObject

IFiles中的“Add”方法工作正常,它只创建IFile对象[Code 1],并将其添加到TList。问题是IFile对象实例以一种非常奇怪的方式丢失。见[守则2]

[守则一]

function IFiles.Add(AFilename: String): IFile;
begin
  Result := CoIFile.Create;
  Result.Filename := AFilename;
  // ShowMessage(IntToStr(Result._AddRef));
  fFiles.Add(@Result);
end;
在主应用程序中,我有这样的测试代码。 [守则二]

var
i:整数;
f:IFile;
档案:IFiles;
开始
文件:=CoTIFile.Create;
对于i:=1到4 do
开始
//创建一个虚拟文件对象
f:=Files.Add('Filename'+IntToStr(i));
f、 _AddRef;//不确定AddRef是否像这样工作
//打印出最后一个文件
Memo1.Lines.Add(Files.Files[i-1].Filename);
结束;
对于i:=0到Files.Count-1 do
开始
f:=Files.Files[i];
//F始终为零。
如果是(fnil),则Memo1.Lines.Add(f.Filename);/!没有打印出来。
结束;
结束;

从第二个循环开始,尽管fFiles.Count=4,但所有内容都已丢失。我是否需要在IFile中进行一些额外的处理来处理AddRef和Release?或者我写的IFiles.Add方法是错误的?

如果没有对COM对象的引用,我会自动释放COM对象。 在代码1中,COM对象在“end”语句中被释放

我认为您需要创建一个包装器对象,这个包装器对象就是您添加到文件中的对象


抱歉,我现在没有时间创建一个示例。

如果没有对COM对象的引用,我会自动发布COM对象。 在代码1中,COM对象在“end”语句中被释放

我认为您需要创建一个包装器对象,这个包装器对象就是您添加到文件中的对象


抱歉,我现在没有时间创建示例。

尝试使用TInterfaceList而不是TList来存储IFile的实例。这可能会解决您的问题。

尝试使用TInterfaceList而不是TList来存储IFile的实例。这可能会解决您的问题。

原始代码中的问题是您向列表添加了一个
IFile
指针,但当您稍后从列表中读取一个值时,您将指针直接指定给另一个
IFile
变量。因此,实际上是一个
PIFile
值,存储在
IFile
变量中。Delphi通常允许您将非类型化的
指针
类型分配给任何类似指针的类型,包括接口

要修复原始代码,您需要编写第二个代码,如下所示:

var
  p: Pointer;

for i := 0 to Pred(Files.Count) do begin
  p := Files.Files[i];
  if not Assigned(p) then
    continue;
  f := IFile(p^);
  if not Assigned(f) then
    continue;
  Memo1.Lines.Add(f.Filename);
end;
您在第一个循环中调用
f.\u AddRef
是正确的。当
IFiles.Add
返回时,结果上的引用计数为
1
,因为循环中存储的值是指针,而不是实际引用。您需要增加引用计数,因为
f
将被重新用于其他值。由于手动计数的引用存储在
IFiles
列表中,因此最好在
IFiles.Add中调用
\u AddRef
,而不是等待它返回

清除列表或从列表中删除项目时,需要对所有接口引用调用
\u Release

但是给出了更好的想法:使用
TInterfaceList
存储接口列表
TList
本身并不适合该任务


最后一条建议:名称上的“I”前缀用于表示接口类型。接口没有自己的方法实现。您已经展示了
IFiles.Add
的实现,因此
IFiles
显然不是一种接口类型。它应该被命名为
TFiles
,或者可能是
TFileList

原始代码中的问题是您向列表添加了一个
IFile
指针,但是当您稍后从列表中读取一个值时,您直接将指针分配给另一个
IFile
变量。因此,实际上是一个
PIFile
值,存储在
IFile
变量中。Delphi通常允许您将非类型化的
指针
类型分配给任何类似指针的类型,包括接口

要修复原始代码,您需要编写第二个代码,如下所示:

var
  p: Pointer;

for i := 0 to Pred(Files.Count) do begin
  p := Files.Files[i];
  if not Assigned(p) then
    continue;
  f := IFile(p^);
  if not Assigned(f) then
    continue;
  Memo1.Lines.Add(f.Filename);
end;
您在第一个循环中调用
f.\u AddRef
是正确的。当
IFiles.Add
返回时,结果上的引用计数为
1
,因为循环中存储的值是指针,而不是实际引用。您需要增加引用计数,因为
f
将被重新用于其他值。由于手动计数的引用存储在
IFiles
列表中,因此最好在
IFiles.Add中调用
\u AddRef
,而不是等待它返回

清除列表或从列表中删除项目时,需要对所有接口引用调用
\u Release

但是给出了更好的想法:使用
TInterfaceList
存储接口列表
TList
本身并不适合该任务

最后一条建议:名称上的“I”前缀用于表示接口类型。接口没有自己的方法实现。您已经展示了
IFiles.Add
的实现,因此
IFiles
显然不是一种接口类型。它应该被命名为
TFiles
,或者可能是
TFileList