Novembre 2024 | Lun | Mar | Mer | Jeu | Ven | Sam | Dim |
---|
| | | | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | | Calendrier |
|
|
| Plugins dans Panoramic ? | |
| | Auteur | Message |
---|
Klaus
Nombre de messages : 12331 Age : 75 Localisation : Ile de France Date d'inscription : 29/12/2009
| Sujet: Plugins dans Panoramic ? Lun 4 Nov 2013 - 14:24 | |
| Je relance un vieux serpent de mer: les plugins avec Panoramic. J'ai trouvé un moyen de faire des plugins pour un programme écrit en Delphi. Les plugins sont réalisés sous forme d'un fichier source en Pascal Script, utilisant l'interface DLL de la version gratuite de pdScript de Precision software & consulting. J'ai réalisé ainsi une maquette gérant l'exécution des plugins (j'en ai réalisé 2), avec la possibilité d'ajouter des plugins dynamiquement, sans devoir arrêter et relancer le programme, via justement un plugin dédié à cela. Je peux inclure ce mécanisme dans une DLL et faire ainsi de sorte qu'un programme application en Panoramic pourra avoir ses propres plugins. Mais de façon beaucoup plus intéressante: serait-ce possible que ce mécanisme soit ajouté à l'interpréteur de Panoramic , ce qui permetttrait alors réellement de faire des plugins à Panoramic ? Voici ce que j'ai fait. Un programme de démo en programme principal (à remplacer in finé par l'interpréteur Panoramic): - Code:
-
unit Unit1;
interface
uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, pdScriptAPI, // interface required to use pdScript via the DLL Dialogs, StdCtrls;
type TForm1 = class(TForm) Memo1: TMemo; Label1: TLabel; Button1: TButton; Label2: TLabel; cbPlugin: TComboBox; lbTrace: TListBox; Label3: TLabel; procedure Button1Click(Sender: TObject); procedure cbPluginChange(Sender: TObject); procedure FormCreate(Sender: TObject);
private { Déclarations privées } public { Déclarations publiques } end;
var Form1: TForm1; container: string;
implementation
{$R *.dfm}
{ Plugins =======
Plugins are implemented by 2 collaborating routines. The interface apart is implemented within the main program, via a callback function with predefined yet extensible features. The real plugin is a Delphi like program written in Pascal Script language. The implementation is done via the pdScript software. pdScript means "Precision Delphi Script" and is provided by Precision software & consulting. The actual implementation uses the portable freeware version: Copyright (c) 2008-2012 Precision software & consulting. All rights reserved.
This callback function is the actual plugin implementation within the main program. Several plugins may be implemented throughout the same callback function.
The 4 parameters of this functions are used as follows: cCommand character string identifying a command to be executed cParams parameters for the command cBuffer buffer pointer into which a string result is to be returned cBuffSize buffer size
The callback function executes a specific action for each expected command string. In any case, the function returns an integer value, designed to be a success/failure/result value. A predefined normally unused result value should be assigned for unrecognized command codes, other normally unused values should be defined as standard error codes. The remaining result value range is freely available as specific command result values.
This demo version implements 4 plugin functions: GetCaption returns the main form caption to the plugin script SetCaption sets the main form caption to a string provided by the plugin script GetDate returns a character string containing the formatted current date to the plugin script Trace adds a string provided by the plugin script to the trace list box of the main program
The plugin script must use the following template:
***************************************************************************************** program Other_Script;
function plugin():integer; var param, buff: string; begin // sample call to get data from the main program if HostCallback('GetDate','',buff) then showmessage(buff);
// sample call to send data to the main program param := 'Other_Script'; if not HostCallback('Trace',param,buff) then showmessage('Trace returns BAD');
result := 23; // plugin specific numeric result
end;
begin exitcode := 7; end. *****************************************************************************************
} function MyPDScriptCallback(cCommand:PChar; cParams:PChar; cBuffer:PChar; cBufSize:Integer):Integer; stdcall; const cb_unknown = -1; cb_unexpected = -2; var MyText: string; begin Result := cb_unknown;
// commands readund data from the main program if AnsiSameText(cCommand,'GetCaption') then begin result := 0; MyText := Form1.Caption; if (cBuffer=nil) or (cBufSize<=0) then Result:=Length(MyText) else StrPLCopy(cBuffer,MyText,cBufSize); end; if AnsiSameText(cCommand,'GetDate') then begin result := 0; MyText := DateToStr(Date); if (cBuffer=nil) or (cBufSize<=0) then Result:=Length(MyText) else StrPLCopy(cBuffer,MyText,cBufSize); end;
// commands modifying data in the main program if AnsiSameText(cCommand,'SetCaption') then begin result := 0; Form1.Caption:=cParams; end; if AnsiSameText(cCommand,'Trace') then begin result := 0; Form1.lbTrace.Items.Add(cParams); end; if AnsiSameText(cCommand,'Add_Plugin') then begin result := 0; if Form1.cbPlugin.Items.IndexOf(cParams)<0 then begin result := cb_unexpected; end else begin Form1.cbPlugin.Items.Add(cParams); // add new plugin to list Form1.cbPlugin.Items.SaveToFile(container); // and update the container file end; end; end;
{ Sample main program - not relevant for the pluin mecanism itself. This button clic procedure simulates the activation of a user written plugin. The ames of the available plugins are placed in the combo cbPlugin. This combo may be initally loaded by a configuration text file containing the names of all installed plugins. Thus, new plugins can be added ad runtime, without the need to restart the program. To achieve this, a simple command Add_Plugin implemented within the callback function does the trick. So, a plugin adding new plgins can easyly built. } procedure TForm1.Button1Click(Sender: TObject); var res: integer; sfunction, script, dfm, param: string; hnd: THandle; begin
// look if there is a plugin eslected if cbPlugin.Text='' then begin showmessage('No plugin selected.'); exit; end;
// load the pdScript DLL sfunction := 'plugin'; // the user supplied function in the script has to be calles "plugin" // pdScriptLibHandle := pdScriptLoad(pdScriptDllNameCL); // command line version pdScriptLibHandle := pdScriptLoad(pdScriptDllName); // VCL version if not pdScriptReady then begin showmessage('Error - not ready'); exit; end;
// compile the script and let it stay alive // (this implementation does not use a client window for the plugin) script := memo1.Text; // script source code from the memo filled by a click on the combo dfm := ''; // no window // the parameters say "stay alive" and give the callback function address param := '/pds{keep-alive=true;host-callback='+IntToStr(Integer(@MyPDScriptCallback))+'}'; // now, execute the script unline to compile ans syntax check it hnd := Inline_pdScript(script,dfm,param,false); if hnd=1 then begin showmessage('Compile error: '+inttostr(hnd)); pdScriptUnload; exit; end;
// execute the plugin function res := Execute_pdScriptFunction(hnd, sfunction); // call the plugin function showmessage('Result: '+inttostr(res)); pdScriptUnload; // unload pdScript end;
procedure TForm1.cbPluginChange(Sender: TObject); begin memo1.Lines.LoadFromFile(cbPlugin.Text+'.pas'); // load the memo with the selectec plugin's source end;
procedure TForm1.FormCreate(Sender: TObject); var name, path: string; inifile: TextFile; begin // try to localize the plugin container file (same folder as program) name := 'KlausApplication'; path := GetCurrentDir + '\'; container := path+name+'.plg'; if FileExists(container) then begin cbPlugin.Items.LoadFromFile(container) // load the combo from existing file end else begin AssignFile(inifile,container); // create new empty file if missing Rewrite(inifile); CloseFile(inifile); end;
end;
end. Et deux plugins, sans but réel, juste pour montrer le passage de données entre plugin et programme principal: Klaus_Script.pas: - Code:
-
program Klaus_Script;
function plugin():integer; var buff: string; n: integer; b: boolean; s1,s2: string; begin if HostCallback('GetCaption','',buff) then showmessage(buff); s1 := 'aaaaaaaaa'; if not HostCallback('SetCaption',s1,s2) then showmessage('SetCaption returns BAD'); s1 := 'Klaus_Script'; if not HostCallback('Trace',s1,s2) then showmessage('Trace returns BAD'); result := 17; end;
begin exitcode := 7; end.
et Other_Script.pas: - Code:
-
program Other_Script;
function plugin():integer; var param, buff: string; begin // sample call to get data from the main program if HostCallback('GetDate','',buff) then showmessage(buff);
// sample call to send data to the main program param := 'Other_Script'; if not HostCallback('Trace',param,buff) then showmessage('Trace returns BAD'); result := 23; // plugin specific numeric result end;
begin exitcode := 7; end.
(ce dernier fichier est à prendre comme maquette commentée des futurs plugins). Et un fichier container contenant la liste des plugins: - Code:
-
Klaus_Script Other_Script
On voit que les plugins sont réalisés dans un langage très proche de Delphi (un sous-ensemble de Pascal). Ce sont de simples fichiers source qui sont lus, compilés dynamiquement et exécutés par la dll pdScript. Ainsi, ce sont en réalité des scripts qu'on peut créer dynamiquement... Les possibilités sont infinies. Bien entendu, il y a un moyen de crypter des fichiers des plugins si nécessaire, afin de préserver la confidentialité des sources en clientèle. Il va sans dire que tout cela, y compris l'outil pdScript, est entièrement gratuit et utilisable librement. J'ai tout placé sur mon WebDav, dans le dossier Plugins. | |
| | | Jicehel
Nombre de messages : 5947 Age : 52 Localisation : 77500 Date d'inscription : 18/04/2011
| Sujet: Re: Plugins dans Panoramic ? Lun 4 Nov 2013 - 14:42 | |
| Bonjour Klaus, j'ai regardé rapidos depuis le boulot, l'idée à terme serait donc si je comprend bien soit de l'intégrer au niveau de la compilation soit d'ajouter les fonctions dans une DLL ou dans KGF.DLL pour ajouter les scripts dans les programmes ?
Désolé, je suis peut-être passé à côté en lisant trop vite. Je ne dirais pas que je testerais ce soir comme la panne se prolonge et que je ne tiens pas mes délais ... | |
| | | Klaus
Nombre de messages : 12331 Age : 75 Localisation : Ile de France Date d'inscription : 29/12/2009
| Sujet: Re: Plugins dans Panoramic ? Lun 4 Nov 2013 - 14:52 | |
| C'est une des possibilités. On pourrait ainsi faire des plugins pour ses propres programmes. Quoique - l'intérêt en sera certainement pas très grand.
Par contre, si Jack ajoute un tel mécanisme à l'interpréteur de Panoramic (et éventuellement à l'éditeur), on aurait alors un vrai mécanisme de plugin - chose dont on parle depuis longtemps et que Jack a évoqué lui-même. Cela permettrait alors d'ajouter, relativement facilement, des fonctions à Panoramic qui aujourd'hui ne sont possibles que par des DLLs. C'est surtout à cet usage que je pensais. | |
| | | Klaus
Nombre de messages : 12331 Age : 75 Localisation : Ile de France Date d'inscription : 29/12/2009
| Sujet: Re: Plugins dans Panoramic ? Lun 4 Nov 2013 - 15:04 | |
| Pour tester, il suffit de télé-charger le contenu du dossier "plugins", puis de double-cliquer sur test1.exe. On a alors une combo remplie avec les noms des deux plugins fournis: Klaus_Script et Other_Script. Un clic sur l'une ou l'autre de ces lignes charge le script dans le mémo (juste pour voir). Un clic sur "Execute" lance le plugin.
On peut ouvrir l'un ou l'autre de ces plugins dans un éditeur de texte et les modifier pour voir l'effer en temps réel, sans sortir du programme test1.exe. Juste enregistrer les modifs et relancer le plugin. Tout ceci est possible dans l'IDE de Delphi. | |
| | | Jicehel
Nombre de messages : 5947 Age : 52 Localisation : 77500 Date d'inscription : 18/04/2011
| Sujet: Re: Plugins dans Panoramic ? Lun 4 Nov 2013 - 17:22 | |
| Merci pour ta réponse Klaus.
Pour les tests, tant que je n'ai pas Internet chez moi, je ne teste rien...
Sinon oui, les plugins semblent intéressant. Reste à imaginer la façon avec laquelle on les appellerais depuis Panoramic si on ne passait pas par une DLL pour les utiliser, mais bon, voyons la réaction de Jack sur ce sujet. Il aura peut être des idées ou un avis sur l'intégration à Panoramic de ce mécanisme qui c'est vrai peut être plus simple à mettre en oeuvre que les DLL s'il est bien conçu. | |
| | | Invité Invité
| Sujet: Re: Plugins dans Panoramic ? Lun 4 Nov 2013 - 17:38 | |
| Bonjour Klaus.
Formidable pour ce que tu fais. Une question: -je viens de télécharger pour jeter un œil. A l'exécution j'ai un message: un programme malveillant a été détecté: TrojWare.Win32.TrojanDropper.Dell.G...
Je suppose que je peux l'ignorer, c'est une fausse alerte. Avant d'accepter et de le mettre dans les exclusions, je pose la question, des fois qu'il s'agit d'autre chose. |
| | | Klaus
Nombre de messages : 12331 Age : 75 Localisation : Ile de France Date d'inscription : 29/12/2009
| Sujet: Re: Plugins dans Panoramic ? Lun 4 Nov 2013 - 17:45 | |
| J'ai bien une idée: On pourrait imaginer une fonction du type resultat% = PLUGIN(nom$,sortie$,p1,p2,p3,p4,...,p30) ou une commande du type PLUGIN nom$,sortie$,p1,p2,p3,p3,...,p30
p1...pn étant des paramètres en entrée uniquement (le 30 étant choisi arbitrairement, en tout cas plus de 10 serait souhaitable)
sortie$ étant une variable chaîne de caractères (et une seule) qui recevrait, si besoin est, une valeur chaîne de caractères retournée par le plugin.
nom$ serait le nom du plugin
Les paramètres en entrée pourraient être de tout type: entier, flottant ou chaîne de caractères. Ils seraient convertis tous en chaîne de caractères et concatenés en une seule chaîne de caractères délimitée par des sémicolons, comme ceci: PLUGIN "Test_Plugin",17,date$,n%-1,s$,table%(i%) avec la conversion des paramètres en entrée comme suit: "17";"04/11/2014",257","contenu de la variable s$","17" Ceci est une chaîne de caractères unique qui pourrait être passée au plugin par le paramètre correspondant des fonctions de plugin.
Ceci est juste une idée d'implémentation - on peut évidemment imaginer tout à fait autre chose. | |
| | | Klaus
Nombre de messages : 12331 Age : 75 Localisation : Ile de France Date d'inscription : 29/12/2009
| Sujet: Re: Plugins dans Panoramic ? Lun 4 Nov 2013 - 17:50 | |
| Tiens, c'est curieux, Cosmos70. Mes logiciels de détection reste muets: Avast! antivirus IOBitMalwareFighter Microsoft Security Essentials Outpost Security Suite opérant tous ensemble en temps réel. Tu peux effectivement ignorer cette alerte - elle vient du fait que le programme, via une DLL, génère du code et tente de l'exécuter, ce qui semble normal pour un script.
Ceci dit, un avertissement pour tous: le danger ne vient pas du programme, mes des scripts qu'on utilise ! C'est comme le Java Script dans un browser internet: dans un script, on peut tout faire, y compris des choses délicates... | |
| | | Klaus
Nombre de messages : 12331 Age : 75 Localisation : Ile de France Date d'inscription : 29/12/2009
| Sujet: Re: Plugins dans Panoramic ? Lun 4 Nov 2013 - 18:26 | |
| J'ai modifié rapidement ma simulation de plugin pour tenir compte de paramètres à passer au plugin. Dans mon cas, j'ai choisi de passer 3 paramètres qui pourront être saisis dans des zones EDIT, avant le lancer le plugin. Le plugin Other_Script a été modifié pour récupérer les paramètres et montrer comment on éclate la chaîne délimitée en paramètres individuels. Voici le programme principal, dont la fonction callback gère une nouvelle commande GetParams: - Code:
-
unit Unit1;
interface
uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, pdScriptAPI, // interface required to use pdScript via the DLL Dialogs, StdCtrls;
type TForm1 = class(TForm) Memo1: TMemo; Label1: TLabel; Button1: TButton; Label2: TLabel; cbPlugin: TComboBox; lbTrace: TListBox; Label3: TLabel; Label4: TLabel; Label5: TLabel; Label6: TLabel; ePar1: TEdit; ePar2: TEdit; ePar3: TEdit; procedure Button1Click(Sender: TObject); procedure cbPluginChange(Sender: TObject); procedure FormCreate(Sender: TObject);
private { Déclarations privées } public { Déclarations publiques } end;
var Form1: TForm1; container: string;
implementation
{$R *.dfm}
{ Plugins =======
Plugins are implemented by 2 collaborating routines. The interface apart is implemented within the main program, via a callback function with predefined yet extensible features. The real plugin is a Delphi like program written in Pascal Script language. The implementation is done via the pdScript software. pdScript means "Precision Delphi Script" and is provided by Precision software & consulting. The actual implementation uses the portable freeware version: Copyright (c) 2008-2012 Precision software & consulting. All rights reserved.
This callback function is the actual plugin implementation within the main program. Several plugins may be implemented throughout the same callback function.
The 4 parameters of this functions are used as follows: cCommand character string identifying a command to be executed cParams parameters for the command cBuffer buffer pointer into which a string result is to be returned cBuffSize buffer size
The callback function executes a specific action for each expected command string. In any case, the function returns an integer value, designed to be a success/failure/result value. A predefined normally unused result value should be assigned for unrecognized command codes, other normally unused values should be defined as standard error codes. The remaining result value range is freely available as specific command result values.
This demo version implements 4 plugin functions: GetCaption returns the main form caption to the plugin script SetCaption sets the main form caption to a string provided by the plugin script GetDate returns a character string containing the formatted current date to the plugin script Trace adds a string provided by the plugin script to the trace list box of the main program
The plugin script must use the following template:
***************************************************************************************** program Other_Script;
function plugin():integer; var param, buff: string; begin // sample call to get data from the main program if HostCallback('GetDate','',buff) then showmessage(buff);
// sample call to send data to the main program param := 'Other_Script'; if not HostCallback('Trace',param,buff) then showmessage('Trace returns BAD');
result := 23; // plugin specific numeric result
end;
begin exitcode := 7; end. *****************************************************************************************
} function MyPDScriptCallback(cCommand:PChar; cParams:PChar; cBuffer:PChar; cBufSize:Integer):Integer; stdcall; const cb_unknown = -1; cb_unexpected = -2; var MyText: string;
begin Result := cb_unknown;
// commands read data from the main program if AnsiSameText(cCommand,'GetCaption') then begin result := 0; MyText := Form1.Caption; if (cBuffer=nil) or (cBufSize<=0) then Result:=Length(MyText) else StrPLCopy(cBuffer,MyText,cBufSize); end; if AnsiSameText(cCommand,'GetDate') then begin result := 0; MyText := DateToStr(Date); if (cBuffer=nil) or (cBufSize<=0) then Result:=Length(MyText) else StrPLCopy(cBuffer,MyText,cBufSize); end; if AnsiSameText(cCommand,'GetParams') then begin result := 0; // just as a sample. In real situation, concatenate here all passed parameter values ! MyText := '"'+Form1.ePar1.Text+'","'+Form1.ePar2.Text+'","'+Form1.ePar3.Text+'"'; if (cBuffer=nil) or (cBufSize<=0) then Result:=Length(MyText) else StrPLCopy(cBuffer,MyText,cBufSize); end;
// commands modifying data in the main program if AnsiSameText(cCommand,'SetCaption') then begin result := 0; Form1.Caption:=cParams; end; if AnsiSameText(cCommand,'Trace') then begin result := 0; Form1.lbTrace.Items.Add(cParams); end; if AnsiSameText(cCommand,'Add_Plugin') then begin result := 0; if Form1.cbPlugin.Items.IndexOf(cParams)<0 then begin result := cb_unexpected; end else begin Form1.cbPlugin.Items.Add(cParams); // add new plugin to list Form1.cbPlugin.Items.SaveToFile(container); // and update the container file end; end; end;
{ Sample main program - not relevant for the pluin mecanism itself. This button clic procedure simulates the activation of a user written plugin. The ames of the available plugins are placed in the combo cbPlugin. This combo may be initally loaded by a configuration text file containing the names of all installed plugins. Thus, new plugins can be added ad runtime, without the need to restart the program. To achieve this, a simple command Add_Plugin implemented within the callback function does the trick. So, a plugin adding new plgins can easyly built. } procedure TForm1.Button1Click(Sender: TObject); var res: integer; sfunction, script, dfm, param: string; hnd: THandle; begin
// look if there is a plugin eslected if cbPlugin.Text='' then begin showmessage('No plugin selected.'); exit; end;
// load the pdScript DLL sfunction := 'plugin'; // the user supplied function in the script has to be calles "plugin" // pdScriptLibHandle := pdScriptLoad(pdScriptDllNameCL); // command line version pdScriptLibHandle := pdScriptLoad(pdScriptDllName); // VCL version if not pdScriptReady then begin showmessage('Error - not ready'); exit; end;
// compile the script and let it stay alive // (this implementation does not use a client window for the plugin) script := memo1.Text; // script source code from the memo filled by a click on the combo dfm := ''; // no window // the parameters say "stay alive" and give the callback function address param := '/pds{keep-alive=true;host-callback='+IntToStr(Integer(@MyPDScriptCallback))+'}'; // now, execute the script unline to compile ans syntax check it hnd := Inline_pdScript(script,dfm,param,false); if hnd=1 then begin showmessage('Compile error: '+inttostr(hnd)); pdScriptUnload; exit; end;
// execute the plugin function res := Execute_pdScriptFunction(hnd, sfunction); // call the plugin function showmessage('Result: '+inttostr(res)); pdScriptUnload; // unload pdScript end;
procedure TForm1.cbPluginChange(Sender: TObject); begin memo1.Lines.LoadFromFile(cbPlugin.Text+'.pas'); // load the memo with the selectec plugin's source end;
procedure TForm1.FormCreate(Sender: TObject); var name, path: string; inifile: TextFile; begin // try to localize the plugin container file (same folder as program) name := 'KlausApplication'; path := GetCurrentDir + '\'; container := path+name+'.plg'; if FileExists(container) then begin cbPlugin.Items.LoadFromFile(container) // load the combo from existing file end else begin AssignFile(inifile,container); // create new empty file if missing Rewrite(inifile); CloseFile(inifile); end;
end;
end. Et voici Other_Script.pas: - Code:
-
program Other_Script;
function plugin():integer; var param, buff: string; pars: TStringList; begin // sample call to get data from the main program if HostCallback('GetDate','',buff) then showmessage('Date: '+buff);
// recover here the application parameters as a delimited string if HostCallback('GetParams','',buff) then showmessage('Parameters: '+buff); pars := TStringList.Create; pars.Delimiter := ';'; pars.Sorted := false; pars.DelimitedText := buff; // here, we can work with the parameters. // pars.count is the number of actual parameters // pars.Strings[n] is the n-th parameter (n=0,1,...) pars.Clear; pars.Free; // sample call to send data to the main program param := 'Other_Script'; if not HostCallback('Trace',param,buff) then showmessage('Trace returns BAD'); result := 23; // plugin specific numeric result end;
begin exitcode := 7; end.
On voit que le passage de paramètres est aisé, quelque soit le nombre de paramètres. . Tout est mis à jour sur mon WebDan, dossier Plugins | |
| | | Invité Invité
| Sujet: Re: Plugins dans Panoramic ? Lun 4 Nov 2013 - 19:13 | |
| Merci. Mon antivirus est commodo, et j'ai mis la barre assez haute. Il ne laisse rien passé. Je vois que ça marche, mais j'ai pas très bien compris. Peut importe on verra plus tard. D'ici là, tu vas certainement en rajouter, ce sera plus compréhensible par la suite. Mais je crois que ton message s'adresse avant tout à Jack. J'ai trop à faire sur mon programme, et je n'y suis pas souvent, surtout que je modifie complètement mon approche.
@+ |
| | | Contenu sponsorisé
| Sujet: Re: Plugins dans Panoramic ? | |
| |
| | | | Plugins dans Panoramic ? | |
|
Sujets similaires | |
|
| Permission de ce forum: | Vous ne pouvez pas répondre aux sujets dans ce forum
| |
| |
| |