delphi 从函数返回OleVariant会导致对所包含的IDispatch对象的额外引用无法释放

s6fujrry  于 2023-02-04  发布在  其他
关注(0)|答案(1)|浏览(169)

我有一个函数返回一个OleVariant,其中包含一个IDispatch引用计数对象:

class function TGrobber.Make: OleVariant;
begin
   Result := (TGrobber.Create as IDispatch);
   // Reference count of IDispatch inside Result at this point is 1
end;

函数的结尾,OleVariant内对象的RefCount正确为1
但是,当OleVariant返回给调用者时,包含的对象突然具有2的引用计数:

var
    grobber: OleVariant;
begin
    grobber := TGrobber.Make; // function that returns an OleVariant
    // Reference count of IDispatch inside OleVariant is now 2 (wrong)
end;

这是因为Delphi调用了Make函数之后,它调用了VarCopy

Project2.dpr.147: grobber := TGrobber.Make;
004DA79D 8D55E0           lea edx,[ebp-$20]
004DA7A0 A1DC614D00       mov eax,[$004d61dc]
004DA7A5 E8CAC0FFFF       call TGrobber.Make       <== Creates the object (refcount 1)
004DA7AA 8D55E0           lea edx,[ebp-$20]
004DA7AD B800444E00       mov eax,$004e4400
004DA7B2 E8B128F5FF       call @VarCopy            <== Adds an extra reference, loses the old reference

这意味着:

  • 编译器正在添加对返回变量的额外引用
  • 同时不释放旧的引用
  • 或者可替换地根本不调用@VarCopy

我如何确保德尔福:

  • 在制作拷贝后销毁旧的OleVariant
      • 不**复制OleVariant,因为它不需要复制
ykejflvf

ykejflvf1#

编译器不会丢失“旧”引用。TGrobber.Make()的结果首先存储在一个 hidden 局部变量中(位于[ebp-$20]),然后将其赋给grobber变量(位于$004e4400),因此复制。因此refcount为2是正确的。两个变量都将被最终化,refcount减2,当它们在包含例程退出时超出范围时。
您的代码 * 有效地 * 完成了以下等效操作:

var
  hidden: OleVariant;
  grobber: OleVariant;
begin
  TGrobber.Make(hidden); // function that returns an OleVariant via a hidden var parameter
  grobber := hidden; // VarCopy(grobber, hidden) is called here
  ...
end; // VarClear(grobber) and VarClear(hidden) are called here...

相关问题