Anyone else also having some problems with the OpenTools API when trying to get a list of Forms and DataModules from the current project?

Anyone else also having some problems with the OpenTools API when trying to get a list of Forms and DataModules from the current project?

What I do is loop over all modules in my ActiveProject. Next I check if all of the IOTAModuleInfo.ModuleType are in [ omtForm. omtDataModule ]. I thought that would only be true for forms / datamodules. Sadly ... it seems to be the case for Units as well.

So I had to resort to checking the FormName and DesignClass properties instead.

for lcv := 0 to Pred( GetActiveProject.GetModuleCount ) do
begin
aModuleInfo := GetActiveProject.GetModule( lcv );

{$IFDEF CODESITE}
CodeSite.SendString( 'aModuleInfo.FormName' , aModuleInfo.FormName );
CodeSite.SendString( 'aModuleInfo.DesignClass', aModuleInfo.DesignClass );
{$ENDIF}

{ Apparently this also returns us units and other stuff. Checking on
the ModuleType doesn't seem to work, since it always returned 0, so
I had to check for the FormName and DesignClass :-( }
// if ( aModuleInfo.ModuleType in setFormAndDataModules ) then
// begin
// ShowMessage( aModuleInfo.FileName );
// end;

if ( aModuleInfo.FormName <> '' ) and
( aModuleInfo.DesignClass <> '' ) then
begin
aModule := aModuleInfo.OpenModule;
aEditor := GetFormEditorFromModule( aModule );

if ( Supports( aEditor.GetRootComponent, INTAComponent, aNTAComponent ) ) then
begin
aComponent := aNTAComponent.GetComponent;

AddCoreClassDescendantsToComboboxes( aComponent, aModuleInfo );
end;
end;
end;

As you can see, I need to list all descendants from some Custom Form descendant in my Expert.

Currently I also have to open every form in my project to be able to see if the actual form inherits from my TCoreForm or Supports my ICoreForm interface. Anyone has any idea if it is possible to detect that without opening every module ? Because in a project with 30 forms / datamodules this process is taking a while :-(

Comments

  1. Use IOTAModuleServices.FindModule to see if the module is open in the IDE. If you open each module the IDE will load everything into memory. If the FindModule returns nil it’s not open and you can open the file from disk. To understand a forms inheritance just parse the first line of the dfm file. Off the top of my head is usually either object | inline | inherit followed by the name and then the type. As for the iteration not conforming, I’ll have to check tomorrow when I can get back to a machine.

    ReplyDelete
  2. David Hoyle Well ... I need to loop over all files from the Active Project, so not sure FindModule will help me, since probably not all forms / datamodules will be open in the IDE anyway. Or maybe I didn't understand you correctly.

    Reading the DFM file to determine if something inherits from XXX won't work. In case of an inherited form it will not contain an indication of it's direct ancestor in the DFM, let along if the Ancester is even further up the Hierarchy. Even parsing the .Pas file doesn't really get me there I think.

    For example I have a TCoreController which is my custom TDataModule descendant I have added and registered in Delphi. The developers could have a TBaseController in his project which directly inherits from TCoreController, and next up have 10 other Controllers which inherit from TBaseController. In that case, the DFM nor the PAS will have any reference to TCoreController. The PAS will have a reference to TBaseController. But when adding a new Controller to my existing Project, I have to allow the user to inherit form any TCoreController descendant, so TCoreController, TBaseController and even descendants from TBaseController. That is why I am filling a combobox on my wizard with that information.

    I have it working, but it's slow as I have to use OpenModule on every form / datamodule in the active Project, get the FormEditor, get it's RootComponent, them check if that component inherits from something or implements some interface.

    I've currently not found a better solution, but if there is one, I'd be happy to try it out.

    ReplyDelete
  3. Stefaan Lesage Regarding looping I meant the code from this article... davidghoyle.co.uk - Getting the up to date project source code from the IDE – Dave's Development Blog

    If you get the classname from the file is there not a way to get its parent using TRttiType.BaseType?

    ReplyDelete
  4. David Hoyle Hm ... not really sure about that. I guess you would have to parse the DFM and the PAS to detect which class in the PAS matches up with the DFM and then maybe you could use RTTI to figure out the rest ? Since there is no guarantee there will be only one class definition in the pas file, nor that it will be the first one.

    ReplyDelete
  5. David Hoyle According the the loop code, that's actually what I'm doing. But once I have the ModuleInfo for a form / datamodule I need to determine if it descends from a common ancestor. Additionally checking the ModuleType to see if it's Form / Datamodule seems to be returning True even for simple units in my case.

    ReplyDelete
  6. Stefaan Lesage It look like you are right that there is a bug in the IDE as the below output from a test is not correct (Only modules with Form as a suffix are actually forms.

    D:\Documents\RAD Studio\Test Projects\Packaged App\Packaged Application.groupproj
    D:\Documents\RAD Studio\Test Projects\Packaged App\Packages\PkgdAppOffice.dproj
    rtl.dcp (omtPackageImport = 11)
    vcl.dcp (omtPackageImport = 11)
    vclx.dcp (omtPackageImport = 11)
    D:\Documents\RAD Studio\Library\office2000_tlb.pas (omtForm = 0)
    D:\Documents\RAD Studio\Library\excel2000_tlb.pas (omtForm = 0)
    D:\Documents\RAD Studio\Library\Word2000_TLB.pas (omtForm = 0)
    D:\Documents\RAD Studio\Library\VBIDE_TLB.pas (omtForm = 0)
    D:\Documents\RAD Studio\Test Projects\Packaged App\Packages\PkgdAppCore.dproj
    rtl.dcp (omtPackageImport = 11)
    vcl.dcp (omtPackageImport = 11)
    vclx.dcp (omtPackageImport = 11)
    vclimg.dcp (omtPackageImport = 11)
    PkgdAppOffice.dcp (omtPackageImport = 11)
    D:\Documents\RAD Studio\Test Projects\Packaged App\Source\PkgdApp.BaseClosableDockForm.pas (omtForm = 0)
    D:\Documents\RAD Studio\Test Projects\Packaged App\Source\PkgdApp.BaseDockForm.pas (omtForm = 0)
    D:\Documents\RAD Studio\Test Projects\Packaged App\Packages\PkgdAppIDECore.dproj
    rtl.dcp (omtPackageImport = 11)
    vcl.dcp (omtPackageImport = 11)
    vclimg.dcp (omtPackageImport = 11)
    D:\Documents\RAD Studio\Test Projects\Packaged App\Source\PkgdApp.IDE.Docking.pas (omtForm = 0)
    D:\Documents\RAD Studio\Test Projects\Packaged App\Source\PkgdApp.DockManager.pas (omtForm = 0)
    D:\Documents\RAD Studio\Test Projects\Packaged App\PkgdApp.dproj
    D:\Documents\RAD Studio\Test Projects\Packaged App\ITHVerInfo.RC (omtRc = 4)
    (omtForm = 0)
    D:\Documents\RAD Studio\Test Projects\Packaged App\Source\PkgdApp.MainForm.pas (omtForm = 0)
    D:\Documents\RAD Studio\Test Projects\Packaged App\Source\PkgdApp.ClosableDockForm.pas (omtForm = 0)

    I'm using 10.2.3.

    I'll now checks with Berlin and Seattle.

    ReplyDelete
  7. Yep, Berlin and Seattle are wrong as well. I'll check QC.

    ReplyDelete
  8. David Hoyle It has been like that since I started fooling with the OTA and that must have been years ago. Some of my old IOTA Wizards (code from 2005) already has comments stating that it doesn't work :-)

    ReplyDelete
  9. Additionally my old code states that the DesignClass of FormName (will have to check which one) ins't 100% reliable since it uses the comments found in the Project Source and you can put just about anything in there or even remove that comment.

    ReplyDelete

Post a Comment