2

I am using Delphi XE IDE. I create a notifier to implement IOTACompileNotifier. After install the expert in the IDE. The code works fine when I compile my project. The notifier is working for ProjectCompileStarted.

The second time I compile my project, the Delphi IDE prompt:

[Fatal Error] Access violation at address 21B7FBED in module 'delphicoreide150.bpl'. Read of address 00000000

Although it seems weird that I perform:

var i: integer;
begin
  i := Project.ProjectBuilder.AddCompileNotifier(TProjectCompileNotifier.Create);
  Project.ProjectBuilder.RemoveCompileNotifier(i);
end;

in notifier. I just want to show Add and Remove compile notifier for ProjectBuilder seems not functioning properly no matter how I use.

Please advise how should I implement IOTAProjectCompileNotifier.

Thank you.

Here are the full source code:

type
  TProjectCompileNotifier = class(TInterfacedObject, IOTAProjectCompileNotifier)
  protected
    procedure AfterCompile(var CompileInfo: TOTAProjectCompileInfo);
    procedure BeforeCompile(var CompileInfo: TOTAProjectCompileInfo);
    procedure Destroyed;
  end;

  TCompileNotifier = class(TInterfacedObject, IOTACompileNotifier)
  protected
    procedure ProjectCompileStarted(const Project: IOTAProject; Mode: TOTACompileMode);
    procedure ProjectCompileFinished(const Project: IOTAProject; Result: TOTACompileResult);
    procedure ProjectGroupCompileStarted(Mode: TOTACompileMode);
    procedure ProjectGroupCompileFinished(Result: TOTACompileResult);
  end;

procedure TCompileNotifier.ProjectCompileStarted(const Project: IOTAProject;
  Mode: TOTACompileMode);
var i: integer;
begin
  i := Project.ProjectBuilder.AddCompileNotifier(TProjectCompileNotifier.Create);
  Project.ProjectBuilder.RemoveCompileNotifier(i);
end;

var i: integer;

initialization
  i := (BorlandIDEServices as IOTACompileServices).AddNotifier(TCompileNotifier.Create);
finalization
  (BorlandIDEServices as IOTACompileServices).RemoveNotifier(i);
end.
Chau Chee Yang
  • 18,422
  • 16
  • 68
  • 132
  • 3
    please note [tagline advertising is not welcome here](http://meta.stackexchange.com/questions/5029/are-taglines-signatures-disallowed/5038#5038). I'm not down-voting but you shall edit your question! – jachguate Mar 26 '11 at 07:07
  • @jachguate: I am sorry. I paste the question from my email and didn't notice there is signature at the bottom. – Chau Chee Yang Mar 26 '11 at 10:48

3 Answers3

4

I think I might be able to answer this. I don't have XE and so I don't appear to have IOTAProjectCompileNotifier. However, the other AddNotifier methods in my ToolsAPI unit suggest it will be declared as:

function AddNotifier(const ANotifier: IOTAProjectCompileNotifier): Integer;

You call this routine this way:

i := Project.ProjectBuilder.AddCompileNotifier(TProjectCompileNotifier.Create);

The problem is that nothing takes a reference to the interface returned by TProjectCompileNotifier.Create. You need to do so, like this:

procedure TCompileNotifier.ProjectCompileStarted(const Project: IOTAProject; Mode: TOTACompileMode);
var
  i: integer;
  Intf: IOTAProjectCompileNotifier;
begin
  Intf := TProjectCompileNotifier.Create;
  i := Project.ProjectBuilder.AddCompileNotifier(Intf);
  Project.ProjectBuilder.RemoveCompileNotifier(i);
end;

You'd need to do likewise in the initialization/finalization code.

I believe that this really should be considered a bug in the interface reference counting implementation. It has been discussed here on Stack Overflow many times.

Community
  • 1
  • 1
David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • @David: I tried the code you suggest. I still get the same error. – Chau Chee Yang Mar 27 '11 at 00:44
  • @Chau Have you worked out where the AV occurs? If you can't user the debugger then put in some calls to MessageBox! – David Heffernan Mar 27 '11 at 00:45
  • @David: Yes. I use OutputDebugString to guard all 4 methods of IOTACompileNotifier. On 1st build, all the 4 methods invoked in this sequence: ProjectGroupCompileStarted, ProjectCompileStarted, ProjectCompileFinished, ProjectGroupCompileFinished. On 2nd build, I get AV immediately after ProjectGroupCompileStarted. – Chau Chee Yang Mar 27 '11 at 01:00
  • @Chau and you did what I said in every place where you create an interface? – David Heffernan Mar 27 '11 at 09:28
  • @David: Yes I have double check my code. I can't think of other possibilities except there is bug in OTA source. I used IInterface a lot in my application and am aware about the reference count problem you mentioned. That is why I am so sensitive about RemoveCompileNotifier or else I would just ignore that. I must see the object get freed at the right place else it would lead to disastrous memory leaks in IDE runtime. – Chau Chee Yang Mar 27 '11 at 11:00
3

I wonder why you're removing your notifier from within the callback. I could imagine that scenario is not handled well by OTA. Try the following: first (when the package is loaded and initialized) install an IOTAIDENotifier to be notified when a project is open (remove it in finalization). Implement its FileNotification to add your IOTAProjectCompileNotifier when a project is open, remove it when it's closed.

Ondrej Kelle
  • 36,941
  • 2
  • 65
  • 128
  • I have done a draft test on your suggestion and it seems works. However, I need quite a bit of coding to retrieve the IOTAProject instance in FileNotification method. I also need to cache a list of (IOTAProject, Index) when open the projects. Remove the notifier by looking for Index in the cache list. – Chau Chee Yang Mar 27 '11 at 02:00
0

error code "Read of address 00000000" can indicate that you are trying to access a resource which does not exist. I saw that you've asked the same question on the Embarcadero forum. From what I saw on here on SO, there are only several developers who are interested on OTA, the documentation from CG or Embarcadero is almost inexistent, so I'm suggesting you to insist on Embarcadero's forum.

best regards,
Radu

RBA
  • 12,337
  • 16
  • 79
  • 126