![]() |
exportieren von Strukturen aus DLLs...
hallo,
ich möchte aus einer DLL eine Struktur exportieren, die Informationen zur DLL ausgibt; dies mache ich per aufruf eine funktion. Hier der Code der DLL:
Delphi-Quellcode:
im hauptprogramm lade ich nun diese DLL (dynamisch) und übernehme den Rückgabewert(die Informationen) der Funktion.
library DLLTest;
{$R *.res} {$R meine_resource.res} type //Definition einer speziellen Karte TSpezielle = record Name: PChar; Index: Word; end; TSpezielleArray = array of TSpezielle; //Definition der Struktur einer KartenSammlung-Information TKartenSammlungInfo = record Name: PChar; //Name der Kartensammlung Version: PChar; //Version der Kartensammlung Karten: Byte; //Anzahl der Karten (ohne spezielle) Spezielle: TSpezielleArray; //vorhandene spezielle Karten mit Name und //Index end; function DLLSammlungInfo(): TKartenSammlungInfo; stdcall; begin with result do begin Name := 'Test der DLL'; Version := '1.0'; Karten := 32; SetLength(Spezielle, 2); Spezielle[0].Name := 'Speziell1'; Spezielle[0].Index := 65534; Spezielle[1].Name := 'Speziell2'; Spezielle[1].Index := 65535; end; end; exports DLLSammlungInfo; end. Hier der Code des Hauptprogramms:
Delphi-Quellcode:
Das Problem: irgendo tritt eine AV auf. jetzt hab ich nach etwas debuggen rausgefunden, dass dieser beim übernehmen des Spezielle-Arrays auftritt. Allerdings kann ich die ursache für das problem nicht finden - liegt das am exportieren von solchen etwas komplexeren strukturen (-> anderer lösungsweg?) oder mache ich den fehler (-> wo ;-))
type
//Definition einer speziellen Karte TSpezielle = record Name: PChar; Index: Word; end; TSpezielleArray = array of TSpezielle; //Definition der Struktur einer KartenSammlung-Information TKartenSammlungInfo = record Name: PChar; //Name der Kartensammlung Version: PChar; //Version der Kartensammlung Karten: Byte; //Anzahl der Karten (ohne spezielle) Spezielle: TSpezielleArray; //vorhandene spezielle Karten mit Name und //Index end; PTKartenSammlungInfo = ^TKartenSammlungInfo; //Definition der Funktion, die von einer Kartensammlung erwartet wird TDLLSammlungInfo = function(): TKartenSammlungInfo; stdcall; procedure KopiereInfo(QuelleInfo: PTKartenSammlungInfo; var ZielInfo: TKartenSammlungInfo); var b: Byte; begin with ZielInfo do begin Name := QuelleInfo.Name; Version := QuelleInfo.Version; Karten := QuelleInfo.Karten; SetLength(Spezielle, Length(QuelleInfo.Spezielle)); //FEHLER for b := 1 to Length(QuelleInfo.Spezielle) do //FEHLER Spezielle[b - 1] := QuelleInfo.Spezielle[b - 1]; //FEHLER end; end; function CheckSammlung(Sammlung: string): Boolean; var KartenLib: THandle; //Handle auf die DLL DLLSammlungInfo: TDLLSammlungInfo; //Addresse der Funktion Info: TKartenSammlungInfo; //Infos von der DLL begin result := false; Sammlung := ExtractFilePath(ParamStr(0)) + PluginPfad + Sammlung; KartenLib := LoadLibrary(PChar(Sammlung)); if KartenLib <> 0 then begin @DLLSammlungInfo := GetProcAddress(KartenLib, 'DLLSammlungInfo'); if Assigned(DLLSammlungInfo) then begin KopiereInfo(@DLLSammlungInfo, Info); //Anzeigen der Informationen (mit zwei speziellen Karten) MessageBox(0, PChar('Name: ' + Info.Name + #10 + 'Version: ' + Info.Version + #10 + 'Kartenzahl: ' + IntToStr(Info.Karten) + #10 + 'Spezielle: ' + IntToStr(Length(Info.Spezielle)) + #10 + 'Sp1: ' + Info.Spezielle[0].Name + ' / ' + IntToStr(Info.Spezielle[0].Index) + #10 + 'Sp2: ' + Info.Spezielle[1].Name + ' / ' + IntToStr(Info.Spezielle[1].Index) ), '', 0);} end; end; FreeLibrary(KartenLib); end; danke für hilfe, heiopei |
Re: exportieren von Strukturen aus DLLs...
Du musst Result mit New erstellen.
Der Record, auf den Result zeigt, wird nur lokal erzeugt und beim Verlassen der Funktion wieder zerstört (analog zu Objektinstanzen, die Du ja auch kreieren musst, wenn Du sie als Funktionsergebnis verwenden willst). Ausserdem solltest Du einen Pointer auf den Record zurückgeben. |
Re: exportieren von Strukturen aus DLLs...
Das problem liegt erstmal in dem dynamischen Array, dadafür von der DLL Speicher reserviert wird, welcher (ohne einen SharedMemoryManager) nicht in anderen Modulen (also der EXE) verwendet werden kann (da der Speicher ja einem anderem MemoryManager gehört, kann der MemoryManager der EXE diesen nicht verwalten) und eventuell gibt's dann ja auch noch ein Problemchen mit der RTTI des dynamischen Arrays.
Außerdem kann es locker noch zu problemen bei der Recordausrichtung kommen, vorallem wenn der Compiler in der DLL anders ausrichtet, als in der EXE (würde dir daher in diesme Fall schonmal zu packed Record's raten) |
Re: exportieren von Strukturen aus DLLs...
hallo,
hmm.... ok. da soll mal einer draufkommen - die informationen werden nämlich richtig angezeigt, aber die av tritt erst auf, wenn ich versuche, das array zu übernehmen... das mit dem pointer hab ich mir auch schon gedacht, aber nur zum teil verwirklicht :oops: @himitsu: das mit dem packed array werd ich dann gleich mal testen (genauso wie New(result)) danke, heiopei |
Re: exportieren von Strukturen aus DLLs...
Zitat:
Der DelphiMM (wird standardmäßig installiert) wird für jedes Delphi-Modul einzeln erzeugt und diese verschiedenen MMs arbeiten nicht zusammen, daher kannst du keinen Speicherbereich in einem Modul (DLL/EXE) erstellen (egal ob mit New, SetLength, oder wie auch immer) und in dem anderen Modul freigeben, oder seine Größe ändern, denn wenn du es versuchst, dann wird der entsprechende MemoryManager meckern (mit 'ner Exception reagieren), da er keine Referenz zu dem angegebenen Speicherbereich(Pointer) in seinen Verwaltungsdaten finden kann. Zitat:
also entweder du nimmst ein Array mit fester größe und übergibst es per Var-Parameter ... denn da wird der Speicher in deiner EXE reserviert und die DLL schreibt nur darain
Delphi-Quellcode:
oder bei 'nem dynamischen array rufst du SetLength in der EXE auf und arbeitest auch per Var-Parameter
type TSpezielle = record
Name: PChar; Index: Word; end; TSpezielleArray = array[0..irgendwas] of TSpezielle; TKartenSammlungInfo = record Name: PChar; //Name der Kartensammlung Version: PChar; //Version der Kartensammlung Karten: Byte; //Anzahl der Karten (ohne spezielle) Spezielle: TSpezielleArray; //vorhandene spezielle Karten mit Name und //Index end; procedure DLLSammlungInfo(var Info: TKartenSammlungInfo); stdcall;
Delphi-Quellcode:
und wenn es keine Probleme mit der RTTI geben sollte, dann kannst du es auch so lassen, wie bisher und bindest aber einen SharedMM ein, damit in der EXE und der DLL der die MemoryManager zusammen arbeiten und somit auch den Speicher des anderen MMs mit verwalten können.
type TSpezielle = record
Name: PChar; Index: Word; end; TSpezielleArray = array of TSpezielle; TKartenSammlungInfo = record Name: PChar; //Name der Kartensammlung Version: PChar; //Version der Kartensammlung Karten: Byte; //Anzahl der Karten (ohne spezielle) Spezielle: TSpezielleArray; //vorhandene spezielle Karten mit Name und //Index end; function DLLSammlungInfoSize: integer; stdcall; procedure DLLSammlungInfo(var Info: TKartenSammlungInfo); stdcall; // in der EXE dann SetLength(Info.Spezielle, DLLSammlungInfoSize); DLLSammlungInfo(Info); |
Re: exportieren von Strukturen aus DLLs...
hallo himitsu,
aber ich rufe doch nur die funktion der DLL auf und weise das ergebnis einer eigenen variable zu, der ich die größe des array an das des ergebnisses anpasse (wasn satz:-)) - verändere ich da irgendwas in der DLL?hää??? PS: ich verwende nur den speichermanager von delphi (7). |
Re: exportieren von Strukturen aus DLLs...
|
Re: exportieren von Strukturen aus DLLs...
jetzt hab ichs kapisch...
ok. das mit ner weiteren funktion, welche die größe des arrays ausgibt, hab ich mir auch überlegt, erschien mir aber erstmal überflüssig, weil ich ja nicht wusste, worans lag - nachher ist man immer schlauer :lol: das mit anderen speichermanagern schau ich mir bei gelegenheit auch noch an, danke für den tipp. mfg, heiopei |
Re: exportieren von Strukturen aus DLLs...
mittach,
so hab das jetzt mal alles umgesetzt, aber es tritt trotzdem noch eine av auf!. (ich kann jetzt die infos erfolgreich übernehmen, aber bei anzeigen der info (strings) tritt wieder die av auf, bzw. nach der anzeige) :-( der code der dll:
Delphi-Quellcode:
das hauptprogramm:
const
SpezielleKarten = 2; type TSpezielle = record Name: PChar; ResID: Word; end; TSpezielleArray = array [1..SpezielleKarten] of TSpezielle; TKartenSammlungInfo = record Name: PChar; Version: PChar; AnzKarten: Byte; AnzSpezielle: Word; Spezielle: TSpezielleArray; end; PTKartenSammlungInfo = ^TKartenSammlungInfo; function DLLSammlungInfo(): PTKartenSammlungInfo; stdcall; begin with result^ do begin Name := 'Beispiel'; Version := '1.0.0'; AnzKarten := 32; AnzSpezielle := SpezielleKarten; Spezielle[1].Name := 'Speziell1'; Spezielle[1].ResID := 65534; Spezielle[2].Name := 'Speziell2'; Spezielle[2].ResID := 65535; end; end;
Delphi-Quellcode:
woran liegts jetzt wieder,
type
TSpezielle = record Name: PChar; ResID: Word; end; TSpezielleArray = array of TSpezielle; TKartenSammlungInfo = record Name: PChar; Version: PChar; AnzKarten: Byte; AnzSpezielle: Word; Spezielle: TSpezielleArray; end; PTKartenSammlungInfo = ^TKartenSammlungInfo; TDLLSammlungInfo = function(): PTKartenSammlungInfo; stdcall; procedure KopiereInfo(QuelleInfo: PTKartenSammlungInfo; var ZielInfo: TKartenSammlungInfo); var w: Word; begin with ZielInfo do begin Name := QuelleInfo^.Name; Version := QuelleInfo^.Version; AnzKarten := QuelleInfo^.AnzKarten; AnzSpezielle := QuelleInfo^.AnzSpezielle; SetLength(Spezielle, AnzSpezielle); if AnzSpezielle > 0 then for w := 1 to AnzSpezielle do Spezielle[w - 1] := QuelleInfo^.Spezielle[w]; end; end; function CheckSammlung(Sammlung: string): Boolean; var KartenLib: THandle; //Handle auf die DLL DLLSammlungInfo: TDLLSammlungInfo; //Addresse der Funktion Info: TKartenSammlungInfo; //Infos von der DLL begin result := false; Sammlung := ExtractFilePath(ParamStr(0)) + PluginPfad + Sammlung; KartenLib := LoadLibrary(PChar(Sammlung)); if KartenLib <> 0 then begin @DLLSammlungInfo := GetProcAddress(KartenLib, 'DLLSammlungInfo'); if Assigned(DLLSammlungInfo) then begin KopiereInfo(DLLSammlungInfo, Info); DLLSammlungInfo := nil; MessageBox(0, PChar('Name: ' + Info.Name + #10 + 'Version: ' + Info.Version + #10 + 'Konvention: ' + Info.Konvention + #10 + 'Kartenzahl: ' + IntToStr(Info.AnzKarten) + #10 + 'Spezielle: ' + IntToStr(Info.AnzSpezielle) + #10 + 'Sp1: ' + Info.Spezielle[0].Name + ' / ' + IntToStr(Info.Spezielle[0].ResID) + #10 + 'Sp2: ' + Info.Spezielle[1].Name + ' / ' + IntToStr(Info.Spezielle[1].ResID) ), '', 0); result := true; end; end; FreeLibrary(KartenLib); end; danke für tipps, heiopei ps: ich hab also in erster linie das dyn. array umgangen, in dem ich in der dll ein statisches erzeuge und die größe als weiteren info-paramter mitgebe! |
Alle Zeitangaben in WEZ +1. Es ist jetzt 02:10 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