Entwickler-Ecke

Sonstiges (Delphi) - Dll mit Komponenten wie idHTTP


JayEff - Sa 23.04.05 18:21
Titel: Dll mit Komponenten wie idHTTP
Tach Leute. Nachdem meine andere frage bezüglich dlls nun geklärt ist, möchte ich versuchen, größere prozeduren in die dll auszulagern. Wie zum Beispiel diese:

Delphi-Quelltext
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:
Procedure TForm1.getChat;
Var
    s: TStringlist;
    Messages: TIniFile;
    mes, abs, seens: String;
Label
    nochmal;
Begin
    nochmal:
    If length(Form3.Edit1.text) > 0 Then
    Begin
        s := TStringlist.Create;
        s.CommaText := IdHTTP1.Get('http://www.jayy.de/update/messages.txt');
        s.savetofile('C:\tempMessages.ini');
        s.text := '';
        Messages := TIniFile.Create('C:\tempMessages.ini');
        If Messages.ReadBool(Form3.Edit1.text, 'x', false) Then
        Begin
            mes := StringReplace(Messages.ReadString(Form3.Edit1.text, 'message'''), '-'' ', [rfReplaceAll]);
            abs := Messages.ReadString(Form3.Edit1.text, 'abs''?');
            Messages.EraseSection(Form3.Edit1.text);
            JaysMessage.zeigs('Nachricht erhalten!', abs + ' schrieb:' + #10#13 + mes); //Wundert euch nicht da drüber, ist nur ne art messagebox mit 3 userdefined buttons und einem an und ausschaltbaren editfeld...
            s.LoadFromFile('C:\tempMessages.ini');
            Form3.IdFTP1.Put(TSTringStream.Create(s.text), 'messages.txt');
        End;
        If Messages.ReadBool(' @all ''x', false) And (pos(Form3.Edit1.text, Messages.ReadString(' @all ''seens''')) <= 0Then
        Begin
            mes := StringReplace(Messages.ReadString(Form3.Edit1.text, 'message'''), '-'' ', [rfReplaceAll]);
            abs := Messages.ReadString(Form3.Edit1.text, 'abs''?');
            seens := Messages.ReadString(' @all ''seen''');
            Messages.WriteString(' @all ''seen', Form3.Edit1.text + ',' + seens);
            JaysMessage.zeigs('Message an alle!', abs + ' schrieb:' + #10#13 + mes);
            s.LoadFromFile('C:\tempMessages.ini');
            Form3.IdFTP1.Put(TSTringStream.Create(s.text), 'messages.txt');
        End;
        Messages.Free;
        If (pos(Form3.Edit1.text, s.text) > 0Then
            Goto nochmal;
        deletefile('C:\tempMessages.ini');
    End;
End;

Seht ihr das problem? ich will nich auf jeder Form eine idHTTP und eine idFTP haben. ich würde mir diese Units sparen: IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient, IdHTTP! Weis nicht, wiviel das ausmacht. aber bestimmt genug... ^^

(Es geht hier übrigens ums vereinfachte und vom Volumen her kleinere Updaten)

Wie kann ich nun auf die Funktionen zugreifen, die runter- bzw hochladen können, gegebenenfalls auch mit einem Form mit diesen Komponenten in der dll? (Versuche endeten in einer Zugriffsverletzung)

Schange döhn schonmal, euer treuuuuuuuuues Mitglied Jay.. (PS: ja ich weis, meine u taste ist kapuuuuuuuuut ;) )


JayEff - Mo 14.08.06 21:09

Richtlinien hat folgendes geschrieben:
4.6 Schiebeposting
Schiebeposting (ein Posting um sein eigenes Topic für unsere Leser wieder als ungelesen zu markieren) sind nach 24 Stunden erlaubt. Es gibt keine Begrenzung von Schiebepostings, sofern ihr Abstand 24 Stunden beträgt.

:!:
Ich mag den Paragraph... However: Das Problem besteht weiter. Kann ich CLS-Komponenten in einer DLL verwenden? Hab schon vieles versucht, wie x:TidHTTP und x:=TidHTTP.Create(lool.foo.? nil!); Aber meistens endete es in Acces Violations.


JayEff - Di 15.08.06 22:50

Hmm.. scheint nicht, als ob es eine Lösung für dieses Problem gäbe. Vermutlich muss man sich diese Proceduren selbst schreiben oder so...


JayEff - Di 15.08.06 23:02

Narses hat mir eine nicht für Skriptkiddies geeignete PN geschrieben ;) Ich hab mal eine kleinigkeit rausgenommen ... :
Er hat gemeint, dass DLLs über keinen MessageLoop verfügen.
Aaaha. verstehe. Ich kann die Komponente desshalb nicht benutzen, weil z.B. Ereignisse für sie nicht verarbeitet werden könnten, verstehe ich das richtig?
Könnte ich nicht einfach eine Form in die DLL klatschen und diese als Parent für die TidFTP nehmen? Dann müsste ich immer die Form auf invisible stellen und schon könnte ich die Komponente ohne Einschränkungen benutzen, oder?
Dann müsste mir einer kurz erklären, wie ich eine Form in die DLL packe :oops:
PS: Updater-Anwendung hab ich ja, aber das veringert doch die größe der Anwendung nicht, oder? :shock: Also eine Anwendung, die das Update runterlädt und ausführt.


Narses - Mi 16.08.06 00:06

Moin!

Es geht nicht um das TForm, sondern um das TApplication-Objekt. ;)

Weiterhin: Ahrg! Das verbotene Wort label und die goto-Sünde... ;)

user profile iconJayEff hat folgendes geschrieben:
ich will nich auf jeder Form eine idHTTP und eine idFTP haben. ich würde mir diese Units sparen:...

Der Linker bindet doch nicht mehrfach die Units in die Anwendung ein, so schlau ist der schon. ;) Im Gegenteil, wenn du den DLL-Ansatz weiter verfolgst, dann handelst du dir tatsächlich diese Units in jeder DLL ein.

Fazit: Diese Teile in eine DLL zu packen ist eher nicht so schlau. Deshalb: entweder auf Packages ausweichen oder in der Hauptapplikation lassen und parametrisiert verwenden.

cu
Narses


JayEff - Mi 16.08.06 00:11

Hm..Den Teil hab ich nich kapiert:
"Der Linker bindet doch nicht mehrfach die Units in die Anwendung ein, so schlau ist der schon. Im Gegenteil, wenn du den DLL-Ansatz weiter verfolgst, dann handelst du dir tatsächlich diese Units in jeder DLL ein."
und was du mit Package meinst (.dpk? :shock: ) bzw mit "parametrisiert verwenden" auch nicht ... ^^
das lable und goto .. nun ja.. recht hast du ^^ Ich benutz es nur, wenn ich keine andere Möglichkeit finde. Warum is das eigentlich so verschrien um etwas OT zu betreiben ... ?


Narses - Mi 16.08.06 00:24

Moin!

user profile iconJayEff hat folgendes geschrieben:
Hm..Den Teil hab ich nich kapiert:
"Der Linker bindet doch nicht mehrfach die Units in die Anwendung ein, so schlau ist der schon.

Wenn du in mehreren Formularen deiner Anwendung die gleichen Units einbindest, dann wird trotzdem in der Anwendung nur einmal der Code der Unit enthalten sein.

user profile iconJayEff hat folgendes geschrieben:
Im Gegenteil, wenn du den DLL-Ansatz weiter verfolgst, dann handelst du dir tatsächlich diese Units in jeder DLL ein."

Wenn du dagegen ein unabhängiges Modul machen willst, dann muss der Linker den Code auch in jedem Modul unterbringen.

user profile iconJayEff hat folgendes geschrieben:
und was du mit Package meinst (.dpk? :shock: )

Ich meine .bpl-Dateien, einfach mal in der DOH nachlesen.

user profile iconJayEff hat folgendes geschrieben:
bzw mit "parametrisiert verwenden" auch nicht ...

Gestalte die Nutzung der Indies in der Applikation so, dass eine DLL auch darauf zugreifen kann, wenn du denn schon unbedingt DLLs verwenden willst. Fazit: du machst einen Indy-Wrapper in deine Anwendung und auf den greifst du dann zu. So bleibt die Indy-Kompo in der Haupt-App und wird von den andern Teilen genutzt. Da die Indies wohl nicht sehr häufig ein Update brauchen, ist dein Code-Größen-Problem doch damit behoben. Oder hab ich dich jetzt falsch verstanden? :? ;)

user profile iconJayEff hat folgendes geschrieben:
das lable und goto .. nun ja.. recht hast du ^^ Ich benutz es nur, wenn ich keine andere Möglichkeit finde. Warum is das eigentlich so verschrien um etwas OT zu betreiben ... ?

Man kann beweisen, dass label/goto "unnötig" sind, bzw. sich immer durch bessere Kontrollstrukturen ersetzen lassen. Soviel zu "keine andere Möglichkeit". ;) Verschrien ist goto deshalb, weil es sogenannten "Spaghetti-Code" erzeugt und dabei gar nicht notwendig ist. :D

cu
Narses


JayEff - Mi 16.08.06 00:36

Die DLL wollte ich benutzen, damit, falls ein Update herunter geladen muss, die größe des Updates minimal bleibt. Also wollte ich die Grafiken und das Hauptprogramm so gestalten, dass es nur einmal heruntergeladen werden muss, während die DLL geupdatet werden kann, bzw umgekehrt. Auf diese Art müsste man nur die Hälfte des Programmes beim Update herunterladen, das war der Grund warum ich diese funktion in die DLL auslagern wollte. Also würden die idFTP (usw. ) units nur einmal, nämlich in der DLL auftauchen. Klar, dass der Code der Unit nur einmal eingebunden wird, auch wenn ich 100 mal in verschiedenen units "uses aUnit" eintrage.
Die DLL habe ich ja nur desshalb geschrieben, weil ich die Größe der Anwendung veringern wollte. Gut, DLL+Anwendung zusammen sind natürlich größer, als wenn ich die Funktionen alle in der Hauptanwendung gelassen hätte.
Was ich sagen will: Ich KÖNNTE auf die DLL verzichten - die DLL MUSS nicht unbedingt auf eine idFTP Komponente zugreifen, WENN, dann macht es nur Sinn, die ganze Prozedur samt Komponente auszulagern (denke ich ... ).

Was ist "Spagetti-Code"? (Meinst du den ASM code oder was genau?) Aah ich weis schon.. ich google mal ^^
Klar könnte man irgentwie drauf verzichten, aber manchmal fällt mir nicht ein, wie ^^ In meinem Beispiel per Rekursion, versteh schon, das ist natürlich sehr viel einfacher... Werds bei Gelegenheit ändern.


Martok - Mi 16.08.06 03:53

Ich habs dir mal ent-Goto-t:

Delphi-Quelltext
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:
Procedure TForm1.getChat;
Var
    s: TStringlist;
    Messages: TIniFile;
    mes, abs, seens: String;
Begin
  If length(Form3.Edit1.text) > 0 Then
  Begin
    repeat
      s := TStringlist.Create;
      s.CommaText := IdHTTP1.Get('http://www.jayy.de/update/messages.txt');
      s.savetofile('C:\tempMessages.ini');
      s.text := '';
      Messages := TIniFile.Create('C:\tempMessages.ini');
      If Messages.ReadBool(Form3.Edit1.text, 'x', false) Then
      Begin
        mes := StringReplace(Messages.ReadString(Form3.Edit1.text, 'message'''), '-'' ', [rfReplaceAll]);
        abs := Messages.ReadString(Form3.Edit1.text, 'abs''?');
        Messages.EraseSection(Form3.Edit1.text);
        JaysMessage.zeigs('Nachricht erhalten!', abs + ' schrieb:' + #10#13 + mes); //Wundert euch nicht da drüber, ist nur ne art messagebox mit 3 userdefined buttons und einem an und ausschaltbaren editfeld...
        s.LoadFromFile('C:\tempMessages.ini');
        Form3.IdFTP1.Put(TSTringStream.Create(s.text), 'messages.txt');
      End;
      If Messages.ReadBool(' @all ''x', false) And (pos(Form3.Edit1.text, Messages.ReadString(' @all ''seens''')) <= 0Then
      Begin
        mes := StringReplace(Messages.ReadString(Form3.Edit1.text, 'message'''), '-'' ', [rfReplaceAll]);
        abs := Messages.ReadString(Form3.Edit1.text, 'abs''?');
        seens := Messages.ReadString(' @all ''seen''');
        Messages.WriteString(' @all ''seen', Form3.Edit1.text + ',' + seens);
        JaysMessage.zeigs('Message an alle!', abs + ' schrieb:' + #10#13 + mes);
        s.LoadFromFile('C:\tempMessages.ini');
        Form3.IdFTP1.Put(TSTringStream.Create(s.text), 'messages.txt');
      End;
      Messages.Free;
    until pos(Form3.Edit1.text, s.text) = 0;
    deletefile('C:\tempMessages.ini');
  End;
End;

Obwohl ich gestehen muss, grade bei Case-Statements benutze ich goto doch manchmal, mir fehlt einfach diese fallthrough-Funktionalität aus C, also wenn kein break da steht wird die Abfrage auch nicht verlassen.


Narses - Mi 16.08.06 08:08

Moin!

Ich sehe gerade, dass meine Hinweise bzgl. MessageLoop auf deinen Fall gar nicht zutreffen... :? ;) (war wohl doch schon etwas später gestern... ;))

Fragt sich also, wie deine Funktion aus der DLL deklariert ist, sprich, wie sieht die Parameterübergabe aus?

cu
Narses


JayEff - Mi 16.08.06 14:58

Das würde dann wohl in etwa so aussehn:

Delphi-Quelltext
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:
uses
  FastShareMem,
  Windows,
  SysUtils,
  Classes,
  shellapi,
  Registry,
  IdFTP,
  idHTTP;

Function xx: String Stdcall;
Var
    IdFTP: TidFTP;
    idHTTP: TidHTTP;
Begin
    IdFTP := TidFTP.Create(Nil);
    idHTTP := TidHTTP.Create(Nil);
    IdFTP.Host := 'http://';
    IdFTP.Username := '';
    IdFTP.Password := '';
    result := idHTTP.Get('www.jayy.de/index.php');
    IdFTP.Free;
    idHTTP.Free;
End;

Exports xx;

End.

Bei nem Aufruf von showmessage(xx); kommt:

---------------------------
Benachrichtigung über Debugger-Exception
---------------------------
Im Projekt Project2.exe ist eine Exception der Klasse EIdHTTPProtocolException aufgetreten. Meldung: 'HTTP/1.0 501 Not Implemented'. Prozess wurde angehalten. Mit Einzelne Anweisung oder Start fortsetzen.
---------------------------
OK Hilfe
---------------------------

Also das wär nen Test.


Narses - Mi 16.08.06 15:08

Moin!

Und wenn du die FTP+HTTP-Kompo weiter in der Hauptapplikation lässt und nur eine Referenz darauf übergibst? (also die Kompos nicht in der DLL erzeugst, weil genau das ist das Problem) Würde genau den von mir angesprochenen Code-Spareffekt erzielen. ;)

cu
Narses


JayEff - Mi 16.08.06 15:15

Hm.. Ich wüsste nicht, wie ich von der DLL aus auf eine Komponente in der Hauptapp zugreifen könnte... Du hast etwas von einem Wrapper gesagt ... das sollte ich mir vielleicht mal anschauen, wa? Aber dann spare ich mir in der Hauptapp nicht wirklich die Units.. Hmm. Ich könnte ja Umdenken, und die Prozeduren in die DLL packen, die wahrscheinlicher geupdatet werden müssen. Hm ja.. dann müsste ich natürlich rausfinden, wie ich auf die Indys zugreifen kann.


Narses - Mi 16.08.06 16:38

Moin!

user profile iconJayEff hat folgendes geschrieben:
Hm.. Ich wüsste nicht, wie ich von der DLL aus auf eine Komponente in der Hauptapp zugreifen könnte...

Wie wäre es so: ;)

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
uses
  FastShareMem,
  Windows,
  SysUtils,
  Classes,
  shellapi,
  Registry,
  IdFTP,
  idHTTP;

Function xx(IdHTTP: TIdHTTP)String Stdcall;
Begin
  result := idHTTP.Get('www.jayy.de/index.php');
End;

Exports xx;

End.

Die Kompo selbst in der HauptApp erzeugen und freigeben, dann nur die Referenz darauf übergeben. Fertig.

cu
Narses


Narses - Mi 16.08.06 22:53

Moin!

Es hat mir einfach keine Ruhe gelassen und ich muss gestehen - ich hatte es auch wohl nicht mehr so ganz richtig in Erinnerung... (hab da was mit den alten Socket-Kompos verwechselt... :oops:) ;)

@user profile iconJayEff: Ich weiß nicht so ganz genau, wo dein Problem im Code liegt, aber die Indies sind durchaus in der Lage, sich dynamisch in einer DLL instanziieren zu lassen (zumindest IdHTTP und IdFTP von Indy9; vermutlich, da blocking socket calls gemacht werden; schätze, bei asynchronen WSA-Ereignissen wird´s trotzdem noch Probleme geben). Hier ist mein Testprojekt, funktioniert.

cu
Narses