4
votes

I am working in an delphi IDE expert , and I need enumerate all the forms displayed by the Delphi IDE, currently i am using the Screen.Forms property , but i am wondering if exist another way to do this using the OTA. because using the Screen.Forms only works when my expert is a BPL but now i am migrating to a dll expert.

2

2 Answers

8
votes

Screen.Forms should still work from a DLL. Just make sure you compile your DLL with the "use runtime packages" linker option selected. That way, your DLL will use the same VCL instance as the IDE, and you'll have access to all the same global variables, including Screen.

2
votes

This is perfectly possible with the OpenToolsAPI.

To extract a list of all opened forms in the IDE, you could use something like this:

procedure GetOpenForms(List: TStrings);
var
  Services: IOTAModuleServices;
  I: Integer;
  Module: IOTAModule;
  J: Integer;
  Editor: IOTAEditor;
  FormEditor: IOTAFormEditor;
begin
  if (BorlandIDEServices <> nil) and (List <> nil) then
  begin
    Services := BorlandIDEServices as IOTAModuleServices;
    for I := 0 to Services.ModuleCount - 1 do
    begin
      Module := Services.Modules[I];
      for J := 0 to Module.ModuleFileCount - 1 do
      begin
        Editor := Module.ModuleFileEditors[J];
        if Assigned(Editor) then
          if Supports(Editor, IOTAFormEditor, FormEditor) then
             List.AddObject(FormEditor.FileName,
               (Pointer(FormEditor.GetRootComponent)));
      end;
    end;
  end;
end;

Note that the pointer in that StringList is an IOTAComponent. To resolve this to the TForm instance you must dig deeper. To be continued.

It's also possible to keep track of all forms being opened in the IDE by adding a notifier of type IOTAIDENotifier to the IOTAServices, as follows:

type
  TFormNotifier = class(TNotifierObject, IOTAIDENotifier)
  public
    procedure AfterCompile(Succeeded: Boolean);
    procedure BeforeCompile(const Project: IOTAProject; var Cancel: Boolean);
    procedure FileNotification(NotifyCode: TOTAFileNotification;
      const FileName: String; var Cancel: Boolean);
  end;

procedure Register;

implementation

var
  IdeNotifierIndex: Integer = -1;

procedure Register;
var
  Services: IOTAServices;
begin
  if BorlandIDEServices <> nil then
  begin
    Services := BorlandIDEServices as IOTAServices;
    IdeNotifierIndex := Services.AddNotifier(TFormNotifier.Create);
  end;
end;

procedure RemoveIdeNotifier;
var
  Services: IOTAServices;
begin
  if IdeNotifierIndex <> -1 then
  begin
    Services := BorlandIDEServices as IOTAServices;
    Services.RemoveNotifier(IdeNotifierIndex);
  end;
end;

{ TFormNotifier }

procedure TFormNotifier.AfterCompile(Succeeded: Boolean);
begin
  // Do nothing
end;

procedure TFormNotifier.BeforeCompile(const Project: IOTAProject;
  var Cancel: Boolean);
begin
  // Do nothing
end;

procedure TFormNotifier.FileNotification(NotifyCode: TOTAFileNotification;
  const FileName: String; var Cancel: Boolean);
begin
  if BorlandIDEServices <> nil then
    if (NotifyCode = ofnFileOpening) then
    begin
      //...
    end;
end;

initialization

finalization
  RemoveIdeNotifier;

end.