Каким-то образом экземпляр объекта COM теряется - PullRequest
1 голос
/ 08 апреля 2009

У меня есть основное приложение, и библиотека типов содержит 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;

Из 2-го цикла, даже если fFiles.Count = 4, но все содержимое потеряно. Нужна ли дополнительная обработка в IFile для обработки AddRef и Release? или неправильный способ IFiles.Add, который я написал?

Ответы [ 3 ]

8 голосов
/ 08 апреля 2009

Попробуйте использовать TInterfaceList вместо TList для хранения экземпляров IFile. Это может решить вашу проблему.

1 голос
/ 08 апреля 2009

Проблема в исходном коде заключалась в том, что вы добавляли указатель IFile в список, но когда вы позже читали значение из списка, вы назначали указатель непосредственно другому * 1004. * переменная. Таким образом, вы имели значение 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 для всех ссылок интерфейса.

Но Ответ Тоби дает лучшую идею: используйте TInterfaceList для хранения списка интерфейсов. TList просто не подходит для этой задачи.

Последний совет: префикс «I» в именах используется для обозначения интерфейс типов. Интерфейсы не имеют собственных реализаций методов. Вы показали реализацию IFiles.Add, поэтому IFiles явно не тип интерфейса. Вместо этого оно должно быть названо TFiles или, может быть, TFileList.

0 голосов
/ 08 апреля 2009

COM-объекты автоматически высвобождаются, если на них нет ссылок. В коде 1 COM-объект освобождается в операторе "end".

Я думаю, вам нужно создать объект-оболочку, и этот объект-оболочка - это то, что вы добавляете в файлы.

Извините, у меня нет времени, чтобы создать пример прямо сейчас.

...