![]() |
Plugins selbst gemacht?
Hi
ist eigentlich nur eine Spinnerei: aber kann ich mit Delphi irgendwie PlugIns für meine Programme schreiben? Damit könnte ich mein Programm erweitern, ohne groß code schreiben zu müssen - wenn ich einen PlugIn-Editor baue. Also einfaches Beispiel: ich will einem Program die Fähigkeit geben und nehmen können z.B. Druckausgabe zu unterstützen, ohne das Programm dabei groß ändern zu müssen - einfach nur durch eine externe Datei, die auf Existenz geprüft wird. ungefähr so: if FilExists(PluginName+'.plg') then EnableFunction(PlugInTitle); wobei die Befehle in einer externen Datei und in einer Speziellen Plugin-Sprache vorliegen... Eine BEfehlsfolge könnte dann so aussehen: PrinterCmd=CommandStream.Beginn; CreatePrinter; SetupPage; PrintDocument; DestroyPrinter; PrinterCmd=CommandStream.End; Hat jemand eine Idee, wie man sowas verwirklichen könnte? |
Man könnte das zum Beispiel mit einer oder mehreren DLL's lösen.
Such mal auf der SEite, da gibt es relativ viele Beispiele mit DLL's. |
Für die unter Euch, welche den Thread beobachten, hier ein Link zum aktuellen Tutorial:
![]() ...:cat:... |
Hi...
ich hab mal ein Testproramm für mein erstes Plugin geschrieben. Das Plugin an sich ist sinnlos, deshalb poste ich auch nix davon. mein Testprogramm sieht so aus:
Code:
in der unit PluginDef steht nur die Definition (also die Klasse) wie ein Plugin aufgebaut ist.
unit Main;
interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, Menus, PluginDef; type TLibraryData = record Handle: Cardinal; Plugin: TPlugin; MenuItem: TMenuItem; end; TForm1 = class(TForm) MainMenu1: TMainMenu; mnuPlugins: TMenuItem; procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); private { Private declarations } FPlugins: array of TLibraryData; procedure LoadPlugin(DLLName: string); procedure LoadPlugins; procedure ExecutePlugin (Sender: TObject); procedure UnloadPlugins; public { Public declarations } end; var Form1: TForm1; implementation {$R *.dfm} uses Inifiles; procedure TForm1.LoadPlugins; var PluginRegistryFile: string; i: integer; iniFile: TInifile; Plugins: TStringlist; begin PluginRegistryFile := ExtractFilePath(Application.Exename)+'Plugins.ini'; if not FileExists (PluginRegistryFile) then Exit; iniFile := TIniFile.Create(PluginRegistryFile); try Plugins := TStringlist.Create; try IniFile.ReadSections(Plugins); for i:= 0 to Pred(Plugins.Count) do begin if AnsiCompareText(iniFile.ReadString(Plugins[i],'type',''),'plugin') = 0 then begin LoadPlugin(iniFile.ReadString(Plugins[i],'dllname','')); end; end; finally Plugins.Free; end; finally iniFile.Free; end; end; procedure TForm1.LoadPlugin(DLLName: string); var TempHandle: Cardinal; ProcAddr: Pointer; LoadPluginProc: TLoadPlugin; TempPlugin: TPlugin; begin if not ((Copy(DLLName,2,1) = ':') or (Copy(DLLName, 1,2) = '\\')) then DLLName := ExtractFilePath(Application.Exename)+DLLName; TempHandle := LoadLibrary (PChar(DLLName)); if (TempHandle <> INVALID_HANDLE_VALUE) and (TempHandle <> 0) then begin ProcAddr := GetProcAddress (TempHandle, 'LoadPlugIn'); if ProcAddr = nil then begin FreeLibrary (TempHandle); Exit; end; LoadPluginProc := TLoadPlugin(ProcAddr); try TempPlugin := nil; LoadPluginProc(Application.Handle, TempPlugin); except FreeLibrary(TempHandle); exit; end; SetLength(FPlugIns, Succ(Length(FPlugins))); FPlugins[High(Fplugins)].Handle := TempHandle; //Add the Plugin to the menu with FPlugins[High(FPlugins)] do begin Plugin := TempPlugin; MenuItem := TMenuItem.Create(Self); MenuItem.Caption := TempPlugin.GetMenuText; MenuItem.Enabled := TempPlugin.GetEnabled; MenuItem.Tag := High(FPlugins); MenuItem.OnClick := ExecutePlugin; end; mnuPlugins.Add(FPlugins[High(Fplugins)].MenuItem); end; end; procedure TForm1.ExecutePlugin (Sender: TObject); begin if Sender = nil then exit; if not (Sender is TMenuItem) then exit; (* if FPlugins[TMenuItem(Sender).Tag].Plugin <> nil then FPlugins[TMenuItem(Sender).Tag].Plugin.Execute; *) if FPlugins[(Sender as TMenuItem).Tag].Plugin <> nil then FPlugins[(Sender as TMenuItem).Tag].Plugin.Execute; end; procedure TForm1.FormCreate(Sender: TObject); begin SetLength(FPlugins, 0); LoadPlugins; end; procedure TForm1.FormDestroy(Sender: TObject); begin UnloadPlugins; end; procedure TForm1.UnloadPlugins; var i: integer; begin if Length(FPlugins) > 0 then begin for i:= 0 to Pred(Length(FPlugins)) do try if FPlugins[i].MenuItem <> nil then FPlugins[i].MenuItem.Free; if FPlugins[i].Plugin <> nil then FPlugins[i].Plugin.Free; FreeLibrary(FPlugins[i].Handle); except end; end; end; end. Wenn ich auf den erstellten Menüpunkt klicke, bekomme ich beim ersten Klicken eine "INVALID POINTER OPERATION". Bei weiteren Klicks funktioniert es. Beim Beenden des Programms bekomme ich eine AccessViolation an der Adresse $00000000. Meine große Frage: WARUM? @sakura (falls du das lesen solltest): du wirst den code erkennen :-) |
OK, Sorry, vergesst es: ich habe vergessen die Unit SHAREMEM in das projekt einzubinden... Ohne die kann es nicht funzen :oops: :twisted: :mrgreen: :coder: :witch: :nerd: :freak: :bounce1: :bouncing4: :dancer2:
|
Zitat:
...:cat:... |
taj ja, manchmal sollte man vorher denken, bevor man das Forum bemüht *leicht-selbst-kristitsch-bemerk*
:dancer: anyway - plugins sind cool |
hmmm, irgendwie hab ich's zur Zeit mit AccessViolations, ich schaff es immer wieder, egal, was ich mache... Spaß beiseite.
Rein theoretisch müsste ich die Klasse TPlugIn mit ein paar Prozeduren erweitern können. Ich will nämlich ein Aboutbox-Plugin schreiben und der Form, die ich in das Plugin eingebunden habe, ein paar Informationen geben:
Dashier:
Code:
wäre meine Methode die Klasse zu erweitern... Geht aber nicht, wegen der oben angesprochenen AccessViolation, die auftritt, wenn das Plugin geladen werden soll.
public
constructor Create(aParent: THandle); procedure SubmitPicutre(Filename: string); virtual; stdcall; abstract; procedure SubmitProductname(Productname: string); virtual; stdcall; abstract; procedure SubmitVersion(Version: string); virtual; stdcall; abstract; procedure SubmitCopyright(Copyright: string); virtual; stdcall; abstract; procedure SubmitComments(Comments: string); virtual; stdcall; abstract; Ja, ich hab ShareMem eingebunden, in die DLL und in mein Projekt. Die INI stimmt auch... Die Borland DLL ist auch vorhanden... Und nu? |
Hast Du die ShareMem Unit auch als erste Unit in die Projekt uses-Klausel von Anwendung und DLL genommen? Wenn ja, zeige mal die PlugIn-Klasse der DLL.
...:cat:... |
ich poste einfach mal die komplette DLL (ist noch nicht soo lange)
Code:
Da fehlt noch eine Prozedur, die dann die Aboutbox updaten soll, aber das kriege ich dann schon hin, wenn ich weiß, was ich falsch gemacht habe...
library Aboutplg;
uses ShareMem, SysUtils, Classes, Windows, Forms, PluginDef in '..\Shared\PluginDef.pas', frmPlugAbout in 'frmPlugAbout.pas' {AboutBox}; {$R *.res} type TPluginAbout = class (TPlugIn) private FPicFilename, FProductname, FCopyright, FVersion, FComments: string; public constructor Create(aParent: THandle); procedure SubmitPicutre(Filename: string); override; stdcall; procedure SubmitProductname(Productname: string); override; stdcall; procedure SubmitVersion(Version: string); override; stdcall; procedure SubmitCopyright(Copyright: string); override; stdcall; procedure SubmitComments(Comments: string); override; stdcall; // information strings function GetName: string; override; stdcall; function GetAuthor: string; override; stdcall; function GetComment: string; override; stdcall; // menu data function GetMenuText: string; override; stdcall; function GetEnabled: Boolean; override; stdcall; // launch the Expert procedure Execute; override; stdcall; // event handler function EventHandler(EventNotification: TEventNotification): TEventAction; override; stdcall; end; procedure TPluginAbout.SubmitPicutre(Filename: string); stdcall; begin FPicFilename := Filename; end; procedure TPluginAbout.SubmitProductname(Productname: string); stdcall; begin FProductname := Productname; end; procedure TPluginAbout.SubmitVersion(Version: string); stdcall; begin FVersion := Version; end; procedure TPluginAbout.SubmitCopyright(Copyright: string); stdcall; begin FCopyright := Copyright; end; procedure TPluginAbout.SubmitComments(Comments: string); stdcall; begin FComments := Comments; end; constructor TPluginAbout.Create(aParent: THandle); begin inherited Create(aParent); FProductname := 'Aboutplg.dll'; FVersion := '1.0'; FCopyright := 'Copyright(C) 2003 by Michael Kirches'; FComments := 'This is a test plugin'; end; // information strings function TPluginAbout.GetName: string; stdcall; begin result := 'About Plugin'; end; function TPluginAbout.GetAuthor: string; stdcall; begin result := 'Michael Kirches'; end; function TPluginAbout.GetComment: string; stdcall; begin result := 'This plugin creates and handles an aboutbox'; end; // menu data function TPluginAbout.GetMenuText: string; stdcall; begin result := 'About'; end; function TPluginAbout.GetEnabled: Boolean; stdcall; begin result := True; end; // launch the Expert procedure TPluginAbout.Execute; stdcall; begin // MessageBox(Parent, 'This is Plugin No. 1 calling.','Info',0); //Now we've got something todo... try Aboutbox := TAboutbox.Create(Application); if FPicFilename <> '' then Aboutbox.ProgramIcon.Picture.LoadFromFile(FPicFilename); Aboutbox.ProductName.Caption := FProductname; Aboutbox.Version.Caption := FVersion; Aboutbox.Copyright.Caption := FCopyright; Aboutbox.Comments.Caption := FComments; Aboutbox.Rescale; Aboutbox.ShowModal; finally Aboutbox.Free; end; end; // event handler function TPluginAbout.EventHandler(EventNotification: TEventNotification): TEventAction; stdcall; begin result := evnContinue; end; function LoadPlugin(Parent: THandle; var PlugIn: TPlugIn): Boolean; export; begin try PlugIn := TPluginAbout.Create(Parent); Result := True; except Result := False; end; end; exports LoadPlugIn name 'LoadPlugIn'; begin end. Ach ja: ShareMem ist in beiden Projekten die erste Unit in der uses-clause |
Alle Zeitangaben in WEZ +1. Es ist jetzt 13:35 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