![]() |
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. |
Re: Wie ermittelt man welche Komponenten in einem Package si
Hi Mabuse,
folgendende Unit hab ich bei unseren niederländischen Kollegen gefunden:
Delphi-Quellcode:
Allerdings ist hierbei Vorraussetzung, dass die Klassen registriert sind, ansonsten hast du nicht wirklich eine Chance, sie zu finden.
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. MfG Stevie |
Re: Wie ermittelt man welche Komponenten in einem Package si
Danke für die Antwort.
Zitat:
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:
Wie kann ich die denn zur Laufzeit registrieren um zu sehen welche Komponenten in dem Package enthalten sind?
RegisterComponent('Palette', [TMyComponent]);
|
Re: Wie ermittelt man welche Komponenten in einem Package si
Zitat:
Delphi-Quellcode:
initialization
RegisterClass(TMyClass); finalization UnRegisterClass(TMyClass); |
Re: Wie ermittelt man welche Komponenten in einem Package si
Zitat:
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:
Mir fehlen z.B. noch folgende Informationen:
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
Code:
Hat jemand eine Idee ?
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 |
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: ![]() |
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 |
Re: Wie ermittelt man welche Komponenten in einem Package si
Zitat:
Dein hier geposteter Quellcode funktioniert bei mir so nicht. Folgende Dinge musste ich ändern:
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:
Dabei ist mir folgendes aufgefallen:
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; 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:
In dem Package sind aber noch folgende Komponenten registriert:
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) 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 |
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:
In der Register; stehen für normalerweise die RegisterComponents(...) Aufrufe
...
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; ... Der Aufruf schlägt natürlich fehl, weil die Prozedur RegisterComponentsProc nur in der IDE gesetzt ist, zur Laufzeit ist sie nil.
Delphi-Quellcode:
Wenn man diese Prozedur zuweist, sollte es klappen:
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;
Delphi-Quellcode:
Es wird auch 'Test hat geklappt' im Memo ausgegeben -> es funktioniert
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; 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. |
Re: Wie ermittelt man welche Komponenten in einem Package si
Zitat:
|
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:
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.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; Angezeigt wird zb. nachfolgendes:
Code:
Gruß Hagen
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 |
Re: Wie ermittelt man welche Komponenten in einem Package si
Ersteinmal will ich mich für die viele Mühe bedanken:
Danke !!! Zitat:
Zitat:
Code:
Ich versuche im Programm eine BPL zu laden.
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
Delphi-Quellcode:
Diese BPL will ich nun untersuchen.
LoadPackage('c:\Programme\Borland\Delphi7\Bin\dclSockets70.bpl');
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:
Was mit fehlt ist nun das in der dclSockets70.bpl folgende Komponenten enthalten sind:
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
Code:
Hat jemand eine Idee?
TClientSocket, TServerSocket
|
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?
|
Re: Wie ermittelt man welche Komponenten in einem Package si
Zitat:
(Hagens Ansatz habe ich noch nicht damit probiert...) [edit] nun gibt Hagens Lösung auch das von Ihm gewünschte Ergebnis:
Code:
Aber das ist ja nicht das was ich will. Mein Package wird immer noch nicht in der Liste angezeigt :-(
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-> ... [/edit] [edit & OT] Ich bin nun im Wochenende, ich schau heute Abend / Morgen vormittag noch mal vorbei...[/edit] |
Re: Wie ermittelt man welche Komponenten in einem Package si
Moin,
aber wenn du mit
Delphi-Quellcode:
dann bekommst du doch genau das Handle, was du bei der suche angeben solltest!?
function LoadPackage(const Name: string): HMODULE;
Delphi-Quellcode:
Naja, wer nicht hören will... :mrgreen:
var Module:HMODULE;
... EnumTypeInfo(Module,RegClassesHandler,nil); 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. |
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 |
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:
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.
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; Gruß Hagen |
Re: Wie ermittelt man welche Komponenten in einem Package si
Zitat:
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 ![]() ... 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:
In dem Package sind aber noch folgende Komponenten registriert:
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) 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] |
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:
|
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 |
Re: Wie ermittelt man welche Komponenten in einem Package si
Zitat:
Zitat:
[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 |
Re: Wie ermittelt man welche Komponenten in einem Package si
Zitat:
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. |
Re: Wie ermittelt man welche Komponenten in einem Package si
Anmerkungen und Links zu deisem Thema:
Ich kann zwar kein Chinesisch, aber ![]() ![]() Folgende Artikel beschäftigen sich auch mit Packages zur Laufzeit: |
Re: Wie ermittelt man welche Komponenten in einem Package si
Zitat:
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 |
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 |
Re: Wie ermittelt man welche Komponenten in einem Package si
Zitat:
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