Jump to content
Sign in to follow this  
limelect

Some components show class =nil

Recommended Posts

I have an expert that gets all the classes from the IDE.

var

 xx: TPersistentClass;

 

        xx := GetClass(PackageServices.ComponentNames[PackageCounter,
          ComponentCounter]);
some components show xx as nil although they are on the pallet and can be used

i cannot read xx.ClassName for that

Any idea why?

P.S It seems that components from ToolPalette do not have that problem

I just checked it on ToolPalette it has the same problem

xx := GetClass on some names are nil

Edited by limelect

Share this post


Link to post

GetClass requires a class to be priory registered using RegisterClass function otherwise it will fail.

Below, a sample that uses some undocumented functions to get all classes:

type
  TDesignPackages = TObject;
  TDesignPackage = TObject;
  TIDEDesignPackage = TObject;
  TRegModule = TObject;
  TRegClass = TObject;

  TDesignPackagesGetPackages = function(Obj: TDesignPackages; PackageIndex: Integer): TObject;
  TIDEDesignPackageGetCount = function(Obj: TIDEDesignPackage): Integer;
  TRegModuleGetCount = function(Obj: TRegModule): Integer;
  TIDEDesignPackageGetModules = function(Obj: TIDEDesignPackage; Index: Integer): TRegModule;
  TRegModuleGetClasses = function(Obj: TRegModule; Index: Integer): TRegClass;

var
  DesignPackagesGetPackages: TDesignPackagesGetPackages;
  IDEDesignPackageGetCount: TIDEDesignPackageGetCount;
  IDEDesignPackageGetModules: TIDEDesignPackageGetModules;
  RegModuleGetCount: TRegModuleGetCount;
  RegModuleGetClasses: TRegModuleGetClasses;

function GetClass2(PackageIndex, ComponentIndex: Integer): TClass;
var
  Coreide: THandle;
  Delphicoreide: THandle;
  LGlobalPackagesPtr: Pointer;
  LDesignPackages: TDesignPackages;
  LIDEDesignPackage: TIDEDesignPackage;
  LRegModule: TRegModule;
  LRegClass: TRegClass;
  LIDEDesignPackageCount: Integer;
  LRegModuleCount: Integer;
  LIndex: Integer;
  I: Integer;
  J: Integer;
begin
  Result := nil;

  { --- Move me outside --- }
  // adapt 260 suffix according to your Delphi version.
  Coreide := GetModuleHandle('coreide260.bpl');
  Delphicoreide := GetModuleHandle('delphicoreide260.bpl');

  LGlobalPackagesPtr := GetProcAddress(Coreide, '@Pakmgr@Packages');
  DesignPackagesGetPackages := GetProcAddress(Coreide, '@Pakmgr@TDesignPackages@GetPackages$qqri');
  IDEDesignPackageGetCount := GetProcAddress(Delphicoreide, '@Pascpppakmgr@TIDEDesignPackage@GetCount$qqrv');
  IDEDesignPackageGetModules := GetProcAddress(Delphicoreide, '@Pascpppakmgr@TIDEDesignPackage@GetModules$qqri');
  RegModuleGetCount := GetProcAddress(Coreide, '@Pakmgr@TRegModule@GetCount$qqrv');
  RegModuleGetClasses := GetProcAddress(Coreide, '@Pakmgr@TRegModule@GetClasses$qqri');

  Assert(Assigned(LGlobalPackagesPtr), 'LGlobalPackagesPtr not assigned');
  Assert(Assigned(DesignPackagesGetPackages), 'DesignPackagesGetPackages not assigned');
  Assert(Assigned(IDEDesignPackageGetCount), 'IDEDesignPackageGetCount not assigned');
  Assert(Assigned(IDEDesignPackageGetModules), 'IDEDesignPackageGetModules not assigned');
  Assert(Assigned(RegModuleGetCount), 'RegModuleGetCount not assigned');
  Assert(Assigned(RegModuleGetClasses), 'RegModuleGetClasses not assigned');
  { --- End Move outside --- }

  if Assigned(LGlobalPackagesPtr) then
  begin
    LDesignPackages := TObject(PPointer(LGlobalPackagesPtr)^);
    LIDEDesignPackage := DesignPackagesGetPackages(LDesignPackages, PackageIndex);
    LIDEDesignPackageCount := IDEDesignPackageGetCount(LIDEDesignPackage);
    LIndex := 0; // Component Index.

    for I := 0 to LIDEDesignPackageCount - 1 do
    begin
      LRegModule := IDEDesignPackageGetModules(LIDEDesignPackage, I);
      LRegModuleCount := RegModuleGetCount(LRegModule);
      for J := 0 to LRegModuleCount - 1 do
      begin
        if LIndex = ComponentIndex then
        begin
          LRegClass := RegModuleGetClasses(LRegModule, J);
          Result := TClass(PPointer(PByte(LRegClass) + 4)^);
          exit;
        end;
        Inc(LIndex);
      end;
    end;
  end;
end;

procedure Test(Sender: TObject);
var
  PackageServices: IOTAPAckageServices;
  I: Integer;
  J: Integer;
  LClass: TClass;
  s: string;
begin
  if Supports(BorlandIDEServices, IOTAPAckageServices, PackageServices) then
  begin
    for I := 0 to PackageServices.PackageCount - 1 do
    begin
      for J := 0 to PackageServices.GetComponentCount(I) - 1 do
      begin
        s := PackageServices.ComponentNames[I, J];
        LClass := GetClass2(I, J);
        if Assigned(LClass) then
        begin
          Assert(LClass.ClassName = s);
        end;
      end;
    end;
  end;
end;

 

  • Like 1

Share this post


Link to post

@Mahdi Safsafi

Well, not good news.

I have used your suggestion it does not work in my case.

Well, let me explain.

I am using this guy component.

https://github.com/digao-dalpiaz/Dam

It worked great and I have no complaint BUT it represents a section of

components that reading them from the IDE get nil for classes.

They seem to register OK and show on the pallet and are usable.

 

So that is the problem.

in your case, I used TPersistentClass(LClass); like that.

Maybe this is the problem.?

Since I have to use TPersistentClass as I am taking an old program 

and making it an EXPERT.

So the question is  if TPersistentClass is the problem as I am using GetClass or

your Lclass.

Any idea?

 

Maybe I can tackle my problem differently.

at the end I use this  RegisterClasses(MyArray);

where MyArray is TPersistentClass. This is why the above

 

Hold my question something fishy

Ok I return to my basic question

1. Reading from component toolbar NO DAM

2. Reading from tool pallet YES DAM

in this case still DAM shows nil !!!

DAM can be used from both

Crazy IDE ????

 

 

 

Edited by limelect

Share this post


Link to post

The code I provided is working perfectly for me ... In fact I'm able to access all components (fmx, vcl, indy, ...). Here is some contracts I made

// all true:
Assert(Assigned(LClass));                 
Assert(LClass.ClassName = s);            
Assert(LClass.InheritsFrom(TPersistent)); 

So what exactly is not working ?

 

Share this post


Link to post

First I am using D10.2.3. All "Normal components are read"

But try to install the above component and am i wrong?

Further more try to do if xx<>nil  then

qqqqq....

else

<<<< catch here and see

I did catch by        InstalledComponentName := PackageServices.ComponentNames[PackageCounter,
          ComponentCounter];

and lastly I  xx := GetClass(InstalledComponentName);

where xx: TPersistentClass; 

The class name is not the problem

Edited by limelect

Share this post


Link to post
Quote

Further more try to do if xx<>nil  then

qqqqq....

else

<<<< catch here and see

Sorry man ! I tried to assist you but definitely I'm not in a position to understand your words. 

Share this post


Link to post

I have made a very simple DEMO reading from the component bar (it does not have to show)

In the end, it saves components to a txt file.

Very simple. See how many components are NIL !!!!!

DockingForm (2).zip

 

And that is my problem

 

The same problem with Tool Pallet although there is a discrepancy between the two

Edited by limelect

Share this post


Link to post

@limelect Yes that's the way you should go for when language fails ... thanks !

I tested with my code and it works perfectly ... all components (tst.txt) are assigned (no nil):

// procedure TExampleDockableForm.Initilize;
// ...
  for PackageCounter := 0 to PackageServices.PackageCount - 1 do
  begin
    for ComponentCounter := 0 to PackageServices.GetComponentCount(PackageCounter) - 1 do
    begin
      InstalledComponentName := PackageServices.ComponentNames[PackageCounter, ComponentCounter];
      // xx := GetClass(InstalledComponentName); remove this line
      xx := TPersistentClass(GetClass2(PackageCounter, ComponentCounter)); // <-- use GetClass2
      if not(xx = nil) then
      begin
        s.Add(xx.ClassName);
      end
      else
        s.Add('nil- ' + InstalledComponentName);

    end;
  end;

 

Share this post


Link to post

@Mahdi Safsafi Just for general knowledge why there is a difference between

the getting of the component from the toolbar and from the package.

Since every component is going from a search through the bpl again and again

which is time-consuming.

I guess I can leave most of the initialization outside of GetClass2

but still a lot of iterations.

So again why the difference? in nil

In the package the class is different?

 

Edited by limelect

Share this post


Link to post
29 minutes ago, limelect said:

@Mahdi Safsafi Just for general knowledge why there is a difference between

the getting of the component from the toolbar and from the package.

Since every component is going from a search through the bpl again and again

which is time-consuming.but still a lot of iterations.

So again why the difference? in nil

In the package the class is different?

 

Don't worry about that ... all what you need to know is that this line (assumed that initialization of GetClass2 moved outside) 

xx := TPersistentClass(GetClass2(PackageCounter, ComponentCounter)); 

runs faster than this :

InstalledComponentName := PackageServices.ComponentNames[PackageCounter, ComponentCounter];
xx := GetClass(InstalledComponentName);
Quote

I guess I can leave most of the initialization outside of GetClass2

Yes that's what you should do. 

 

Share this post


Link to post

I hop i do not bother someone but this buffels me

https://github.com/digao-dalpiaz/Dam

this is not on the list although it is on the pallet

And if this is the case may be some other components too.

 

procedure GetAllClass; //
var
  Coreide: THandle;
  Delphicoreide: THandle;
  LGlobalPackagesPtr: Pointer;
  LDesignPackages: TDesignPackages;
  LIDEDesignPackage: TIDEDesignPackage;
  LRegModule: TRegModule;
  LRegClass: TRegClass;
  LIDEDesignPackageCount: Integer;
  LRegModuleCount: Integer;
  LIndex: Integer;
  I: Integer;
  J: Integer;
  PackageServices: IOTAPackageServices;
  PackageCounter: Integer;
  s: TStringList;
begin
  s := TStringList.Create;
  // Result.Clear;
  PackageServices := BorlandIDEServices as IOTAPackageServices;
  Assert(Assigned(PackageServices));

  { --- Move me outside --- }
  // adapt 260 suffix according to your Delphi version.
  Coreide := GetModuleHandle('coreide250.bpl');
  Delphicoreide := GetModuleHandle('delphicoreide250.bpl');
  LGlobalPackagesPtr := GetProcAddress(Coreide, '@Pakmgr@Packages');
  DesignPackagesGetPackages := GetProcAddress(Coreide,
    '@Pakmgr@TDesignPackages@GetPackages$qqri');
  IDEDesignPackageGetCount := GetProcAddress(Delphicoreide,
    '@Pascpppakmgr@TIDEDesignPackage@GetCount$qqrv');
  IDEDesignPackageGetModules := GetProcAddress(Delphicoreide,
    '@Pascpppakmgr@TIDEDesignPackage@GetModules$qqri');
  RegModuleGetCount := GetProcAddress(Coreide,
    '@Pakmgr@TRegModule@GetCount$qqrv');
  RegModuleGetClasses := GetProcAddress(Coreide,
    '@Pakmgr@TRegModule@GetClasses$qqri');

  Assert(Assigned(LGlobalPackagesPtr), 'LGlobalPackagesPtr not assigned');
  Assert(Assigned(DesignPackagesGetPackages),
    'DesignPackagesGetPackages not assigned');
  Assert(Assigned(IDEDesignPackageGetCount),
    'IDEDesignPackageGetCount not assigned');
  Assert(Assigned(IDEDesignPackageGetModules),
    'IDEDesignPackageGetModules not assigned');
  Assert(Assigned(RegModuleGetCount), 'RegModuleGetCount not assigned');
  Assert(Assigned(RegModuleGetClasses), 'RegModuleGetClasses not assigned');
  { --- End Move outside --- }

  if Assigned(LGlobalPackagesPtr) then
  begin
    for PackageCounter := 0 to PackageServices.PackageCount - 1 do
    begin
      if PackageServices.GetComponentCount(PackageCounter) > 0 then
      begin
        LDesignPackages := TObject(PPointer(LGlobalPackagesPtr)^);
        LIDEDesignPackage := DesignPackagesGetPackages(LDesignPackages,
          PackageCounter);
        LIDEDesignPackageCount := IDEDesignPackageGetCount(LIDEDesignPackage);
        LIndex := 0; // Compeginonent Index.

        for I := 0 to LIDEDesignPackageCount - 1 do
        begin
          LRegModule := IDEDesignPackageGetModules(LIDEDesignPackage, I);
          LRegModuleCount := RegModuleGetCount(LRegModule);
          for J := 0 to LRegModuleCount - 1 do
          begin
            //        if LIndex = ComponentIndex then
            begin
              LRegClass := RegModuleGetClasses(LRegModule, J);
              s.Add(TClass(PPointer(PByte(LRegClass) + 4)^).ClassName);
              //    exit;
            end;
            Inc(LIndex);
          end;
        end;
      end;
    end;
  end;
  s.SaveToFile('c:\tst.txt');
  s.Free;
end;
 

can some one install and help ?

just add above to my test package and in Initilize just call GetAllClass;

 

Share this post


Link to post

OK to sum it .

I do not understand the IDE. I recompiled and reinstaled

the component and now it shows on the list. Even it was on the pallet it did not show.

Not my fault.

As for my first problem the @Mahdi Safsafi solution helped a lot. Thanks

Share this post


Link to post

@Mahdi Safsafi and others

Well, I just installed a new component on my D10.2.3, and

after closing the Delphi program and reopening it does not show on

my list !!. Although it is on the pallet.

So it is the Delphi program. !!!!

So now for the questions

1. is there another way to get the component list?

 beside    PackageServices := BorlandIDEServices as IOTAPackageServices;

and     for PackageCounter := 0 to PackageServices.PackageCount - 1 do

2. is there a max quantity for components? I have many.

P.S  @Mahdi Safsafi I just installed your ZControl and it too disappeared

 

 

Edited by limelect

Share this post


Link to post
Guest

@limelect It took me while to understand what is going on based on your description, and had to try it is.

 

I tried your example and it work just perfect, the problem is you are populating the package using Initialize, means this package will see only the initialized packages before it, an when you install new package then most likely (if not always) will be initialized and registered after this package, so the populating will not see them, just recompile/install your demo and it will start to see them, but that is not a solution, just a confirmation of expected behavior.

 

You have to find a work around for that like use TPackageNotifier or something, also might be interesting to test if it is possible to uninstall self and reinstall, this might be ugly, dangerous and definitely not recommend as easily can lead to endless loop then crash the IDE, but interesting non the less.

Share this post


Link to post

I have created a text file of the components and there

packeges.

Where there is no component in the package  see ---------zcontrols_d.bpl

and more.

    if PackageServices.GetComponentCount(PackageCounter) = 0 then

    s.Add('---------'+PackageServices.PackageNames[PackageCounter]);
 

But one can see in the component tab the components and also on the pallet

So i am trying to investigate but i am almost at the end.

tst.txt

Share this post


Link to post

@Kas Ob. I am too professional to leave this point.

After installing and seeing the component I close the Delphi program

and reopen. This is when the package is empty.

P.S I have a new demo with a button to initialize.

The problem is that restart Delphi the packages are empty. !!!

If you want I can put here the source it is 2 more lines.

See my last comment

 

Edited by limelect

Share this post


Link to post
Guest
7 minutes ago, limelect said:

Here it is my last demo to see how many packages are empty

Are referring to a package with no class's reported ? is this what did you mean with empty packages ?

image.thumb.png.e07e574347bf67310bff04a86942e539.png

Share this post


Link to post

Use my last demo because the old one are not perfect

You will get a list of similar txt

This is an empty package ---------xxxxxx.bpl

Edited by limelect

Share this post


Link to post
Guest
2 minutes ago, limelect said:

You will get a list of similar txt

I did, but still confused as you did not answer if you referring to these packages with no components.

 

Take an example you package itself "DockingFormPackage.bpl", what should it show ? ( away from its name )

 

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×