不知何故COM对象实例丢失了

时间:2009-04-08 05:51:00

标签: delphi com

我有一个主app,一个类型库包含2个COM对象,一个是IFile,一个是IFiles。 IFiles创建IFile,并将它们存储在TLIST中,并具有标准方法,如Add,Remove等.IFile和IFiles都是TAutoObject。

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

[代码1]

function IFiles.Add(AFilename: String): IFile;
begin
  Result := CoIFile.Create;
  Result.Filename := AFilename;
  // ShowMessage(IntToStr(Result._AddRef));
  fFiles.Add(@Result);
end;

在主应用程序中,我有这样的测试代码。 [代码2]

var
  i: Integer;
  f: IFile;
  Files: IFiles;
begin
  Files := CoTIFile.Create;
  for i:= 1 to 4 do
  begin
    // Create a dummy file object
    f := Files.Add('Filename ' + IntToStr(i));
    f._AddRef; // Not sure if AddRef works like this
    // Prints out the last file
    Memo1.Lines.Add(Files.Files[i-1].Filename);
  end;

  for i:= 0 to Files.Count-1 do
  begin
    f := Files.Files[i];
    // F is nil at all time.
    if (f<>nil) then Memo1.Lines.Add(f.Filename); // ! No print out.
  end;  
end;

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

3 个答案:

答案 0 :(得分:8)

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

答案 1 :(得分:1)

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

要修复原始代码,您需要编写第二个类似的内容:

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._AddRef是正确的。当IFiles.Add返回时,结果的引用计数为1,因为存储在循环中的值是指针,而不是实际引用。您需要增加引用计数,因为f将重新用于其他值。由于您手动计数的引用存储在FFiles列表中,因此最好在_AddRef内调用IFiles.Add,而不是等到它返回。

当您清除列表时,或者当您从列表中删除项目时,您需要在所有界面引用上调用_Release

Toby's answer提供了更好的主意:使用TInterfaceList存储接口列表。 TList本身并不适合这项任务。

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

答案 2 :(得分:0)

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

我认为您需要创建一个包装器对象,并且该包装器对象是您添加到文件中的内容。

在索里,我现在没有时间创造一个例子。