![]() |
Callback Funktionen und DLL?
Hallo Leute,
ich habe ein Pluginbasierendes Programm geschrieben und hab nun jede Menge Probleme zu bewältigen, die ich nicht einmal verstehe. Die Plugins sind einfache Win32 DLL's. Die DLL's besitzen nur 2 Hauptfunktionen, die mit der Delphi Standardkonvetion "register" aufegrufen werden. Die Funktionen heissen "init" und "start" und sehen wie folgt aus.
Delphi-Quellcode:
Wie man sieht, übergebe ich Init 2 Zeiger auf Funktionen im Hauptprogramm.
{DLL Plugin}
type TGet = function(link,cookie:pchar;redirect,sendcookie:boolean; var location,rawheaders:pchar):pchar ;stdcall; TPost = function(link,params,cookie:pchar;redirect,sendcookie:boolean; var location,rawheaders:pchar):pchar ;stdcall; var CBGet : TGet ; CBPost : TPost ; function initcb(const get,post:Pointer):pchar ; begin @CBGet := Get ; @CBPost := Post ; Result := 'Plugin_1' ; end; function start(link:pchar):pchar ; var Location, RawHeaders : pchar begin Result := CBPost('http://www.google.de','','',false,false,Location,RawHeaders) ; end; Get dient dazu den HTML Code einer beliebigen Seite abzurufen und Post steht eben für einen Post Request zur Verfügung. Diese beiden Fukntionen werden aber mit "stdcall" als Aufrufkonvention aufgerufen, da ich glaube gelesen zu haben, dass Callbackfunktionen sich nur mit "stdcall" vertragen. Für die echten Funktionen im Hauptprogramm habe ich Indy 9 verwendet und sie sehen folgerndermaßen aus.
Delphi-Quellcode:
Die DLL Plugins fasse ich in einem array mit einem Record zusammen und rufe sie nacheinander auf.
{Hauptprogramm}
function PLGHTTPGet(link,cookie:pchar;redirect,sendcookie:boolean;var location,rawheaders:pchar):pchar ; stdcall ; var IDHTTP : TIdHTTP ; begin IDHTTP := TIdHTTP.Create(nil); IDHTTP.HandleRedirects := redirect ; if sendcookie then begin IDHTTP.AllowCookies := True ; IDHTTP.Request.CustomHeaders.Text := cookie ; end else IDHTTP.AllowCookies := False ; try Result := pchar(IDHTTP.Get(link)) ; except Result := 'failed' ; end; location := pchar(IDHTTP.Response.Location) ; rawheaders := pchar(IDHTTP.Response.RawHeaders.text); IDHTTP.Free ; end; function PLGHTTPPost(link,params,cookie:pchar;redirect,sendcookie:boolean;var location,rawheaders:pchar):pchar ; stdcall; var Parameters : TStringList ; HTTP : TIdHTTP ; begin HTTP := TIdHTTP.Create(nil); Parameters := TStringList.Create ; Parameters.Add(params) ; HTTP.HandleRedirects := redirect ; if sendcookie then begin HTTP.AllowCookies := True ; HTTP.Request.CustomHeaders.Text := cookie ; end else HTTP.AllowCookies := False ; try Result := PChar(HTTP.Post(link,Parameters)) ; except Result := 'failed' ; end; location := PCHar(HTTP.Response.Location) ; rawheaders := pChar(HTTP.Response.RawHeaders.text); Parameters.Free ; HTTP.Free ; end;
Delphi-Quellcode:
Soweit sogut.
{Hauptprogramm}
.. ... try MemoOutput.text := PlgArray[i].start(PChar(Link)) ; except ... .. Es klappt auch alles wunderbar und wird auch richtig ausgeführt, aber dann passieren unter bestimmten Umständen ganz komische Sachen. Wenn ich die Post Funktion ca. 20 - 30 in einem Plugin aufrufe, dann bekommt das Hauptprogramm nichts mehr als Ergebnis von "start" zurück, obwohl in der DLL alles richtig ablaüft und sie auch das richtige Result zurückgibt. Dann wird es aber noch abgefahrener und das Hauptprogramm bleibt nach dem Aufruf der DLL einfach sporadisch an irgendeiner Stelle hängen. Jetzt kann ich es mir absolut nicht erklären. Es kommt auch nie eine AV, aber manchmal ein Runtime Error. Könnt ihr einen Fehler entdecken. Mache ich vielleicht grundsätzlich etwas falsch? Danke im Voraus. PS: Ich benutze Delphi 2006. |
Re: Callback Funktionen und DLL?
das liegt daran das du als result ein pchar zurück gibst!
ein PChar ist nichts anderes als ein Zeiger der eben auf das erste Zeichen einer Zeichenkette zeigt. folgendes klappt noch (ist aber auch unschön)
Delphi-Quellcode:
folgendes geht aber nicht!
result := 'staticher Text';
Delphi-Quellcode:
Der Grund ist ganz einfach. PChar ist eben nur ein Pointer auf das erste Zeichen einer Zeichenkette.
result := lokaleVarible;
Bei dem statichen Text zeigt dieser PChar auf einen fest einkompilierten Text im Speicher (der da fest drin steht). Bei der lokalen Variblen hingegen zeigt der PChar auf das erste Zeichen der lokalen Variablen die auf dem Stack liegt. Der Stack wird aber beim verlassen der Funktion aufgeräumt und somit zeigt der Pointer auf den Stack wo eventuell schon was ganz anderes liegt wenn du diesen abfragst bzw. nichts mehr liegt. |
Re: Callback Funktionen und DLL?
PChar als Rückgabewert einer DLL-Funktion kann schnell zu Fehlern führen, da zwar für die Speicheradresse des PChars Speicher reserviert wird, aber nicht für die Zeichenkette, was dazu führen kann, dass ein anderes Programm diesen Speicherbereich allokiert, und damit u.U. "deine" Daten weg sind.
Entweder sorgst du für eine eigene Speicherverwaltung für die Rückgabewerte, oder, was ich empfehlen würde, die übergibst die PChars als Var-Parameter, dann hast du auch immer den korekten Wert in deiner Funktion. |
Re: Callback Funktionen und DLL?
Zitat:
Wieso klappt es denn mit einem oder 2 Posts einwandfrei und erst ab ca. 20 wird es erst Fehlerhaft? |
Re: Callback Funktionen und DLL?
eine eigene speicherverwaltung würde auch nichts bringen weil zu dem zeitpunkt wo du drauf zugreifst das ganze gar nicht mehr auf dem stack liegt bzw. du dich da nicht mehr drauf verlassen solltest.
Und warum es am anfang klappt und später nicht liegt daran das irgendwann eben dochmal was auf dem stack landet was deins überschreibt. Somit fehlt dann wohl die abschließende #0 und es wird diese gesucht. Mit etwas pech liegt diese dann außerhalb des Speichers auf den du zugriff hast und schon knallts, hängts etc. Eine Notlösung wäre das du anstelle einer lokalen Variablen eine globale verwendest, denn diese behält ihren wert auch noch nach verlassen der Procedure da sie nicht auf dem stack liegt. Ist aber eben eine Notlösung. richtiger wäre einen PChar auf bereits reservierten speicher zu übergeben wo deine procedure dann die zeichen rein kopiert. |
Re: Callback Funktionen und DLL?
Erstmal danke für die schnellen Antworten, denn ich konnte mir dabei nichts zusammenreimen.
Jetzt übergebe ich das Ergebnis der DLL, per var Pramater zurück ans Hauptprogramm. Dies funktioniert anscheinend auch ganz gut, jedoch kann ich nun das Programm nicht mehr beenden und muss es per Takmanager killen. Wenn ich debugge, dann erhalte ich am Ende folgende Fehlermeldung. Zitat:
|
Re: Callback Funktionen und DLL?
per var-parameter? den Pointer? irgendwas wirst du da durcheinander. kannst du den quelltext mal zeigen? Wenn du einen pointer auf den speicher übergibst wo hinn geschrieben werden soll (also das ergebnis) muss nichts als var-Parameter übergeben werden.
|
Re: Callback Funktionen und DLL?
Na ich habe aus der start function eine procedure gemacht:
Delphi-Quellcode:
procedure start(link:pchar; var Return:pchar);
var Location, RawHeaders : pchar begin Return:= CBPost('http://www.google.de','','',false,false,Location,RawHeaders) ; end; |
Re: Callback Funktionen und DLL?
so nicht! das ist das gleiche wie mit dem PChar als result. Das musst du erstmal ändern.
Du weißt ja schon wieder die adresse der lokalen Variablen deinem PChar zu. So macht man das:
Delphi-Quellcode:
(ungetestet)
//procedure außerhalb der dll
var lRes : String; begin SetLength(lRes, 1024); ZeroMemory(@lRes[1], Length(lRes)); DllProcedure(@lRes[1], Length(lRes)); end; //procedure innerhalb der dll procedure DllProcedure(ARes: PChar; AResSize); var meinString: String; begin meinString := 'Rückgabe'; move(ARes^, meinString[1], Min(AResSize, Length(meinString)); end; |
Re: Callback Funktionen und DLL?
Guck mal hier:
![]() |
Alle Zeitangaben in WEZ +1. Es ist jetzt 03:01 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