[delphi] plugin systeem met feedback naar host

Pagina: 1
Acties:
  • 218 views sinds 30-01-2008
  • Reageer

  • bgever
  • Registratie: April 2002
  • Laatst online: 28-05-2021
Ik wil een plugin systeem maken. En leuk programmatje waarbij de host een MySQL verbinding verzorgt. Nu moeten alleen de plugins ook met deze verbinding kunnen communiceren.

Ik heb het voor elkaar gekregen om een plugin systeem te maken met DLL's, door het comonent in de Jedi-VCL te gebruiken, en ook nog op een andere manier door een ander componentje. Hierbij zit alleen een probleem. Het lukt me wel om een command naar een plugin te sturen, en dat deze plugin wat doet, een formpje laat zien of zo, maar het is me niet gelukt om feedback terug te geven. Dat de plugin bijv. een functie uit de Hostapp aanroept en daardoor kan communiceren.

Wat wil ik eigenlijk bereiken? Dat ik bijvoorbeeld zo een functie kan aanroepen vanuit een plugin:
getDataSource(SQLQuery: string; ReturnForm: TForm): TDataSource;
Ongeveer zo wil ik dan de mainapp functie aanroepen.
Hostapp.mainform.getDataSource('SELECT * FROM bla', Form2);

Is dit mogelijk, of niet? En hoe zou ik dit dan ongeveer moeten aanpakken? Gaat dit beter als ik .bpl's als plugin gebruik?

  • Tomatoman
  • Registratie: November 2000
  • Laatst online: 01:25

Tomatoman

Fulltime prutser

Da's heel eenvoudig te doen door van de applicatie een COM server te maken en de plugins uit te voeren als COM clients. Aangezien je een databaseverbinding gebruikt, kun je ook nog overwegen om de server uit te voeren met een remote data module (die je dan alleen lokaal gebruikt), zodat je de database direct vanuit de plugin kunt benaderen via de IAppServer interface.

Een goede grap mag vrienden kosten.


  • bgever
  • Registratie: April 2002
  • Laatst online: 28-05-2021
Grmbl, wat een zooi om in te zoeken. :( Weet je toevallig een goede COM tutorial, of heb je een simpel voorbeeld?

  • alienfruit
  • Registratie: Maart 2003
  • Laatst online: 15:12

alienfruit

the alien you never expected

Waarom gebruik je niet WM_COPYDATA message van windows hiervoor, of kan je dit niet sturen naar een dll :S ? (volgens mij wel)

  • LordLarry
  • Registratie: Juli 2001
  • Niet online

LordLarry

Aut disce aut discede

Kan ook gewoon zonder COM. De host app roept een functie aan van de DLL en geeft als parameter bijvoorbeeld het MainForm of meteen de DataSource mee. De DLL onthoudt deze referentie en gebruikt m in het vervolg.

Strings kunnen niet zomaar worden doorgegeven aan DLL's. Daarvoor zal je in beide projecten de unit Sharemem als eerste moeten includen (in de dpr!) en voortaan een extra DLL moeten meeleveren. Als je objecten overgeeft en deze bevatten strings zal het ook moeten gebeuren. BPL's hebben deze beperking niet.

Je kan ook het Application object benaderen en dan aan het MainForm komen door gewoon de Forms unit te usen. Het probleem is dat de DLL en de App beide een andere instantie hebben van Application en je deze dus even gelijk moet zetten als de DLL geladen wordt. Vooral als je met forms gaat werken in je DLL is dit nodig. Wederom hebben BPL's deze beperking niet.

We adore chaos because we like to restore order - M.C. Escher


Verwijderd

Je kunt ook met shared memory files gaan werken, even googlen en je weet het..

Een paar voorbeelden van com kun je hier vinden:

http://www.marcocantu.com/code/md6htm/19.htm

Dit zijn de stukken broncode behorende bij het hoofdstuk 'Com programming' uit 'Mastering Delphi 6' van Marco Cantu, sowieso een aanrader als je een goed boek voor Delphi nodig hebt..

  • bgever
  • Registratie: April 2002
  • Laatst online: 28-05-2021
LordLarry schreef op 01 May 2003 @ 09:25:
Je kan ook het Application object benaderen en dan aan het MainForm komen door gewoon de Forms unit te usen. Het probleem is dat de DLL en de App beide een andere instantie hebben van Application en je deze dus even gelijk moet zetten als de DLL geladen wordt. Vooral als je met forms gaat werken in je DLL is dit nodig. Wederom hebben BPL's deze beperking niet.
Ik kan al aan het MainForm object komen, omdat deze in het JvPlugin systeem wordt doorgegeven.
Delphi:
1
HostApplication.MainForm.caption = 'Nieuwe caption';

Dit werkt dus wel, maar als ik een functie die ik in de MainForm heb staan wil aanroepen gaat dit niet, omdat Delphi die niet herkent vanuit de plugin.

Wat ik btw een nadeel vind aan COM, is dat je de Host Server moet registreren in het registry.

@hezik: thnx, ik was sowieso op zoek naar een goed boek, omdat ik aan allemaal verschillende tuto's niets heb.

[ Voor 8% gewijzigd door bgever op 01-05-2003 13:52 ]


Verwijderd

Ik denk dat je dan ook verkeerde zaken aan het doen bent. Je mainform hoort functies uit de DLL te gebruiken, niet andersom.

Wil je dat toch, zonder gebruik te maken van com.. dan kom je al snel uit op shared memory files. Voor een voorbeeld, kijk even naar de laatste post in dit topic:

http://groups.google.com/...rojht1ht%404ax.com&rnum=2

  • LordLarry
  • Registratie: Juli 2001
  • Niet online

LordLarry

Aut disce aut discede

oikoyama schreef op 01 mei 2003 @ 13:50:
[...]

Ik kan al aan het MainForm object komen, omdat deze in het JvPlugin systeem wordt doorgegeven.
Delphi:
1
HostApplication.MainForm.caption = 'Nieuwe caption';

Dit werkt dus wel, maar als ik een functie die ik in de MainForm heb staan wil aanroepen gaat dit niet, omdat Delphi die niet herkent vanuit de plugin.
Ok, das netjes van dat JvPlugin. HostApplication.MainForm is vast van het type TForm, na een typecast naar het juiste type werkt het allemaal wel hoor. Maar ik ben het met de rest eens dat het niet zo netjes is vanuit je plugin weer je App aan te roepen. Beter is de gegevens die je nodig hebt door te geven van je App naar de DLL.

We adore chaos because we like to restore order - M.C. Escher


  • LordLarry
  • Registratie: Juli 2001
  • Niet online

LordLarry

Aut disce aut discede

Verwijderd schreef op 01 mei 2003 @ 13:54:
Wil je dat toch, zonder gebruik te maken van com.. dan kom je al snel uit op shared memory files. Voor een voorbeeld, kijk even naar de laatste post in dit topic:
Onzin en overkill IMHO. De DLL wordt gewoon netjes in de process space van de App geladen en het is dus gewoon veilig om pointers door te geven.

We adore chaos because we like to restore order - M.C. Escher


  • Creepy
  • Registratie: Juni 2001
  • Laatst online: 16:57

Creepy

Tactical Espionage Splatterer

Verwijderd schreef op 01 May 2003 @ 13:54:
Ik denk dat je dan ook verkeerde zaken aan het doen bent. Je mainform hoort functies uit de DLL te gebruiken, niet andersom.

Wil je dat toch, zonder gebruik te maken van com.. dan kom je al snel uit op shared memory files. Voor een voorbeeld, kijk even naar de laatste post in dit topic:

http://groups.google.com/...rojht1ht%404ax.com&rnum=2
Nog nooit gehoord van callback functies, pointers of messages?

"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney


Verwijderd

Onzin en overkill IMHO. De DLL wordt gewoon netjes in de process space van de App geladen en het is dus gewoon veilig om pointers door te geven.
Agreed, echter werkt dat in Delphi niet zo best, zoals topicstarter al ondervind. Borland zelf raad het in dit soort situaties aan om van dergelijke constructies gebruik te maken. Het is imo een elegante oplossing.
Nog nooit gehoord van callback functies, pointers of messages?
Iets minder sarcastisch mag wel. Ja natuurlijk heb ik daar wel van gehoord, echter met een plugin systeem zijn die zelden nodig. In 99% van de gevallen waarbij mensen in zo'n situatie met callback functies gaan werken, hebben ze de functionaliteit op de verkeerde plek zitten, waardoor er alsnog een spagettistructuur ontstaat en er geen sprake is van een eenduidige plugin-structuur.

Messages is een ander verhaal, echter dat valt buiten mijn opmerking, aangezien dat geen directe communicatie is, en imo ook van andere orde.

En ja, dit zijn persoonlijke meningen, geen feiten. Daarvan ben ik me bewust, evenals het feit dat mensen het daarmee oneens kunnen zijn. Ik persoonlijk vind het not-done om dan gelijk aan het kennisniveau van iemand te gaan twijfelen.

Ik stel het waarsch. wat harder dan nodig, maar in zo'n bui..

[ Voor 73% gewijzigd door Verwijderd op 01-05-2003 17:23 ]


  • Creepy
  • Registratie: Juni 2001
  • Laatst online: 16:57

Creepy

Tactical Espionage Splatterer

Verwijderd schreef op 01 mei 2003 @ 17:18:
[...]
Iets minder sarcastisch mag wel. Ja natuurlijk heb ik daar wel van gehoord, echter met een plugin systeem zijn die zelden nodig. In 99% van de gevallen waarbij mensen in zo'n situatie met callback functies gaan werken, hebben ze de functionaliteit op de verkeerde plek zitten, waardoor er alsnog een spagettistructuur ontstaat en er geen sprake is van een eenduidige plugin-structuur.


Ik stel het waarsch. wat harder dan nodig, maar in zo'n bui..
* Creepy zal volgende keer de smiley niet vergeten :Y)

"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney


  • bgever
  • Registratie: April 2002
  • Laatst online: 28-05-2021
Goed gesproken, ik kom er nu helemaal niet meer uit.

Wat is de beste manier om een plugin-systeem te maken (DLL/BPL), waarbij in de HostApp een MySQL connectie is, waarmee de plugins kunnen communiceren? Als het kan, moeten plugins ook kunnen communiceren met elkaar...

Verwijderd

oikoyama schreef op 02 May 2003 @ 01:01:
[...]

Goed gesproken, ik kom er nu helemaal niet meer uit.

Wat is de beste manier om een plugin-systeem te maken (DLL/BPL), waarbij in de HostApp een MySQL connectie is, waarmee de plugins kunnen communiceren? Als het kan, moeten plugins ook kunnen communiceren met elkaar...
Een mogelijkheid die nog niet genoemd is...

Je kan net als bij DLL's functies in de HostApp 'exporteren'. Let wel dat deze functies alleen door je eigen applicatie gebruikt kunnen worden. Aangezien de plug-in draait in de address space van de HostApp hoeft dit dus geen probleem op te leveren.

  • LordLarry
  • Registratie: Juli 2001
  • Niet online

LordLarry

Aut disce aut discede

Verwijderd schreef op 01 May 2003 @ 17:18:
Agreed, echter werkt dat in Delphi niet zo best, zoals topicstarter al ondervind. Borland zelf raad het in dit soort situaties aan om van dergelijke constructies gebruik te maken. Het is imo een elegante oplossing.
Is dat zo? Wat werkt er dan niet zo best aan DLL's in Delphi, als ik vragen mag?

We adore chaos because we like to restore order - M.C. Escher


  • LordLarry
  • Registratie: Juli 2001
  • Niet online

LordLarry

Aut disce aut discede

oikoyama schreef op 02 mei 2003 @ 01:01:
[...]

Goed gesproken, ik kom er nu helemaal niet meer uit.

Wat is de beste manier om een plugin-systeem te maken (DLL/BPL), waarbij in de HostApp een MySQL connectie is, waarmee de plugins kunnen communiceren? Als het kan, moeten plugins ook kunnen communiceren met elkaar...
Dat hangt af van meerdere factoren. Inprincipe kan alles, alleen sommige wat makkelijker/mooier als andere en soms vergt het wat meer kennis. Vergeet ook niet te bedenken of je misschien platform onafhankelijk wil worden of de plugins in een andere programmeertaal wil schrijven.

Een gewone DLL is makkelijk te converteren naar linux, terwijl dit bijna onmogelijk is voor COM. Ook ben ik bang dat Memory Mapped Files een te specifieke windows oplossing zijn. Bovendien voegen de memory mapped files IMHO niets toe aan de functionaliteit van de DLLs. Een BPL is ook een DLL, maar zorgt er voor dat enkele zaken waar een DLL last van heeft opgelost zijn. BPL's zijn een specifiek Borland iets en het zal dan ook niet mogelijk zijn om het met een andere taal als pascal of c++ te maken. Als je een beetje oppast met DLL's kan het wel en ook COM is daar uitermate geschikt voor.

Het maken van een plugin framework is niet zo heel erg ingewikkeld, maar aangezien jij het JVCL plugin framework gebruikt ben je beperkt door wat daarmee mogelijk is en is deze discussie niet eens erg relevant voor je originele vraag.

In jouw huidige situatie zou ik bij het initialiseren van de plugin via een functie aanroep van de App op de DLL bepaalde context objecten doorgeven. Zoals bijvoorbeeld een object voor de database toegang en een object om bijvoorbeeld de andere plugins te kunnen benaderen. Deze objecten zijn geimplementeerd in de App en alle communicatie van de DLL's naar de App gaan via deze objecten.

We adore chaos because we like to restore order - M.C. Escher


  • bgever
  • Registratie: April 2002
  • Laatst online: 28-05-2021
LordLarry schreef op 02 May 2003 @ 09:31:
In jouw huidige situatie zou ik bij het initialiseren van de plugin via een functie aanroep van de App op de DLL bepaalde context objecten doorgeven. Zoals bijvoorbeeld een object voor de database toegang en een object om bijvoorbeeld de andere plugins te kunnen benaderen. Deze objecten zijn geimplementeerd in de App en alle communicatie van de DLL's naar de App gaan via deze objecten.
Dit zal ik zeker onthouden. Maar wat ik eerst maar eens doe, is mijn Basic Delphi ervaringen maar eens flink uitbreiden. Blijkbaar heb ik nog niet alles onder de knie en het OO mag ook wel wat meer aand8 krijgen.
Zonder een degelijke basis zal ik waarschijnlijk niet echt verder kunnen, en ben dus van plan om maar eerst eens de tuto 'Teach Yourself Borland Delphi 4 in 21 Days' door te nemen. Blijkt deze onvoldoende te zijn, kijk ik wel of het boek 'Mastering Delphi 7 UK' in het butget zit. (is dat boek btw een goede keus, of is er een ander boek dat een betere/duidelijkere manier van uitleggen heeft?)

Wat misschien nog aardig is om te weten: De app die ik wilde bouwen, is een soort administrator voor internet. De bedoeling is dus dat je een MySQL database ermee kunt beheren. Aangezien ik deze modulair wilde maken, zodat je de app makkelijk kunt uitbreiden in functionaliteit, had ik een plugin systeem in gedachten. De manier waarop boeit mij niet, als het maar modulair en simpel werkt. De 'plugins' hoeven alleen voor het Windows platform beschikbaar te zijn, en zelfs alleen maar in één taal (Delphi7) en door één persoon (jaja, ikke :P) gemaakt te worden. Eigenlijk is het dus niet echt een plugin systeem te noemen, modulair systeem komt al beter in de richting.

Maar ik zal eerst eens een goede tuto leren, en daarna nog eventueel als extra daarop een boek doornemen, en dan zal ik het allemaal wel wat beter snappen :). Vooral omdat in die boeken/tuto's meestal ook COM aan de orde komt, en dan weet ik dat ook gelijk. Kan ik zelfs de voordelen/nadelen ervan overwegen.

Nou goed, als je nog een goede oplossing weet, laat het me dan weten, en anders bedankt voor de hulp. ;)

Verwijderd

Na ff wat knip en plakwerk ff snel een ruwe opzet, gebruik makend van interfaces.
Eerst definieer je een interface (ModuleIntf), deze is voor alle modules gelijk. Vervolgens
per module een eigen implementatie (ModuleImpl, of ModuleXxxImpl, etc).
Deze modules kunnen dan eenvoudig geladen worden. Dmv van de interface kun je
allerlei functies etc definieren.

Je kunt nu allerlei packages maken, BPL's. Hierdoor kun je alle forms, units, etc aanroepen en gebruiken als zijnde je 'eigen' forms, etc. Maar mooiste natuurlijk via de interface. Database connecties worden automatisch overgenomen (bijv module Data.bpl) als een module geladen wordt (moet wel Data.dcp gebruiken, in de requires list van de package). Wij gebruiken het hier op werk ook, en werkt "monster"! 8) _/-\o_

Oh ja, werkt ook met Kylix / Linux! :P :*)

code:
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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
=================================================================
unit ModuleIntf;

interface

type
  IModInterface = interface(IInterface)
    function CreateClientForm: TForm
  end;

  TGetModInterface = function : IModInterface;

const
  sGetProcName = 'GetModInterfaceProc';

implementation

end.

=================================================================
unit ModuleImpl;

interface
implementation

uses
  ModuleIntf, Form1;

type
  TModInterface = class(TInterfacedObject, IModInterface)
  private
    function CreateClientForm: TForm
  end;

function CreateInterface: IModInterface;
begin
  result := TModInterface.Create;
end;

exports
  CreateInterface name sGetProcName;

{ TModInterface }

function TModInterface.CreateClientForm: TForm;
begin
  result := TForm1.create(nil);
end;

end.
=================================================================
procedure TfrmMain.LoadClientModule;
var
  GetProc: TGetModInterface;
  tmpPackage : HMODULE;
  modname, packname : string;

begin
  packname := 'test';
  packname := ExtractFilePath(Application.ExeName) + packname;
  tmpPackage := LoadPackage(packname);

  assert(tmpPackage <> 0)
  @GetProc := GetprocAddress(tmpPackage, sGetprocName);
  assert(assigned(GetProc));

  fModInt := GetProc;

  try
    ClientForm := fModInt.CreateClientForm;
  except
    ClientForm := nil;
    raise;
  end;

  hPackage := tmpPackage;

end;

Verwijderd

Zonder een degelijke basis zal ik waarschijnlijk niet echt verder kunnen, en ben dus van plan om maar eerst eens de tuto 'Teach Yourself Borland Delphi 4 in 21 Days' door te nemen.
Gooi dat boek alstjeblieft weg. Daar leer je alleen van hoe de IDE werkt, en hoe je _niet_ moet programmeren.
Blijkt deze onvoldoende te zijn, kijk ik wel of het boek 'Mastering Delphi 7 UK' in het butget zit. (is dat boek btw een goede keus, of is er een ander boek dat een betere/duidelijkere manier van uitleggen heeft?)
Dat is zo ongeveer het beste Delphi boek wat je krijgen kunt. Let wel: in zo'n boek worden niet echt de principes van OO behandeld, eerder hoe je deze moet toepassen in Delphi. Je zou dus eigenlijk moeten beginnen met een goed boek over 'applicatieontwikkeling op een OO manier'.

Je hebt wel een leuk 'opstap project' gekozen, valt veel lol aan te beleven en is nog leerzaam ook.

//edit
mijn tip: vergeet DLLs nog even. Bouw gewoon eerst een applicatie die doet wat je wilt. Functies onderbrengen in DLL's kan dan later altijd nog.

[ Voor 11% gewijzigd door Verwijderd op 02-05-2003 13:21 ]

Pagina: 1