【问题标题】:Somehow COM object instance gets lost不知何故 COM 对象实例丢失
【发布时间】:2011-12-02 04:20:58
【问题描述】:

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

IFiles 中的“Add”方法工作正常,它只是创建 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 方法不对?

【问题讨论】:

    标签: delphi com


    【解决方案1】:

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

    【讨论】:

      【解决方案2】:

      原始代码中的问题是您向列表添加了一个IFile 指针,但是当您稍后从列表中读取一个值时,您将指针直接分配给另一个@ 987654323@ 变量。所以你拥有的本质上是一个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 列表中,因此最好在IFiles.Add 中调用_AddRef,而不是等到它返回。

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

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

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

      【讨论】:

        【解决方案3】:

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

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

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2012-03-09
          • 2011-07-24
          • 2013-03-22
          • 1970-01-01
          • 2011-04-18
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多