I have a function that returns an OleVariant that contains an IDispatch reference counted object:
class function TGrobber.Make: OleVariant;
begin
Result := (TGrobber.Create as IDispatch);
// Reference count of IDispatch inside Result at this point is 1
end;
And the end of the function, the RefCount of the object inside the OleVariant is correctly 1.
But when the OleVariant is returned to the caller, the contained object suddenly has a reference count of 2:
var
grobber: OleVariant;
begin
grobber := TGrobber.Make; // function that returns an OleVariant
// Reference count of IDispatch inside OleVariant is now 2 (wrong)
end;
This is because after Delphi calls the Make function, it calls 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
Which means:
- the compiler is adding an extra reference to the returned variable
- while not releasing the old reference
- or alternatively not calling
@VarCopyat all
How can i ensure that Delphi either:
- destroys the old
OleVariantafter it makes a copy - not make a copy of the
OleVariant, since it doesn't need to make a copy
The compiler does not lose the "old" reference. The result of
TGrobber.Make()is first stored in a hidden local variable (located at[ebp-$20]), which is then assigned to yourgrobbervariable (located at$004e4400), hence the copy. So the refcount being 2 is correct. Both variables will be finalized, decrementing the refcount by 2, when they go out of scope when the containing routine exits.Your code is effectively doing the equivalent of this: