3

(Delphi XE2 update 4)

I'm trying to get a big Microsoft Word OLE automation unit I inherited (based on the early binding TWordApplication and interfaces from the WordXP/Word2010 units) to close WINWORD.EXE when all references have been released.

So far, it looks like I did catch a couple of reference leaks: most references are properties or local variables.

Some usage scenario's however still keep WINWORD.EXE open.

A few of the fixes indicate I should favour local variables in stead of chains from

procedure TOffice_10_XP_WordInterface.AddDocument;
var
  WordApplicationDocuments: Documents;
begin
  WordApplication_Documents.Add(EmptyParam, EmptyParam, EmptyParam, EmptyParam);
end;

to

procedure TOffice_10_XP_WordInterface.AddDocument;
var
  WordApplicationDocuments: Documents;
begin
  WordApplicationDocuments := WordApplication_Documents;
  WordApplicationDocuments.Add(EmptyParam, EmptyParam, EmptyParam, EmptyParam);
end;

based on a WordApplication_Documents property that calls this function:

function TOffice_10_XP_WordInterface.GetWordApplication_Documents: Documents;
begin
  Result := WordApplicationReference.Documents;
  if not Assigned(Result) then
    raise EAccessViolation.Create('Documents');
end;

The properties are there to make the EAccessViolation messages more readable than the $C0000005 errors you get in the debugger.

I'm wondering about generic (since I'll probably need this for other automation projects as well) ways to monitor _AddRef and _Release calls.

I did take a look at these links:

Community
  • 1
  • 1
Jeroen Wiert Pluimers
  • 23,965
  • 9
  • 74
  • 154

1 Answers1

1

A tedious way that gets you going is this:

Put breakpoints of all _AddRef and _Release calls in the Delphi System unit that are not inside TInterfacedObject specific methods.

Now eliminate (using conditional expressions) all the interfaces that are not part of Delphi (EAX contains the vTable pointer for each interface).

  1. Start debugging your application with a simple run/exit without doing much actual functionality:
  2. Before tracing in each call, make a note of the EAX value.
  3. If you end up in any of these methods: NopRelease, NopAddref, TInterfacedObject._AddRef, TInterfacedObject._Release, MemRelease, MemAddRef then add the EAX value to a conditional breakpoint instruction for all of the breakpoints like below.

Example conditional breakpoint expression for my application:

(EAX <> $401E58) and (EAX <> $54AD14) and (EAX <> $4A7C88) ...

This method has a lot of drawbacks, but it gets you going.

Drawbacks:

  • There are limitations on the length of the conditional breakpoint expression. Which means that if you continue to add and (EXA <> $xxxx) portions, the debugger will ignore those without indicating a warning.
  • You loose the setting if you exit Delphi without saving your desktop
  • It takes a lot of time to setup
Jeroen Wiert Pluimers
  • 23,965
  • 9
  • 74
  • 154