Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Delphi Wie ermittelt man welche Komponenten in einem Package sind? (https://www.delphipraxis.net/44581-wie-ermittelt-man-welche-komponenten-einem-package-sind.html)

MaBuSE 21. Apr 2005 08:44


Wie ermittelt man welche Komponenten in einem Package sind?
 
Hallo,
ich würde gerne zur Laufzeit wissen welche Komponenten in dem Package xyz.bpl enthalten sind.
Die Info ob das ein Runtime-, Designtime-Package oder Beides ist wär auch nicht schlecht.

Wenn ein Package in Delphi geladen wird (Menu -> Komponenten -> Packages installieren) kann man mit dem Komponenten Button sehen welche Komponenten in diesem Package sind.
Genau das will ich auch in meinem Programm haben !!!

An die Beschreibung und die Units des Package kommt man relativ leicht mit getPackageInfo.

Kann mir jemand helfen?

Delphi-Quellcode:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Memo1: TMemo;
    procedure Button1Click(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure cbprocPackageInfo(const Name: string; NameType: TNameType; Flags: Byte; Param: Pointer);
var
  s: string;
begin
  // CallbackFunktion von GetPackageInfo
  case NameType of
    ntContainsUnit   : s := 'Unit: ';
    ntRequiresPackage : s := 'benötigt Package: ';
    ntDcpBpiName     : s := 'PackageName: ';
  end;
  Form1.Memo1.Lines.Add(' Flags: ' + IntToHex(Flags, 2) + ' - ' +s + name);
end;

procedure GetBplInfo(FileName: string);
var
  HPack, Flags : integer;
begin
  Form1.Memo1.Lines.Add('Dateiname: '+FileName);
  Form1.Memo1.Lines.Add(' Package Name: '+GetPackageDescription(PAnsiChar(FileName)));
  HPack := LoadPackage(FileName);
  GetPackageInfo(HPack, nil, Flags, cbprocPackageInfo);
  UnloadPackage(HPack);
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  Memo1.Lines.Clear;
  getBplInfo('dclisp70.bpl');
end;

end.

Stevie 21. Apr 2005 09:52

Re: Wie ermittelt man welche Komponenten in einem Package si
 
Hi Mabuse,

folgendende Unit hab ich bei unseren niederländischen Kollegen gefunden:
Delphi-Quellcode:
unit PackageInfo;

interface
uses Classes;

type
  TPackageClassesAndUnits = class
  protected
    FModuleName: string;
    FUnitList: TStringList;
    FClassList: TList;
    procedure MethodGetClass(AClass: TPersistentClass);
  public
    constructor Create(ModuleHandle: THandle); Overload;
    constructor Create(ModuleName: String); Overload;
    destructor Destroy; override;
    property ClassList: TList read FClassList;
    property Units: TStringList read FUnitList;
    property ModuleName: string read FModuleName;
  end;

implementation
uses TypInfo, SysUtils, Windows;

procedure PackageInfoMethod(const Name: string; NameType: TNameType; Flags: Byte; Param: Pointer);
var
  UnitList: TStringList;
begin
  // add unit
  if NameType = ntContainsUnit then
  begin
    UnitList := TStringList(Param); // should work when Param is FUnitList from TPackageClassesAndUnits
    UnitList.Add(Name);
  end;
end;


{ TPackageClassesAndUnits }

constructor TPackageClassesAndUnits.Create(ModuleHandle: THandle);
var
  flags: integer;
begin
  // create class list
  FClassList:= TList.Create;
  // create unit list (sorted, ignore duplicates)
  FUnitList := TStringList.Create;
  FUnitList.Duplicates := dupIgnore;
  FUnitList.Sorted := true;

  FModuleName := GetModuleName(ModuleHandle);

  // build unit list
  GetPackageInfo(ModuleHandle, FUnitList, flags, @PackageInfoMethod);

  // build class list
  with TClassFinder.Create(nil, false) do
  try
    GetClasses(MethodGetClass);
  finally
    Free;
  end;
end;

constructor TPackageClassesAndUnits.Create(ModuleName: String);
begin
  Create(GetModuleHandle(PChar(ModuleName)));
end;

destructor TPackageClassesAndUnits.Destroy;
begin
  FClassList.Free;
  FUnitList.Free;
  inherited;
end;

procedure TPackageClassesAndUnits.MethodGetClass(AClass: TPersistentClass);
var
  TypeData: PTypeData;
begin
  // get typedata pointer
  TypeData := GetTypeData(AClass.ClassInfo);
  // add class when unit name of class typedate in unit list and not
  // already added
  if (FUnitList.IndexOf(TypeData^.UnitName) >= 0) and
    (FClassList.IndexOf(AClass) < 0) then
    FClassList.Add(AClass);
end;

end.
Allerdings ist hierbei Vorraussetzung, dass die Klassen registriert sind, ansonsten hast du nicht wirklich eine Chance, sie zu finden.

MfG
Stevie

MaBuSE 21. Apr 2005 12:42

Re: Wie ermittelt man welche Komponenten in einem Package si
 
Danke für die Antwort.
Zitat:

Zitat von Stevie
Allerdings ist hierbei Vorraussetzung, dass die Klassen registriert sind, ansonsten hast du nicht wirklich eine Chance, sie zu finden.

Wenn Sie nicht registriert sind habe ich wohl keine Chance :-(

Ich habe versucht die Register Prozedur der Packages aufzurufen, bekomme aber nur einen Fehler EComponentError "Ungültige Komponentenregistrierung" :-(

In den Register Prozeduren der Packages steht natürlich folgendes drin:
Delphi-Quellcode:
RegisterComponent('Palette', [TMyComponent]);
Wie kann ich die denn zur Laufzeit registrieren um zu sehen welche Komponenten in dem Package enthalten sind?

Stevie 21. Apr 2005 13:49

Re: Wie ermittelt man welche Komponenten in einem Package si
 
Zitat:

Zitat von MaBuSE
Wie kann ich die denn zur Laufzeit registrieren um zu sehen welche Komponenten in dem Package enthalten sind?

In jeder Unit, wo Klassen enthalten sind, die du finden willst, muss folgendes enthalten sein:
Delphi-Quellcode:
initialization
  RegisterClass(TMyClass);

finalization
  UnRegisterClass(TMyClass);

MaBuSE 21. Apr 2005 14:40

Re: Wie ermittelt man welche Komponenten in einem Package si
 
Zitat:

Zitat von Stevie
In jeder Unit, wo Klassen enthalten sind, die du finden willst, muss folgendes enthalten sein:
Delphi-Quellcode:
initialization
  RegisterClass(TMyClass);
finalization
  UnRegisterClass(TMyClass);

Wer macht das denn?

Nicht mal in den Standard Package z.B. dclstd70.bpl ist das gemacht.

Ich will aber wissen, was in den einzelnen Package enthalten ist.
Die IDE kann das ja auch :mrgreen:

Als Experten, der in die IDE geklingt wird und dann das Package läd, nachschaut und es wieder entläd funktioniert das über die ToolsAPI. (BorlandIDEServices as IOTAPackageServices)

Aber Leider nicht ohne IDE :evil:

Mein Tool gibt bisher folgendes aus:
Code:
Dateiname: dclstd70.bpl
  Package Name: Borland Standardkomponenten
  Flags: 00 - benötigt Package: designide70.bpl
  Flags: 00 - benötigt Package: vclx70.bpl
  Flags: 00 - benötigt Package: vcl70.bpl
  Flags: 00 - benötigt Package: rtl70.bpl
  Flags: 03 - Unit: dclstd
  Flags: 00 - Unit: StdConst
  Flags: 00 - Unit: SysInit
  Flags: 00 - Unit: ActnRes
  Flags: 00 - Unit: ActnDrag
  Flags: 00 - Unit: NewStdAc
  Flags: 00 - Unit: ActnEdit
  Flags: 00 - Unit: SvcReg
               SvcReg.Register;
  Flags: 00 - Unit: DdeReg
               DdeReg.Register; fehlgeschlagen (Ungültige Komponentenregistrierung)
  Flags: 00 - Unit: FiltEdit
  Flags: 00 - Unit: HCtlEdit
  Flags: 00 - Unit: NodeEdit
  Flags: 00 - Unit: ImgEdit
  Flags: 00 - Unit: ItemEdit
  Flags: 00 - Unit: ColEdit
  Flags: 00 - Unit: SBarEdit
  Flags: 00 - Unit: MaskProp
  Flags: 00 - Unit: MaskText
  Flags: 00 - Unit: OleReg
               OleReg.Register; fehlgeschlagen (Ungültige Komponentenregistrierung)
  Flags: 00 - Unit: StdReg
               StdReg.Register; fehlgeschlagen (Ungültige Komponentenregistrierung)
  Flags: 00 - Unit: SysReg
               SysReg.Register; fehlgeschlagen (Ungültige Komponentenregistrierung)
  Flags: 00 - PackageName: dclstd
Mir fehlen z.B. noch folgende Informationen:
Code:
TOpenDialog
TSaveDialog
TOpenPictureDialog
TSavePictureDialog
TFontDialog
TColorDialog
TPrintDialog
TPrinterSetupDialog
TFindDialog
TReplaceDialog
TPageSetupDialog
TTimer
TPaintBox
TMediaPlayer
TMainMenu
TPopupMenu
TLabel
TEdit
TMemo
TButton
TCheckBox
TRadioButton
TListBox
TComboBox
TScrollBar
TGroupBox
TRadioGroup
TPanel
TActionList
TBitBtn
TSpeedButton
TMaskEdit
TStringGrid
TDrawGrid
TImage
TShape
TBevel
TScrollBox
TCheckListBox
TSplitter
TStaticText
TControlBar
TApplicationEvents
TValueListEditor
TLabeledEdit
TColorBox
TTabControl
TPageControl
TImageList
TRichEdit
TTrackBar
TProgressBar
TUpDown
THotKey
TAnimate
TDateTimePicker
TMonthCalendar
TTreeView
TListView
THeaderControl
TStatusBar
TToolBar
TCoolBar
TPageScroller
TComboBoxEx
TXPManifest
TOleContainer
TCOMAdminCatalog
TDdeClientConv
TDdeClientItem
TDdeServerConv
TDdeServerItem
Hat jemand eine Idee ?

maximov 21. Apr 2005 14:46

Re: Wie ermittelt man welche Komponenten in einem Package si
 
Moin Mabuse,

der Hagen hat mal einen sehr trickreichen, wenn auch illegalen, code zum iterieren über alle typeInfo eines moduls veröffentlicht, mit dem du wohl deine aufgabenstellung erfüllen kannst.

in folgendem thread findest du alles nötige: http://www.delphipraxis.net/internal...ght=hagen+rtti

negaH 22. Apr 2005 00:10

Re: Wie ermittelt man welche Komponenten in einem Package si
 
Korrekt, und mit System.EnumModules() kannst du über die geladenen Packages iterieren.

Delphi-Quellcode:
uses TypInfo, HagEnumInfo;

function TForm1.DoTypeInfo(Info: PTypeInfo): Boolean; register;
begin
  Result := False;
  if Info.Kind = tkClass then
    Memo1.Lines.Add(GetModuleName(FindHInstance(Info)) + ', ' + Info.Name);
end;

procedure TForm1.Button1Click(Sender: TObject);

  function MyEnumModule(Instance: Integer; Data: Pointer): Boolean;
  begin
    Result := not EnumTypeInfo(Instance, @MyEnumTypeInfo, Data);
  end;

begin
  Memo1.BeginUpdate;
  try
    Memo1.Clear;
    EnumModules(@MyEnumModule, Self);
  finally
    Memo1.EndUpdate;
  end;
end;

Gruß Hagen

MaBuSE 22. Apr 2005 06:38

Re: Wie ermittelt man welche Komponenten in einem Package si
 
Zitat:

Zitat von negaH
Korrekt, und mit System.EnumModules() kannst du über die geladenen Packages iterieren.

Danke, aber irgendwie funnktioniert das nicht richtig bei mir.

Dein hier geposteter Quellcode funktioniert bei mir so nicht.
Folgende Dinge musste ich ändern:
  • Memo1.BeginUpdate und Memo1.EndUpdate gibts bei meinem Delphi 7 TMemo nicht
  • EnumTypeInfo fibt bei mir nicht Boolean, sondern PTypeInfo zurück
  • EnumModules(@MyEnumModule, self); musste ich zu EnumModules(TEnumModuleFunc(@MyEnumModule), self); ändern (gab Fehlermeldung wegen mehrdeutiger Überladung)
  • Result := not EnumTypeInfo(Instance, @MyEnumTypeInfo, Data); musste ich nach EnumTypeInfo(Instance, @DoTypeInfo, Data); ändern, da MyEnumTypeInfo nicht definiert ist.
  • function TForm1.DoTypeInfo(Info: PTypeInfo): Boolean; register; musste ich nach function DoTypeInfo(UserData: Pointer; Info: PTypeInfo): Boolean; register; ändern (da TEnumTypeInfoCallback so definiert ist)
Ich hoffe das diese Änderungen so richtig sind.

Im Memo steht nun eine Liste der eingebundenen Klassen.

Leider nur die von Projekt1.exe nicht die der Package, obwohl ich ein Package mit LoadPackage('dclsockets70.bpl'); geladen habe.

Mein Versuch gestern mit Deiner Unit brachten mich etwas weiter.

Ich habe einfach Deine Unit wie folgt abgeändert: (2 x Ausgabe in Memo)
Delphi-Quellcode:
function RegClassesHandler(UserData: Pointer; Info: PTypeInfo): Boolean; register;
var td:PTypeData;
begin
  if Info^.Kind = tkClass then
  begin
    td := GetTypeData(info);
    if td^.ClassType.InheritsFrom(TPersistent) then
    begin
      RegisterClass(TPersistentClass(td^.ClassType));
      Form1.Memo1.Lines.Add('             Register: '+TPersistentClass(td^.ClassType).ClassName);
    end;
    Form1.Memo1.Lines.Add('             Unit:'+td^.UnitName+' - Klasse: '+td^.ClassType.ClassName+
      ' = class('+td^.ParentInfo^.Name+')');
  end;
  result := false;
end;
Dabei ist mir folgendes aufgefallen:
1. Es werden nicht alle Komponenten gefunden.
2. RegisterClass wird nicht aufgerufen, obwohl TForm von TPersistent abgeleitet ist.
Hier die Ausgabe der Procedure für Package dclstd70.bpl
Code:
Unit:FiltEdit - Klasse: TFilterEditor = class(TForm)
Unit:FiltEdit - Klasse: TFilterProperty = class(TStringProperty)
Unit:MaskText - Klasse: TMaskTextProperty = class(TStringProperty)
Unit:MaskText - Klasse: TMaskTextForm = class(TForm)
Unit:MaskProp - Klasse: TMaskProperty = class(TStringProperty)
Unit:MaskProp - Klasse: TMaskForm = class(TForm)
Unit:ItemEdit - Klasse: TItemInfo = class(TObject)
Unit:ItemEdit - Klasse: TListViewItems = class(TForm)
Unit:NodeEdit - Klasse: TTreeViewItems = class(TForm)
Unit:ImgEdit - Klasse: TImageInfo = class(TObject)
Unit:ImgEdit - Klasse: TImageListEditor = class(TForm)
Unit:NewStdAc - Klasse: TNewStdActionDlg = class(TForm)
Unit:ActnDrag - Klasse: TActionDragObject = class(TDragControlObject)
Unit:ActnEdit - Klasse: TActionImageListListener = class(TChangeLink)
Unit:ActnEdit - Klasse: TActionListDesigner = class(TToolbarDesignWindow)
Unit:ActnRes - Klasse: TStandardActions = class(TDataModule)
Unit:XPMan - Klasse: TXPManifest = class(TComponent)
Unit:SBarEdit - Klasse: TStatusBarEditor = class(TForm)
Unit:ColEdit - Klasse: TColInfo = class(TObject)
Unit:ColEdit - Klasse: TListViewColumns = class(TForm)
Unit:HCtlEdit - Klasse: THeaderControlEditor = class(TForm)
Unit:DdeReg - Klasse: TSrvrConvEdit = class(TDefaultEditor)
Unit:DdeReg - Klasse: TCliConvEdit = class(TDefaultEditor)
Unit:DdeReg - Klasse: TSrvrItemEdit = class(TDefaultEditor)
Unit:DdeReg - Klasse: TDdeLinkDlg = class(TForm)
Unit:DdeReg - Klasse: TDdeLinkInfoProperty = class(TPropertyEditor)
Unit:DdeReg - Klasse: TDdeClientItemProperty = class(TStringProperty)
In dem Package sind aber noch folgende Komponenten registriert:
TOpenDialog, TSaveDialog, TOpenPictureDialog, TSavePictureDialog, TFontDialog, TColorDialog, TPrintDialog, TPrinterSetupDialog, TFindDialog, TReplaceDialog, TPageSetupDialog, TTimer, TPaintBox, TMediaPlayer, TMainMenu, TPopupMenu, TLabel, TEdit, TMemo, TButton, TCheckBox, TRadioButton, TListBox, TComboBox, TScrollBar, TGroupBox, TRadioGroup, TPanel, TActionList, TBitBtn, TSpeedButton, TMaskEdit, TStringGrid, TDrawGrid, TImage, TShape, TBevel, TScrollBox, TCheckListBox, TSplitter, TStaticText, TControlBar, TApplicationEvents, TValueListEditor, TLabeledEdit, TColorBox, TTabControl, TPageControl, TImageList, TRichEdit, TTrackBar, TProgressBar, TUpDown, THotKey, TAnimate, TDateTimePicker, TMonthCalendar, TTreeView, TListView, THeaderControl, TStatusBar, TToolBar, TCoolBar, TPageScroller, TComboBoxEx, TXPManifest, TOleContainer, TCOMAdminCatalog, TDdeClientConv, TDdeClientItem, TDdeServerConv und TDdeServerItem

Für das Package dclsockets70.bpl zeigt mir Deine Funktion gar nichts an, aber es sind die Komponenten
TClientSocket und TServerSocket enthalten

MaBuSE 22. Apr 2005 06:55

Re: Wie ermittelt man welche Komponenten in einem Package si
 
Gestern hatte ich noch eine Idee, die aber auch nicht funktioniert :-/

In jedem Package (das Komponenten enthällt) gibt es eine Unit, die eine Prozedur Register enthällt.
Diese Prozedur habe ich aufgerufen
Delphi-Quellcode:
...
  case NameType of
    ntContainsUnit   : begin
                          s := 'Unit: ';
                          s2 := LowerCase(Name);
                          s2[1] := UpCase(s2[1]);
                          @PRegister := GetProcAddress(PInteger(Param)^,
                            pchar('@'+s2+'@Register$qqrv'));
                          if @PRegister <> nil then
                          begin
                            s2 := name+'.Register;';
                            try
                              PRegister; // <--- hier wird Register; aufgerufen !!!
                            except
                              on E: Exception do
                                s2 := s2 + ' fehlgeschlagen ('+E.Message+')';
                            end;
                          end
                          else s2:= '';
                        end;
...
In der Register; stehen für normalerweise die RegisterComponents(...) Aufrufe
Der Aufruf schlägt natürlich fehl, weil die Prozedur RegisterComponentsProc nur in der IDE gesetzt ist, zur Laufzeit ist sie nil.
Delphi-Quellcode:
  SRegisterError = 'Ungültige Komponentenregistrierung';
...
procedure RegisterComponents(const Page: string;
  const ComponentClasses: array of TComponentClass);
begin
  if Assigned(RegisterComponentsProc) then
    RegisterComponentsProc(Page, ComponentClasses)
  else
    raise EComponentError.CreateRes(@SRegisterError);
end;
Wenn man diese Prozedur zuweist, sollte es klappen:
Delphi-Quellcode:
procedure myTestProc(const Page: string; const ComponentClasses: array of TComponentClass);
begin
  Form1.Memo1.Lines.Add(Page); // Testweise nur die Palette ausgeben
end;

procedure TForm1.Button4Click(Sender: TObject);
var
  bak : procedure(const Page: string; const ComponentClasses: array of TComponentClass);
begin
  bak := RegisterComponentsProc;
  RegisterComponentsProc := myTestProc;
  RegisterComponents('Test hat geklappt', [TComponent]);
  RegisterComponentsProc := bak;
end;
Es wird auch 'Test hat geklappt' im Memo ausgegeben -> es funktioniert

Also habe ich das PAckage geladen, die Register Procedure aufgerufen und ein 'Ungültige Komponentenregistrierung' Fehler bekommen. Das Memo bleibt leer. Das verbiegen des Zeigers hat wohl keine Auswirkungen auf das Package.

Wie macht das Delphi?

Ich kann das Package ja in der IDE Laden, und die Komponenten werden dann brav in der Palette angezeigt.

maximov 22. Apr 2005 10:02

Re: Wie ermittelt man welche Komponenten in einem Package si
 
Zitat:

Zitat von MaBuSE
...
Im Memo steht nun eine Liste der eingebundenen Klassen.

Leider nur die von Projekt1.exe nicht die der Package, obwohl ich ein Package mit LoadPackage('dclsockets70.bpl'); geladen habe.
...

Das macht mich ein bischen stutzig, da ich davon ausgehe, das du das ModulHandle von 'dclsockets70.bpl' angegeben hast. Deine aussage lässt aber eher darauf schliessen, das dort das Handle des hauptmoduls angekommen ist. ?

negaH 22. Apr 2005 13:56

Re: Wie ermittelt man welche Komponenten in einem Package si
 
@Mabuse:

ok, das mein obiger Code nicht sofort funktioniert ist auch logisch, ich habe ihn hier einfach aus dem gedächtnis eingehämmert, da kann man sich mal irren. Öfters komme ich mit den verschiedenen aber ähnlichen Sprachen durcheinander. Zb. gerade jetzt arbeite ich mit VHDL und dieses ist in der Syntax ähnlich wie PASCAL aber eben nicht gleich, da kostet es schon Anstrengung das if then nicht als if end if; oder das case of end; nicht als case is when end case; zu schreiben :-) sorry also:

dieser Code funktioniert bei mir super, und er extrahiert sogar noch den Unit Namen ohne deinen Trick:


Delphi-Quellcode:

uses BlaBla, TypInfo;

type
  TEnumTypeInfoCallback = function(UserData: Pointer; Info: PTypeInfo): Boolean; register;

function GetBaseOfCode(Module: hModule; var CodeStart, CodeEnd: PChar): Boolean;
asm // get Codesegment pointers, check if module is a valid PE
       PUSH EDI
       PUSH ESI
       AND  EAX,not 3
       JZ   @@2
       CMP  Word Ptr [EAX],'ZM';
       JNE  @@1
       MOV  ESI,[EAX + 03Ch]
       CMP  Word Ptr [ESI + EAX],'EP'
       JNE  @@1
       MOV  EDI,[EAX + ESI + 014h + 008h]
       ADD  EAX,[EAX + ESI + 014h + 018h]
       ADD  EDI,EAX
       MOV  [EDX],EAX
       MOV  [ECX],EDI
       XOR  EAX,EAX
@@1:  SETE AL
@@2:  POP  ESI
       POP  EDI
end;

function EnumTypeInfo(Module: hModule; Callback: TEnumTypeInfoCallback; UserData: Pointer): PTypeInfo;
// copyright (c) 1998 Hagen Reddmann
var
  P,E,K,N: PChar;
  L: Integer;
begin
  Result := nil;
  if Assigned(Callback) then
  try
    if GetBaseOfCode(Module, P, E) then
      while P < E do
      begin
        DWord(P) := DWord(P) and not 3;
        K := P + 4;
        if (PDWord(P)^ = DWord(K)) and (PByte(K)^ > 0)
        and (PByte(K)^ <= Integer(High(TTypeKind))) then // Info.Kind in ValidRange.D6
        begin
          L := PByte(K + 1)^; // length Info.Name
          N := K + 2;         // @Info.Name[1]
          if (L > 0) and (N^ in ['_', 'a'..'z', 'A'..'Z']) then // valid ident ??
          begin
            repeat
              Inc(N);
              Dec(L);
            until (L = 0) or not (N^ in ['_', 'a'..'z', 'A'..'Z', '0'..'9']);
            if L = 0 then // length and ident valid
              if Callback(UserData, Pointer(K)) then // tell it and if needed abort iteration
              begin
                Result := Pointer(K);
                Exit;
              end else K := N;
          end;
        end;
        P := K;
      end;
  except
  end;
end;

function TForm1.DoEnumTypeInfo(Info: PTypeInfo): Boolean; register;

  function UnitName(Info: PTypeInfo): String;
  var
    Data: PTypeData;
  begin
    Data := GetTypeData(Info);
    case Info.Kind of
      tkClass: Result := Data.UnitName;
      tkInterface: Result := Data.IntfUnit;
      tkDynArray: Result := Data.DynUnitName;
   else
      Result := '';
    end;
  end;

var
  Prop: PPropList;
  Count,I: Integer;
begin
  Result := False;

  Memo.Lines.Add(Format('%:-40s: %-20s, %s->%s', [
                   Info.Name,
                   GetEnumName(TypeInfo(TTypeKind), Byte(Info.Kind)),
                   ExtractFileName(GetModuleName(FindHInstance(Info))),
                   UnitName(Info)]));
{
  if (Info.Kind = tkClass) and (GetTypeData(Info).PropCount > 0) then
  begin
    Count := GetPropList(Info, Prop);
    try
      for I := 0 to Count -1 do
        Memo.Lines.Add(Format('   %:-36s: %-20s', [
            Prop[I].Name,
            Prop[I].PropType^.Name]));
    finally
      FreeMem(Prop);
    end;
  end;
}
end;

procedure TForm1.Button1Click(Sender: TObject);

  function MyEnumModule(Instance: Integer; Data: Pointer): Boolean;
  begin
    Result := EnumTypeInfo(Instance, @TForm1.DoEnumTypeInfo, Data) = nil;
  end;

begin
  Memo.Lines.BeginUpdate;
  try
    Memo.Clear;
    EnumModules(TEnumModuleFunc(@MyEnumModule), Self);
  finally
    Memo.Lines.EndUpdate;
  end;
end;
Wie du auch siehst ist die Deklaration von TEnumModuleFunc durch Borland sehr unglücklich erfolgt. Besser wäre es wie in meiner Deklaration den UserData Paramater als ersten Parameter der Callback zu benutzen. So kann man nämlich diese Callbacks ohne Probleme als Methoden-Callback eines Objectes benutzen. Dazu muß UserData eben nur Self enthalten.

Angezeigt wird zb. nachfolgendes:

Code:
TForm1                                  : tkClass            , Project1.exe->Unit1
HWND                                   : tkInteger          , vcl70.bpl->
TOwnerDrawState                        : tkSet              , vcl70.bpl->
TColor                                 : tkInteger          , vcl70.bpl->
EInvalidGraphic                        : tkClass            , vcl70.bpl->Graphics
EInvalidGraphicOperation               : tkClass            , vcl70.bpl->Graphics
TFontPitch                             : tkEnumeration      , vcl70.bpl->
TFontName                              : tkLString          , vcl70.bpl->
TFontCharset                           : tkInteger          , vcl70.bpl->
TFontDataName                          : tkString           , vcl70.bpl->
TFontStyle                             : tkEnumeration      , vcl70.bpl->
TFontStyles                            : tkSet              , vcl70.bpl->
TFontStylesBase                        : tkSet              , vcl70.bpl->
TPenStyle                              : tkEnumeration      , vcl70.bpl->
TPenMode                               : tkEnumeration      , vcl70.bpl->
TBrushStyle                            : tkEnumeration      , vcl70.bpl->
TGraphicsObject                        : tkClass            , vcl70.bpl->Graphics
IChangeNotifier                        : tkInterface        , vcl70.bpl->Graphics
TPrinterCapabilities                   : tkSet              , vcl70.bpl->
TPrinter                               : tkClass            , vcl70.bpl->Printers
TPrinterCanvas                         : tkClass            , vcl70.bpl->Printers
TEdgeBorder                            : tkEnumeration      , vcl70.bpl->
TEdgeBorders                           : tkSet              , vcl70.bpl->
TEdgeStyle                             : tkEnumeration      , vcl70.bpl->
TToolWindow                            : tkClass            , vcl70.bpl->ToolWin
TToolDockObject                        : tkClass            , vcl70.bpl->ToolWin
TSizingOrientation                     : tkEnumeration      , vcl70.bpl->
TToolDockForm                          : tkClass            , vcl70.bpl->ToolWin
IShellFolder                           : tkInterface        , vcl70.bpl->ShlObj
IAutoComplete                          : tkInterface        , vcl70.bpl->ShlObj
TCommonDialog                          : tkClass            , vcl70.bpl->Dialogs
TOpenOption                            : tkEnumeration      , vcl70.bpl->
TOpenOptions                           : tkSet              , vcl70.bpl->
TOpenOptionEx                          : tkEnumeration      , vcl70.bpl->
TOpenOptionsEx                         : tkSet              , vcl70.bpl->
TFileEditStyle                         : tkEnumeration      , vcl70.bpl->

.....

ISecurityInfo                          : tkInterface        , rtl70.bpl->OleDB
ISecurityInfoSC                        : tkInterface        , rtl70.bpl->OleDB
IDBPromptInitialize                    : tkInterface        , rtl70.bpl->OleDB
IDBPromptInitializeSC                  : tkInterface        , rtl70.bpl->OleDB
IDataInitialize                        : tkInterface        , rtl70.bpl->OleDB
IDataInitializeSC                      : tkInterface        , rtl70.bpl->OleDB
THEMESIZE                              : tkEnumeration      , rtl70.bpl->
PROPERTYORIGIN                         : tkEnumeration      , rtl70.bpl->
TCustomZlibStream                      : tkClass            , rtl70.bpl->ZLib
TCompressionLevel                      : tkEnumeration      , rtl70.bpl->
TCompressionStream                     : tkClass            , rtl70.bpl->ZLib
TDecompressionStream                   : tkClass            , rtl70.bpl->ZLib
EZlibError                             : tkClass            , rtl70.bpl->ZLib
ECompressionError                      : tkClass            , rtl70.bpl->ZLib
EDecompressionError                    : tkClass            , rtl70.bpl->ZLib
Gruß Hagen

MaBuSE 22. Apr 2005 14:35

Re: Wie ermittelt man welche Komponenten in einem Package si
 
Ersteinmal will ich mich für die viele Mühe bedanken:
Danke !!!

Zitat:

Zitat von negaH
@Mabuse:
ok, das mein obiger Code nicht sofort funktioniert ist auch logisch, ich habe ihn hier einfach aus dem gedächtnis eingehämmert, da kann man sich mal irren. Öfters komme ich mit den verschiedenen aber ähnlichen Sprachen durcheinander. Zb. gerade jetzt arbeite ich mit VHDL und dieses ist in der Syntax ähnlich wie PASCAL aber eben nicht gleich, da kostet es schon Anstrengung das if then nicht als if end if; oder das case of end; nicht als case is when end case; zu schreiben :-) sorry also:

Das dachte ich mir, und deshalb habe ich ihn ja angepasst, ich wollte nur wissen, ob ich es richtig gemacht habe ;-)

Zitat:

Zitat von negaH
dieser Code funktioniert bei mir super, und er extrahiert sogar noch den Unit Namen ohne deinen Trick:

...Quellcode...

Wie du auch siehst ist die Deklaration von TEnumModuleFunc durch Borland sehr unglücklich erfolgt. Besser wäre es wie in meiner Deklaration den UserData Paramater als ersten Parameter der Callback zu benutzen. So kann man nämlich diese Callbacks ohne Probleme als Methoden-Callback eines Objectes benutzen. Dazu muß UserData eben nur Self enthalten.

Angezeigt wird zb. nachfolgendes:

Code:
TForm1                                  : tkClass            , Project1.exe->Unit1
HWND                                   : tkInteger          , vcl70.bpl->
TOwnerDrawState                        : tkSet              , vcl70.bpl->
TColor                                 : tkInteger          , vcl70.bpl->
EInvalidGraphic                        : tkClass            , vcl70.bpl->Graphics
...

Bei mir zeigt er alles im Kontext von Projekt1.exe an.

Code:
Boolean                                : tkEnumeration      , Project1.exe->
Char                                   : tkChar             , Project1.exe->
Integer                                : tkInteger          , Project1.exe->
Byte                                   : tkInteger          , Project1.exe->
Word                                   : tkInteger          , Project1.exe->
Cardinal                               : tkInteger          , Project1.exe->
String                                 : tkLString          , Project1.exe->
TObject                                : tkClass            , Project1.exe->System
IInterface                             : tkInterface        , Project1.exe->System
TOwnerDrawState                        : tkSet              , Project1.exe->
TErrorRec                              : tkRecord           , Project1.exe->
TExceptRec                             : tkRecord           , Project1.exe->
TCustomVariantType                     : tkClass            , Project1.exe->Variants
TTypeKind                              : tkEnumeration      , Project1.exe->
TAlignment                             : tkEnumeration      , Project1.exe->
TBiDiMode                              : tkEnumeration      , Project1.exe->
TShiftState                            : tkSet              , Project1.exe->
THelpContext                           : tkInteger          , Project1.exe->
THelpType                              : tkEnumeration      , Project1.exe->
TShortCut                              : tkInteger          , Project1.exe->
TNotifyEvent                           : tkMethod           , Project1.exe->
TPersistent                            : tkClass            , Project1.exe->Classes
TInterfacedPersistent                  : tkClass            , Project1.exe->Classes
IStringsAdapter                        : tkInterface        , Project1.exe->Classes
TStrings                               : tkClass            , Project1.exe->Classes
TStringItem                            : tkRecord           , Project1.exe->
TStringList                            : tkClass            , Project1.exe->Classes
TComponentName                         : tkLString          , Project1.exe->
IDesignerNotify                        : tkInterface        , Project1.exe->Classes
TComponent                             : tkClass            , Project1.exe->Classes
TBasicAction                           : tkClass            , Project1.exe->Classes
TIdentMapEntry                         : tkRecord           , Project1.exe->
TColor                                 : tkInteger          , Project1.exe->
TFontPitch                             : tkEnumeration      , Project1.exe->
TFontName                              : tkLString          , Project1.exe->
...
THelpEvent                             : tkMethod           , Project1.exe->
TCustomForm                            : tkClass            , Project1.exe->Forms
TForm                                  : tkClass            , Project1.exe->Forms
TCustomDockForm                        : tkClass            , Project1.exe->Forms
TScreen                                : tkClass            , Project1.exe->Forms
THintInfo                              : tkRecord           , Project1.exe->
TApplication                           : tkClass            , Project1.exe->Forms
TForm2                                  : tkClass            , Project1.exe->Unit2
TForm1                                  : tkClass            , Project1.exe->Unit1
Ich versuche im Programm eine BPL zu laden.
Delphi-Quellcode:
  LoadPackage('c:\Programme\Borland\Delphi7\Bin\dclSockets70.bpl');
Diese BPL will ich nun untersuchen.

Die erscheint in obiger Liste gar nicht, obwohl sie doch geladen wurde.

Aber ich glaube wir haben etwas aneinander vorbei geredet (geschrieben ;)):

Die BPL ist nicht in mein Programm (Listing 1. Beitrag) compiliert.
(Sie wird via TOpenDialog zur Laufzeit ausgewählt)

Mit GetPackageDescription bekomme ich die Beschreibung
(z.B. bei dclSockets70.bpl: "Borland Socket-Komponenten")

Mit GetPackageInfo bekomme ich die von dem Package benötigten Packages
(z.B. bei dclSockets70.bpl: "rtl70.bpl")

Mit GetPackageInfo bekomme ich die von dem Package benutzten Units (dcu Dateien)
(z.B. bei dclSockets70.bpl: "dclsockets, SocketsReg, SysInit")

In der Callback Prozedur ermittele ich auch noch ob eine "procedure Register;" vorhanden ist
(z.B. bei dclSockets70.bpl: "SocketsReg.Register;")

Die DelphiIDE ruft diese Register Prozedur auf und initialisiert damit die Komponenten.
(z.B.
Delphi-Quellcode:
procedure Register;
begin
  RegisterComponents('Internet', [TClientSocket, TServerSocket]);
end;
)

Ich will also ein beliebiges Package öffnen und ermitteln welche Komponenten dort drin sind.

Mein Tool gibt nun folgendes aus:
Code:
Dateiname: c:\Programme\Borland\Delphi7\Bin\dclsockets70.bpl
  Package Name: Borland Socket-Komponenten
  Flags: 00 - benötigt Package: rtl70.bpl
  Flags: 03 - Unit: dclsockets
  Flags: 00 - Unit: SocketsReg
               SocketsReg.Register;
  Flags: 00 - Unit: SysInit
  Flags: 00 - PackageName: dclsockets
Was mit fehlt ist nun das in der dclSockets70.bpl folgende Komponenten enthalten sind:
Code:
TClientSocket, TServerSocket
Hat jemand eine Idee?

Stevie 22. Apr 2005 14:40

Re: Wie ermittelt man welche Komponenten in einem Package si
 
Kann es sein, dass du dein Programm mit der "Mit Laufzeit-Packages aktualisieren"-Option erstellen musst, damit dein Vorhaben funktioniert?

MaBuSE 22. Apr 2005 14:42

Re: Wie ermittelt man welche Komponenten in einem Package si
 
Zitat:

Zitat von Stevie
Kann es sein, dass du dein Programm mit der "Mit Laufzeit-Packages aktualisieren"-Option erstellen musst, damit dein Vorhaben funktioniert?

Habe ich schon mit und ohne probiert.
(Hagens Ansatz habe ich noch nicht damit probiert...)

[edit]
nun gibt Hagens Lösung auch das von Ihm gewünschte Ergebnis:
Code:
TForm2                                  : tkClass            , Project1.exe->Unit2
TForm1                                  : tkClass            , Project1.exe->Unit1
HWND                                   : tkInteger          , vcl70.bpl->
TOwnerDrawState                        : tkSet              , vcl70.bpl->
TColor                                 : tkInteger          , vcl70.bpl->
EInvalidGraphic                        : tkClass            , vcl70.bpl->Graphics
EInvalidGraphicOperation               : tkClass            , vcl70.bpl->Graphics
TFontPitch                             : tkEnumeration      , vcl70.bpl->
...
Aber das ist ja nicht das was ich will. Mein Package wird immer noch nicht in der Liste angezeigt :-(
[/edit]

[edit & OT] Ich bin nun im Wochenende, ich schau heute Abend / Morgen vormittag noch mal vorbei...[/edit]

maximov 22. Apr 2005 14:54

Re: Wie ermittelt man welche Komponenten in einem Package si
 
Moin,

aber wenn du mit
Delphi-Quellcode:
function LoadPackage(const Name: string): HMODULE;
dann bekommst du doch genau das Handle, was du bei der suche angeben solltest!?
Delphi-Quellcode:
var Module:HMODULE;
...
EnumTypeInfo(Module,RegClassesHandler,nil);
Naja, wer nicht hören will... :mrgreen:


PS: mit den laufzeit-packages hat das IMO nix zu tun, denn die werden ja ins hauptmodul eingebunden. Zumindest ist das in diesen zusammenhang witzlos, da ja dynamisch geladen werden soll.

negaH 22. Apr 2005 18:23

Re: Wie ermittelt man welche Komponenten in einem Package si
 
LoadPackage() wird bei seiner Methode schon fehlschlagen, d.h. der Rückgabewert wird schon INVALID_HANDLE_VALUE oder 0 oder -1 sein aber kein gültiges Modul.

Du kannst in deine Anwendung kein Package laden das selber wiederum das VCL Package benötigt in dem selber wiederum die Units Classes, Forms ect. pp. gelinkt wurden.

Deine Anwendung MUSS mit Laufzeitpackage compiliert werden, anders ginge es nur wenn du das Package mit LoadLibrary() lädst. Aber NUR so LoadLibrary('Package.bpl', LOAD_LIBRARY_AS_DATAFILE) und dann dieses Handle meiner EnumTypeInfo() Funktion direkt übergibst.

Gruß Hagen

negaH 22. Apr 2005 19:38

Re: Wie ermittelt man welche Komponenten in einem Package si
 
So wie nachfolgend geht es auch mit einer EXE die ohne Laufzeitpackages compiliert wurde.

Delphi-Quellcode:
procedure TForm1.Button2Click(Sender: TObject);
var
  Module: hModule;
begin
  Module := LoadLibrary('VCLDB70.bpl');
  if Module <> INVALID_HANDLE_VALUE then
  try
    Memo.Lines.BeginUpdate;
    try
      Memo.Clear;
      EnumTypeInfo(Module, @TForm1.DoEnumTypeInfo, Self);
    finally
      Memo.Lines.EndUpdate;
    end;
  finally
    FreeLibrary(Module);
  end;
end;
Wichtig ist nur das du nicht LoadPackage() benutzt da diese Funktion intern viel mehr Überprüfungen durchführt. Mit LoadPackage() können nur Packages geladen und initialisiert werden die unterschiedliche Units zu den schon geladenen Modulen enthalten.

Gruß Hagen

MaBuSE 25. Apr 2005 09:10

Re: Wie ermittelt man welche Komponenten in einem Package si
 
Zitat:

Zitat von negaH
So wie nachfolgend geht es auch mit einer EXE die ohne Laufzeitpackages compiliert wurde.
Delphi-Quellcode:
...
  Module := LoadLibrary('VCLDB70.bpl');
...
Wichtig ist nur das du nicht LoadPackage() benutzt da diese Funktion intern viel mehr Überprüfungen durchführt. Mit LoadPackage() können nur Packages geladen und initialisiert werden die unterschiedliche Units zu den schon geladenen Modulen enthalten.

Ich hatte mit LoafPackage keine Probleme.
Aber mit LoadLibrary funktioniert es auch nicht so recht.

Probier mal bitte das Package dclSockets70.bpl aus.
Es sind 2 Komponenten enthalten. Keine wird angezeigt.

Probier mal dclstd70.bpl aus
Es werden einige Klassen angezeigt, aber eben nicht alle.
Vor allem nicht die Komponenten:
[equote="MaBuSE schrieb in http://www.delphipraxis.net/internal...=356197#356197 "]Mein Versuch gestern mit Deiner Unit brachten mich etwas weiter.
...
Dabei ist mir folgendes aufgefallen:
1. Es werden nicht alle Komponenten gefunden.
2. RegisterClass wird nicht aufgerufen, obwohl TForm von TPersistent abgeleitet ist.
Hier die Ausgabe der Procedure für Package dclstd70.bpl
Code:
Unit:FiltEdit - Klasse: TFilterEditor = class(TForm)
Unit:FiltEdit - Klasse: TFilterProperty = class(TStringProperty)
Unit:MaskText - Klasse: TMaskTextProperty = class(TStringProperty)
Unit:MaskText - Klasse: TMaskTextForm = class(TForm)
Unit:MaskProp - Klasse: TMaskProperty = class(TStringProperty)
Unit:MaskProp - Klasse: TMaskForm = class(TForm)
Unit:ItemEdit - Klasse: TItemInfo = class(TObject)
Unit:ItemEdit - Klasse: TListViewItems = class(TForm)
Unit:NodeEdit - Klasse: TTreeViewItems = class(TForm)
Unit:ImgEdit - Klasse: TImageInfo = class(TObject)
Unit:ImgEdit - Klasse: TImageListEditor = class(TForm)
Unit:NewStdAc - Klasse: TNewStdActionDlg = class(TForm)
Unit:ActnDrag - Klasse: TActionDragObject = class(TDragControlObject)
Unit:ActnEdit - Klasse: TActionImageListListener = class(TChangeLink)
Unit:ActnEdit - Klasse: TActionListDesigner = class(TToolbarDesignWindow)
Unit:ActnRes - Klasse: TStandardActions = class(TDataModule)
Unit:XPMan - Klasse: TXPManifest = class(TComponent)
Unit:SBarEdit - Klasse: TStatusBarEditor = class(TForm)
Unit:ColEdit - Klasse: TColInfo = class(TObject)
Unit:ColEdit - Klasse: TListViewColumns = class(TForm)
Unit:HCtlEdit - Klasse: THeaderControlEditor = class(TForm)
Unit:DdeReg - Klasse: TSrvrConvEdit = class(TDefaultEditor)
Unit:DdeReg - Klasse: TCliConvEdit = class(TDefaultEditor)
Unit:DdeReg - Klasse: TSrvrItemEdit = class(TDefaultEditor)
Unit:DdeReg - Klasse: TDdeLinkDlg = class(TForm)
Unit:DdeReg - Klasse: TDdeLinkInfoProperty = class(TPropertyEditor)
Unit:DdeReg - Klasse: TDdeClientItemProperty = class(TStringProperty)
In dem Package sind aber noch folgende Komponenten registriert:
TOpenDialog, TSaveDialog, TOpenPictureDialog, TSavePictureDialog, TFontDialog, TColorDialog, TPrintDialog, TPrinterSetupDialog, TFindDialog, TReplaceDialog, TPageSetupDialog, TTimer, TPaintBox, TMediaPlayer, TMainMenu, TPopupMenu, TLabel, TEdit, TMemo, TButton, TCheckBox, TRadioButton, TListBox, TComboBox, TScrollBar, TGroupBox, TRadioGroup, TPanel, TActionList, TBitBtn, TSpeedButton, TMaskEdit, TStringGrid, TDrawGrid, TImage, TShape, TBevel, TScrollBox, TCheckListBox, TSplitter, TStaticText, TControlBar, TApplicationEvents, TValueListEditor, TLabeledEdit, TColorBox, TTabControl, TPageControl, TImageList, TRichEdit, TTrackBar, TProgressBar, TUpDown, THotKey, TAnimate, TDateTimePicker, TMonthCalendar, TTreeView, TListView, THeaderControl, TStatusBar, TToolBar, TCoolBar, TPageScroller, TComboBoxEx, TXPManifest, TOleContainer, TCOMAdminCatalog, TDdeClientConv, TDdeClientItem, TDdeServerConv und TDdeServerItem

Für das Package dclsockets70.bpl zeigt mir Deine Funktion gar nichts an, aber es sind die Komponenten
TClientSocket und TServerSocket enthalten[/equote]

MaBuSE 25. Apr 2005 09:18

Re: Wie ermittelt man welche Komponenten in einem Package si
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hier ist ein kleines Beispielprogramm um das mal auszuprobieren:

negaH 25. Apr 2005 09:53

Re: Wie ermittelt man welche Komponenten in einem Package si
 
Vergiss es, das was du vorhast kann nicht funktionieren. Du versucht die Packages der Delphi IDE zu laden, diese können aber nur innerhalb vom Delphi selber geladen und benutzt werden.

Erkläre mal was du überhaupt vor hast, denn so wie ich das sehe läuft es auf einen Verstoß gegen die Lizenzbestimmungen hinaus.

Gruß Hagen

MaBuSE 25. Apr 2005 12:23

Re: Wie ermittelt man welche Komponenten in einem Package si
 
Zitat:

Zitat von negaH
Vergiss es, das was du vorhast kann nicht funktionieren. Du versucht die Packages der Delphi IDE zu laden, diese können aber nur innerhalb vom Delphi selber geladen und benutzt werden.

So langsam habe ich auch das Gefühl, dass das nicht klappt.

Zitat:

Zitat von negaH
Erkläre mal was du überhaupt vor hast, denn so wie ich das sehe läuft es auf einen Verstoß gegen die Lizenzbestimmungen hinaus.

Nein, ich will nicht gegen die Lizenzbestimmungen verstoßen.

[OffTopic, nur zur Erklärung, nicht zur Diskussion]
[edit]...(Erklärung entfernt, da OT)[/edit]
Deshalb möchte ich vorher durch ein kleines Testprogramm alle einzubindenden Package untersuchen ob "doppelte" Komponenten enthalten sind dann kann man vor dem Kompilieren schon darauf reagieren.
(Diese Funktionalität soll auch noch zu Diagnosezwecken beim Delphi Start laufen, ...)

Da dieses Testprogramm nur auf dem Buildserver läuft (auf dem auch eine vollständige Lizenz des Delphi installiert ist) besteht keine Lizenzverletzung.
[/OffTopic]

Liebe Grüße
MaBuSE

MaBuSE 25. Apr 2005 12:49

Re: Wie ermittelt man welche Komponenten in einem Package si
 
Zitat:

Zitat von negaH
Vergiss es, das was du vorhast kann nicht funktionieren. Du versucht die Packages der Delphi IDE zu laden, diese können aber nur innerhalb vom Delphi selber geladen und benutzt werden.

AAAARRRG :wall:

Ich habe gerade bemerkt warum dass nicht geht.

Lieber Hagen, Du hast Recht.
In den DesigntimePackages (dcl*.bpl) sind natürlich keine Komponenten definiert.
Die sind ja in den RuntimePackages. Die benötigten Runtimepackages bekomme ich ja mit meiner Methode raus, ich muss also alle RuntimePackages durchlaufen um "doppelte" Komponenten zu finden.

Da zu lade ich alle DesigntimePackages und merke mir welche Packages benötigt werden.
Dann schaue ich alle (diese benötigten) RuntimePackage duch und wenn eine Komponente doppelt vorkommt, weiss ich ja welche 2 RuntimePackage davon betroffen sind und kann daraus schliessen, weche DesigntimePackage dafür verantwortlich sind.

Vielen Dank, wenn ich das mal soweit "fertig" habe, werde ich es hier aud Anfrage veröffentlichen.

MaBuSE 25. Apr 2005 13:03

Re: Wie ermittelt man welche Komponenten in einem Package si
 
Anmerkungen und Links zu deisem Thema:
Ich kann zwar kein Chinesisch, aber hier (GoogleCache) wird gezeigt, die man durch Zuweisen der Classes.RegisterComponentsPro mit einer eigenen Prozedur an diese Informationen kommt. Das ist die gleiche Idee, die ich auch schon letzte Woche hatte, nur die Funktioniert bei mir nicht. Es tritt trotzdem der Fehler auf. (Meine Prozedur wird nicht ausgeführt.)

Folgende Artikel beschäftigen sich auch mit Packages zur Laufzeit:

negaH 25. Apr 2005 16:21

Re: Wie ermittelt man welche Komponenten in einem Package si
 
Zitat:

In den DesigntimePackages (dcl*.bpl) sind natürlich keine Komponenten definiert.
Die sind ja in den RuntimePackages. Die benötigten Runtimepackages bekomme ich ja mit meiner Methode raus, ich muss also alle RuntimePackages durchlaufen um "doppelte" Komponenten zu finden.
Richtig, mal abgesehen von den nötigen Designtime Komponenten wie Property Editoren usw. Diese benötigen aber immer auch die Funktionen der IDE oder genauer gesagt der ominösen Proxies.dcu :)

Die für dich relevanten Klassen sollten alle in Runtime Packages enthalten sein, aber das ist eben bei so manchen Libraries nicht der Fall. Die Methode mit dem Finden doppelter Komponten steckt in ähnlicher Form schon un der Funktion LoadPackage() drinnen. Diese benutzt aber nicht die Komponenten sondern die UNIT Listen die in der Resourcen der Packages eingelinkt werden. Vorteil dabei ist das man beim Zugriff auf solche Packages um diese Resource zu laden diese DLL nicht komplett laden braucht. Sprich man lädt sie nur als Resourcen-DLL, lädt die UNIT-Resource, und vergleicht deren Inhalt mit den UNITs der anderen Packages. In einem Projekt ist ein UNIT-Name packagebezogen immer eineindeutig. Eventuell könnte dies deine Überprüfung enorm erleichtern. Schau dir dazu mal den Source von SysUtils.CheckForDuplicateUnits().InternalUnitChec k() genauer an.

Ich habe aber noch nicht ganz den Sinn der Übung verstanden, wie ihr eure Projekte verwaltet, ist aber auch nicht so wichtig.

Gruß hagen

negaH 25. Apr 2005 16:24

Re: Wie ermittelt man welche Komponenten in einem Package si
 
Achso, sich an den Klassen/Komponenten als Vergleichskriterium festzuklammern kann nach hinten losgehen. Denn es ist schon erlaubt das man in verschiedenen Units einen Klassennamen mehrmals benutzen darf, und dies kommt sogar manchmal vor. Aber ein UNIT-Name muß eben innerhalb der geladenen Packages eineindeutig sein.

Gruß Hagen

MaBuSE 25. Apr 2005 16:29

Re: Wie ermittelt man welche Komponenten in einem Package si
 
Zitat:

Zitat von negaH
Achso, sich an den Klassen/Komponenten als Vergleichskriterium festzuklammern kann nach hinten losgehen. Denn es ist schon erlaubt das man in verschiedenen Units einen Klassennamen mehrmals benutzen darf, und dies kommt sogar manchmal vor. Aber ein UNIT-Name muß eben innerhalb der geladenen Packages eineindeutig sein.

Stimmt, Du hast Recht. Ich brauche ja nur auf Unit Ebene zu schauen :wall:

Danke an Alle für die ausführliche Hilfe.
Das Wissen kann ich trotzdem sehr gut gebrauchen :mrgreen:
(, und der Eine oder Andere vieleicht auch)


Alle Zeitangaben in WEZ +1. Es ist jetzt 17:16 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz