AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Win32/Win64 API (native code) Delphi exportieren von Strukturen aus DLLs...
Thema durchsuchen
Ansicht
Themen-Optionen

exportieren von Strukturen aus DLLs...

Ein Thema von heiopei · begonnen am 3. Mai 2006 · letzter Beitrag vom 4. Mai 2006
Antwort Antwort
heiopei
(Gast)

n/a Beiträge
 
#1

exportieren von Strukturen aus DLLs...

  Alt 3. Mai 2006, 11:32
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:
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.
im hauptprogramm lade ich nun diese DLL (dynamisch) und übernehme den Rückgabewert(die Informationen) der Funktion.

Hier der Code des Hauptprogramms:

Delphi-Quellcode:
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;
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 )

danke für hilfe,
heiopei
  Mit Zitat antworten Zitat
Sidorion

Registriert seit: 23. Jun 2005
403 Beiträge
 
#2

Re: exportieren von Strukturen aus DLLs...

  Alt 3. Mai 2006, 11:40
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.
Manchmal sehen Dinge, die wie Dinge aussehen wollen mehr wie Dinge aus, als Dinge
<Esmerelda Wetterwachs>
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
43.142 Beiträge
 
Delphi 12 Athens
 
#3

Re: exportieren von Strukturen aus DLLs...

  Alt 3. Mai 2006, 11:55
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)
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests
  Mit Zitat antworten Zitat
heiopei
(Gast)

n/a Beiträge
 
#4

Re: exportieren von Strukturen aus DLLs...

  Alt 3. Mai 2006, 11:59
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


@himitsu: das mit dem packed array werd ich dann gleich mal testen (genauso wie New(result))

danke,
heiopei
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
43.142 Beiträge
 
Delphi 12 Athens
 
#5

Re: exportieren von Strukturen aus DLLs...

  Alt 3. Mai 2006, 12:07
Zitat von heiopei:
genauso wie New(result))
Du hast doch bestimmt keinem anderen MemoryManager (z.B. ShareMM, FastMM, oder ähnliches) eingebunden?

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:
wenn ich versuche, das array zu übernehmen
wie gesagt ... lesen und schreiben kann man zwar in diesen Speicherbereich, da der ja zur Instance(Anwendung) gehört und somit alle Module dieser Instance zugriff haben, der Speicher kann außerhalb einenes Moduls nicht verwaltet werden.

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:
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;
oder bei 'nem dynamischen array rufst du SetLength in der EXE auf und arbeitest auch per Var-Parameter
Delphi-Quellcode:
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);
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.
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests
  Mit Zitat antworten Zitat
heiopei
(Gast)

n/a Beiträge
 
#6

Re: exportieren von Strukturen aus DLLs...

  Alt 3. Mai 2006, 12:12
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).
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
43.142 Beiträge
 
Delphi 12 Athens
 
#7

Re: exportieren von Strukturen aus DLLs...

  Alt 3. Mai 2006, 12:20
Ja.

aus der DLL
SetLength(Spezielle, 2); du veränderst was an dem Array.

PS: hatte oben gerade noch was geändert gehabt.



Zitat:
PS: ich verwende nur den speichermanager von delphi (7).
kannst ja mal nach Hier im Forum suchenFastMM/Hier im Forum suchenFastXMM suchen
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests
  Mit Zitat antworten Zitat
heiopei
(Gast)

n/a Beiträge
 
#8

Re: exportieren von Strukturen aus DLLs...

  Alt 3. Mai 2006, 12:26
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

das mit anderen speichermanagern schau ich mir bei gelegenheit auch noch an, danke für den tipp.


mfg,
heiopei
  Mit Zitat antworten Zitat
heiopei
(Gast)

n/a Beiträge
 
#9

Re: exportieren von Strukturen aus DLLs...

  Alt 4. Mai 2006, 13:30
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:
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;
das hauptprogramm:

Delphi-Quellcode:
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;
woran liegts jetzt wieder,
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!
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 15:56 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz