1

I'm trying to implement an IDE Wizard with ToolsApi and using the GExperts FAQ (http://www.gexperts.org/examples/GXModuleCreator.pas) as reference.

Although the bpl compiles, the unit doesn't shows up on the IDE. I'm Using Delphi 10.3.2 Rio.

unit ModuleCreator;

interface

uses
  SysUtils, Windows, Dialogs, ToolsAPI;

type
  TJIdeWizardSourceFile = class(TInterfacedObject, IOTAFile)
  private
    FSource: string;
  public
    function GetSource: string;
    function GetAge: TDateTime;
    constructor Create(const Source: string);
  end;

  TJIdeWizardModuleCreator = class(TInterfacedObject, IOTACreator, IOTAModuleCreator)
  public
    // IOTACreator
    function GetCreatorType: string;
    function GetExisting: Boolean;
    function GetFileSystem: string;
    function GetOwner: IOTAModule;
    function GetUnnamed: Boolean;
    // IOTAModuleCreator
    function GetAncestorName: string;
    function GetImplFileName: string;
    function GetIntfFileName: string;
    function GetFormName: string;
    function GetMainForm: Boolean;
    function GetShowForm: Boolean;
    function GetShowSource: Boolean;
    function NewFormFile(const FormIdent, AncestorIdent: string): IOTAFile;
    function NewImplSource(const ModuleIdent, FormIdent, AncestorIdent: string): IOTAFile;
    function NewIntfSource(const ModuleIdent, FormIdent, AncestorIdent: string): IOTAFile;
    procedure FormCreated(const FormEditor: IOTAFormEditor);
  end;

implementation

{ TJIdeWizardModuleCreator }

procedure TJIdeWizardModuleCreator.FormCreated(const FormEditor: IOTAFormEditor);
begin
  //
end;

function TJIdeWizardModuleCreator.GetAncestorName: string;
begin
  Result := 'Form';
end;

function TJIdeWizardModuleCreator.GetCreatorType: string;
begin
  Result := sUnit;
end;

function TJIdeWizardModuleCreator.GetExisting: Boolean;
begin
  Result := False;
end;

function TJIdeWizardModuleCreator.GetFileSystem: string;
begin
  Result := '';
end;

function TJIdeWizardModuleCreator.GetFormName: string;
begin
  Result := '';
end;

function TJIdeWizardModuleCreator.GetImplFileName: string;
begin
  Result := '';
end;

function TJIdeWizardModuleCreator.GetIntfFileName: string;
begin
  Result := '';
end;

function TJIdeWizardModuleCreator.GetMainForm: Boolean;
begin
  Result := False;
end;

function TJIdeWizardModuleCreator.GetOwner: IOTAModule;
var
  ModuleServices: IOTAModuleServices;
  Module: IOTAModule;
  NewModule: IOTAModule;
begin
  // You may prefer to return the project group's ActiveProject instead
  Result := nil;
  ModuleServices := (BorlandIDEServices as IOTAModuleServices);
  Module := ModuleServices.CurrentModule;

  if Module <> nil then
  begin
    if Module.QueryInterface(IOTAProject, NewModule) = S_OK then
      Result := NewModule

    else if Module.OwnerModuleCount > 0 then
    begin
      NewModule := Module.OwnerModules[0];
      if NewModule <> nil then
        if NewModule.QueryInterface(IOTAProject, Result) <> S_OK then
          Result := nil;
    end;
  end;
end;

function TJIdeWizardModuleCreator.GetShowForm: Boolean;
begin
  Result := True;
end;

function TJIdeWizardModuleCreator.GetShowSource: Boolean;
begin
  Result := True;
end;

function TJIdeWizardModuleCreator.GetUnnamed: Boolean;
begin
  Result := True;
end;

function TJIdeWizardModuleCreator.NewFormFile(const FormIdent, AncestorIdent: string): IOTAFile;
begin
  Result := nil;
end;

function TJIdeWizardModuleCreator.NewImplSource(const ModuleIdent, FormIdent, AncestorIdent: string): IOTAFile;
begin
  // or Result := nil; for the default unit
  Result := nil;
end;

function TJIdeWizardModuleCreator.NewIntfSource(const ModuleIdent, FormIdent, AncestorIdent: string): IOTAFile;
begin
  Result := nil;
end;

{ TJIdeWizardSourceFile }

constructor TJIdeWizardSourceFile.Create(const Source: string);
begin
  FSource := Source;
end;

function TJIdeWizardSourceFile.GetAge: TDateTime;
begin
  Result := -1;
end;

function TJIdeWizardSourceFile.GetSource: string;
begin
  result := FSource;
end;

end.

Here is an example of how I´m calling the method "NewImplSource" from IOTAModuleCreator

  procedure TfrmMapearObjetoRelacional.btnSimpleORMDaoClick(Sender: TObject);
  var
    _Mod: TJIdeWizardModuleCreator;
    _Str: string;
  begin
    _Mod := TJIdeWizardModuleCreator.Create;
    try
      _Str := _Mod.NewImplSource('unit1','','');
      ShowMessage(_Str);
    finally
      FreeAndNil(_Mod);
    end;
  end;
Leo Bruno
  • 474
  • 3
  • 16
  • Some queries: 1. You say you've compiled your .Bpl, but have you installed it in the IDE? 2. Where exactly does your btnSimpleORMDaoClick execute, in a unit in the .Bpl or somewhere else and, if so, where? – MartynA Jul 02 '20 at 08:36
  • Thank you for the response. Yes, the bpl is installed. The unit that contains the TfrmMapearObjetoRelacional class is on the contains "folder" of the bpl project, and it is a TForm that is called by a click event from a TMenuItem whitch is installed on the IDE Main Menu. – Leo Bruno Jul 02 '20 at 20:43
  • 1
    Well, a way to debug this is to close everything in the IDE, open the .Dpk file for the .Bpl as the current project, set breakpoints in the .Dpk's units wher you attempt to use your IOTAModuleCreator, then click `Run` in the IDE and it should invoke a second instance of the IDE, which will stop when one of the breakpoints is hit. It's a bit labourious but works fine as a way to debug an in-IDE .Bpl. – MartynA Jul 02 '20 at 21:17
  • Thank's again, I'll try it as soon as I get home. Do you think the method TJIdeWizardModuleCreator.NewImplSource is correctly implemented? Resulting nil should really create a standard empty unit? – Leo Bruno Jul 02 '20 at 21:22

2 Answers2

2

The answer for the question is YES it does.

The problem was that one should not call "NewImplSource" directly.

In order for it to work, it should be called based on the result from "GetCreatorType" inside the "IOTAModuleCreator" Constructor.

for instance:

  procedure TJModuleCreatorWizard.Execute;
  begin
    (BorlandIDEServices as IOTAModuleServices).CreateModule(TJModuleCreator.Create);
  end;

Where "TJModuleCreator" implements IOTAModuleCreator interface.

Martyn, thak you very much for your assistance, in fact I was able to figure it out by simplifying the scenario as you suggested on your answer.

Leo Bruno
  • 474
  • 3
  • 16
1

If you don't have any luck debugging this in a second instance of the IDE like I suggested in a project, I think you should consider changing your code do follow the way I go about implementing something like this.

  1. I implement the OTA interface of interest on a small form. Although the form is, in principle, unnecessary, it is very useful to give a visual sign that the thing's working and there is actually quite a lot of debugging you can do without having to resort to the second-IDE-instance business. You can build quite a lot of debugging facilities into the form by placing a small TMemo on it and using it as a logging facility to record what it does. And, of course, the form can have a MainMenu or whatever to invoke various of the OTA interface's methods to check that they do what they are supposed to do.

  2. The form shouldn't be autocreated. Instead, create and call .Show on it in the `Initialization' section of the form's unit and Free it in its Finalization section.

  3. Once you've compiled the .Dpk containing the form, install it in the IDE using Install Packages.

I always write OTA stuff in a form like this and very rarely get into any major problems that need the second-IDE-instance to investigate and resolve.

Good luck!

MartynA
  • 30,454
  • 4
  • 32
  • 73
  • Mostly I use D7 or Seattle. – MartynA Jul 04 '20 at 11:59
  • 10.2+ IDE are loaded with bugs, and I´m begining to think the issue has to do with it. I have managed to debug the dpk, but it did not helped me at all, the code executes, but no new tab sheet containing the new unit is showed. I also tryied to install the example code contained on the GExperts FAQ to investigate its guts, but it throws an assertion failure error. There is also a nice papper by David Ghoyle, his example does not install either. – Leo Bruno Jul 04 '20 at 12:03
  • I can't say I've noticed any major bugs in Seattle, certainly not with the OTA stuff, which works fine. So do David Hoyle's examples. If you're having problems, I think your set-up is possibly borked ... – MartynA Jul 04 '20 at 12:07