Toon posts:

[DELPHI] van EXE naar DLL OnEvent luistert niet meer

Pagina: 1
Acties:

Verwijderd

Topicstarter
Hier in het bedrijf waar ik werk hebben we apparatuur die over TCP/IP te benaderen en aan te sturen is. Commando's voor dit apparaat en reacties van het apparaat worden eerst op een apparaat specifieke wijze versleuteld en daarna over UDP verstuurd.

Een van mijn taken is het schrijven van kleine besturingstools voor deze apparaten. Vandaar dat ik ooit een .pas bestandje heb geschreven waarmee het mogelijk is om een procedure aan te roepen die vervolgens het commando versleuteld, verstuurd en vervolgens de ontvangen data terug geeft aan de host applicatie door een functie daarin aan te roepen. De functie in de host applicatie die de gedecodeerde data ontvangt wordt meegegeven in de parameters van de verzend procedure (callback). Deze methode werkte altijd erg goed en is in een tiental tooltjes van mij verwerkt.

Nu, echter, bestaat de behoefte om deze verzend en ontvangst procedure in een DLL te stoppen zodat deze gemakkelijker uitgeleverd kan worden aan klanten voor custom oplossingen. Dit leek mij geen probleem, aangezien ik de .pas ook op een soort gelijke manier gebruikte. Echter, op het moment dat het een DLL is, reageert de code niet meer op het OnUDPRead Event. Events die heb gedefinieerd voor timers worden wel gewoon aangeroepen, maar zodra er een UDP pakket binnen komt reageert de code daar niet op. De code verstuurd wel gewoon de data.

Alles is volledig form-loos. TCP/IP communicatie gebeurd via Indy9. Alle componenten worden met de hand gemaakt en uiteindelijke ge-free-ed.

Zie ik nou iets over het hoofd? In principe moet code die in een EXE werkt toch ook zo in een DLL moeten kunnen werken?

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 22-05 16:53
Als die messages worden verstuurd naar een window kan het goed zijn dat het nu niet meer werkt. Misschien ff een message only window aanmaken.

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


  • LordLarry
  • Registratie: Juli 2001
  • Niet online

LordLarry

Aut disce aut discede

Hoe maak je het component aan? Hoe verbint je het event er aan?

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


Verwijderd

Topicstarter
farlane schreef op 14 september 2004 @ 17:55:
Als die messages worden verstuurd naar een window kan het goed zijn dat het nu niet meer werkt. Misschien ff een message only window aanmaken.
Nee, er wordt niet naar een window verstuurd. Alles is volledig form-loos. Ik krijg ook geen foutmeldingen oid. De data wordt terug gestuurd door een functie aan te roepen in de host applicatie die als parameter is meegegeven aan de functie in de DLL (callback dus).

Als ik alle regels code, at runtime, stuk voor stuk doorloop kom ik dus niet in het OnUDPRead event. Dus met het terug geven van de data heeft het vermoedelijk niets te maken, want in dat gedeelte van de code kom ik niet eens at runtime.

Overigens geeft mijn packet sniffer wel aan dat er data binnen komt. En, zoals al eerder gezegd, als ik de functie gebruik uit een gewoon .pas bestand dan werkt het als een zonnetje.
LordLarry schreef op 14 september 2004 @ 19:08:
Hoe maak je het component aan? Hoe verbint je het event er aan?
Ok, ik zit nu niet meer op me werk, heb de code dus niet voor me, maar uit me hoofd was het het volgende:

Delphi:
1
2
3
4
UDPServer := TIdUDPServer.Create(Application);
...
...
UDPServer.OnUDPRead := TEventHandlers.ReadUDPData;
TEventHandlers is dus een klasse waarin ik alle eventhandlers ondergebracht heb.

Ik maak overigens gebruik van een server component, omdat de apparaten waar ik mee moet communiceren gelockt zijn op één poort voor zowel verzenden als ontvangen, een Client kan daar niet goed tegen, omdat die data terug verwacht op de door hem dynamisch geopende uitgaande poort (off topic, mocht iemand het zich afvragen).

  • Tomatoman
  • Registratie: November 2000
  • Laatst online: 23:27

Tomatoman

Fulltime prutser

• Probeer eens wat er gebeurt als je de application handle in de DLL een geldige waarde (anders dan nul) geeft.
• Probeer ook eens wat er gebeurt als je de UDP-component als parent een onzichtbare TForm geeft.
Ik gok dan een van beide suggesties of misschien de combinatie ervan tot resultaat zal leiden.

Een goede grap mag vrienden kosten.


Verwijderd

Topicstarter
tomatoman schreef op 14 september 2004 @ 20:40:
• Probeer eens wat er gebeurt als je de application handle in de DLL een geldige waarde (anders dan nul) geeft.
• Probeer ook eens wat er gebeurt als je de UDP-component als parent een onzichtbare TForm geeft.
Ik gok dan een van beide suggesties of misschien de combinatie ervan tot resultaat zal leiden.
Ok, de tweede optie zal wel gaan lukken, de eerste moet ik geloof ik nog even mee op weg geholpen worden.

Ik vond het volgende in de Delphi help:
code:
1
2
3
4
5
When writing a DLL that uses VCL forms, assign the window
handle of the host EXE's main window to the DLL's 
Application.HandleApplication->Handle property. This makes the 
DLL's form part of the host application. Never assign to the Handle
property in an EXE.

Is dit ongeveer wat je bedoelt? Dus bij iedere aanroep van de DLL functie zal als parameter de ApplicationHandle mee gestuurd moeten worden.
Of bedoel je dat ik de DLL een eigen Handle geef? Aan wat voor waarde zou ik dan moeten denken?

  • Tomatoman
  • Registratie: November 2000
  • Laatst online: 23:27

Tomatoman

Fulltime prutser

De application handle heeft in een DLL standaard de waarde 0. Logisch, want het is geen applicatie. Sommige Win32 functies (misschien wel een paar die de UDP-component gebruikt) vereisen de window handle van het proces dat de functieaanroep doet (dus de handle van de executable). Als je eenmalig de application handle een geldige waarde geeft, zou daarna alles goed moeten gaan.

Eis gewoon dat eerst een functie wordt aangeroepen waarmee de application handle (in Delphi Application.Handle van het type HWnd) van de executable aan de DLL wordt doorgegeven. In de DLL doe je dan
Delphi:
1
Application.Handle := DeNieuweHandle;
en daarna kan de rest van de DLL als vanouds worden geïnitialiseerd. Als er al een initialisatiefunctie is die de applicatie dient aan te roepen, is de extra functie niet eens nodig en voeg je gewoon de handle als extra parameter toe.

[ Voor 9% gewijzigd door Tomatoman op 15-09-2004 13:25 ]

Een goede grap mag vrienden kosten.


  • LordLarry
  • Registratie: Juli 2001
  • Niet online

LordLarry

Aut disce aut discede

En je bent je er van bewust dat de TEventHandlers.ReadUDPData code alleen in de DLL aangeroepen wordt? Vanuit daar zal je het weer naar de EXE moeten communiceren als je dat wilt.

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


Verwijderd

Topicstarter
tomatoman schreef op 15 september 2004 @ 13:23:
Eis gewoon dat eerst een functie wordt aangeroepen waarmee de application handle (in Delphi Application.Handle van het type HWnd) van de executable aan de DLL wordt doorgegeven. In de DLL doe je dan
Delphi:
1
Application.Handle := DeNieuweHandle;
en daarna kan de rest van de DLL als vanouds worden geïnitialiseerd. Als er al een initialisatiefunctie is die de applicatie dient aan te roepen, is de extra functie niet eens nodig en voeg je gewoon de handle als extra parameter toe.
Heel erg bedankt voor de suggestie, het klinkt ook erg aannemelijk na nog enige research, maar helaas... Het mag niet baten. Ik heb een speciale Initialize procedure geschreven die Application.Handle (in de DLL) dezelfde waarde geeft als de Handle van het aanroepende form (of wat er dan ook wordt meegegeven aan de procedure als variabele). Maar me OnUDPRead event wordt er niet alerter van :'(

Offtopic:
Ik heb ook maar vast een afsluitende procedure geschreven die alle gemaakte objecten in de DLL sluit als die aangeroepen wordt. Dit moet gebeuren als de host applicatie afgesloten wordt (kan dat ook automatisch? Dus zonder dat de host applicatie deze functie aanroept? Bestaat erzoiets als een OnApplicationClose event?)

Verwijderd

Topicstarter
LordLarry schreef op 15 september 2004 @ 14:02:
En je bent je er van bewust dat de TEventHandlers.ReadUDPData code alleen in de DLL aangeroepen wordt? Vanuit daar zal je het weer naar de EXE moeten communiceren als je dat wilt.
Ja, dat begrijp ik, dat doe ik dan ook doormiddel van een callback procedure. Zodra de TEventHandlers.ReadUDPData procedure aangeroepen wordt en de data behandelt heeft roept deze procedure een procedure aan in de host applicatie om de data terug te geven.

Maar, als ik debug zie ik dat er nooit naar het OnUDPRead event gesprongen wordt in de DLL.

Het enige moment waarop de OnUDPRead event wordt aangesproken is als ik de IdUDPServer.Active false maak of IdUDPServer.Free aanroep. Dat vind ik dan overigens wel weer een beetje apart.

[ Voor 13% gewijzigd door Verwijderd op 15-09-2004 14:16 ]


  • farlane
  • Registratie: Maart 2000
  • Laatst online: 22-05 16:53
NIet om het een of ander maar je laat em wel receiven neem ik aan? ;)

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


Verwijderd

Topicstarter
farlane schreef op 15 september 2004 @ 15:03:
NIet om het een of ander maar je laat em wel receiven neem ik aan? ;)
Ehrm, euh, kan je dat uitzetten dan?

Ik heb de volgende properties:
code:
1
2
3
4
5
6
7
8
Active := TRUE
Bindings := [leeg]
BroadcastEnabled := [dynamisch]
BufferSize := 8192
DefaultPort := 44527
Name:= UDPServer
Tag := 0
ThreadedEvent := FALSE


En de volgende events:
code:
1
2
OnStatus := [leeg]
OnUDPRead := EventHandler.IdUDPServerUDPRead

Verwijderd

Topicstarter
Godgloeiende... Ben eruit...

ThreadedEvent moest op TRUE.

En ook hier gaat mijn lijfspreuk helemaal op: 'tis zo simpel :)


Iedereen heel erg bedankt!!!

Verwijderd

Topicstarter
Overigens, mijn offtopic vraag staat nog wel open:
Ik heb ook maar vast een afsluitende procedure geschreven die alle gemaakte objecten in de DLL sluit als die aangeroepen wordt. Dit moet gebeuren als de host applicatie afgesloten wordt. Kan dat ook automatisch? Dus zonder dat de host applicatie deze functie aanroept? Bestaat erzoiets als een OnApplicationClose event?

  • LordLarry
  • Registratie: Juli 2001
  • Niet online

LordLarry

Aut disce aut discede

Je kan daarvoor de finalization sectie gebruiken van een Unit. Of de DllEntryPoint procedure.

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


  • Tomatoman
  • Registratie: November 2000
  • Laatst online: 23:27

Tomatoman

Fulltime prutser

Onder het keyword 'initialization (libraries)' vind je in de helpfiles uitleg over initialisatie/finalisatie van DLL's. Het volgende stukje voorbeeldcode staat erbij:

Delphi:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
library Test;
var
  SaveDllProc: Pointer;
procedure LibExit(Reason: Integer);
begin
  if Reason = DLL_PROCESS_DETACH then
  begin
  ...  // library exit code
  end;
  SaveDllProc(Reason);  // call saved entry point procedure
end;
begin
  ...  // library initialization code
  SaveDllProc := DllProc;  // save exit procedure chain
  DllProc := @LibExit;  // install LibExit exit procedure
end.

Een goede grap mag vrienden kosten.


  • farlane
  • Registratie: Maart 2000
  • Laatst online: 22-05 16:53
Verwijderd schreef op 15 september 2004 @ 15:15:
Ehrm, euh, kan je dat uitzetten dan?
Ik heb geen idee eigenlijk. Het was maar een hersenspinsel van me omdat je andere events wel binnenkreeg.

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.

Pagina: 1