AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Programmieren allgemein C++-DLL --> Delphi - dynamischer struct-Array?
Thema durchsuchen
Ansicht
Themen-Optionen

C++-DLL --> Delphi - dynamischer struct-Array?

Ein Thema von Legato · begonnen am 20. Jun 2007 · letzter Beitrag vom 20. Jun 2007
Antwort Antwort
Legato

Registriert seit: 31. Mai 2007
6 Beiträge
 
Delphi 2006 Enterprise
 
#1

C++-DLL --> Delphi - dynamischer struct-Array?

  Alt 20. Jun 2007, 14:18
Huhu,

ich habe eine Funktion in C++, die einen Pointer auf eine struct entgegennimmt und diese dynamisch füllen soll. Die Anzahl der Elemente wird erst in der Funktion selber bekannt. Hier eine reduzierte Testversion davon:
Code:
struct ContactType
{
//   __int64 id;
//   char *name;
   int protocol;
};

extern "C" __declspec(dllexport) int ContactManagerSOAP_GetContactTypes(ContactType* result)
{
   int count = 1;
   result = new ContactType[count];
   for (int i = 0; i <= count; i++) {
      result[i].protocol = 3;
   }
   return count;
}
Nun sollte der Array ja theoretisch ein Element enthalten.

Ich rufe das ganze in Delphi auf:

Delphi-Quellcode:
type
   ContactManagerSOAP_ContactType = record
//      a: INT64;
//      b: PChar;
      c: Integer;
   end;
  ContactManagerSOAP_ContactTypeArray = array of ContactManagerSOAP_ContactType;

function _ContactManagerSOAP_GetContactTypes(var result: ContactManagerSOAP_ContactTypeArray) : Integer; cdecl; external '../DLL/ObjectWebservice.dll';

procedure TDataDisplayForm.btnGetContactTypesClick(Sender: TObject);
var
  ContactTypes: ContactManagerSOAP_ContactTypeArray;
  count: Integer;
begin
// SetLength(ContactTypes, 1);
  count := _ContactManagerSOAP_GetContactTypes(ContactTypes);
  ShowMessage(IntToStr(ContactTypes[0].c));
end;
Klappt nicht - ContactTypes enthält 0 Elemente, c zeigt ins Nichts.

Sieht jemand, was ich falsch mache, oder hat eine Idee, wie ich das ganze stattdessen lösen könnte?

Mit liebem Gruß,
Tobias
Tobias
The highest sounds are hardest to hear.
Going forward is a way to retreat.
Great talent shows itself late in life.
Even a perfect program still has bugs.
  Mit Zitat antworten Zitat
Benutzerbild von SirThornberry
SirThornberry
(Moderator)

Registriert seit: 23. Sep 2003
Ort: Bockwen
12.235 Beiträge
 
Delphi 2006 Professional
 
#2

Re: C++-DLL --> Delphi - dynamischer struct-Array?

  Alt 20. Jun 2007, 14:22
aua, ein dynamisches Delphiarray ist was ganz anderes als was deine C-Funktion erwartet. Ein Dynamisches Array in Delphi ist wie ein dynamischer String in Delphi nur ein Pointer der auf die Daten und noch einige andere Infos zeigt.

Ich hoffe dir ist auch bewusst das deine DLL den Speicher freigeben muss wenn sie ihn angefordert hat. Laut deinem bisherigen Quelltext würdest du in der DLL speicher anfordern der nie frei gegeben wird.

Üblich ist folgendes:

Funktion in der DLL
Delphi-Quellcode:
function GibWerte(Speicher, AnzahlDerSpeicherElemente): Integer;
begin
  AnzahlderVorhandenenElemente;
  //in Speicher nur soviel schreiben wie rein passt und vorhanden ist
  //Wenn AnzahlderVorhandenenElemente also größer ist als AnzahlDerSpeicherElemente darfst du trotzdem nur AnzahlDerSpeicherElemente schreiben
  //ist AnzahlderVorhandenenElemente kleiner oder gleich AnzahlDerSpeicherElemente kannst du natürlich AnzahlderVorhandenenElemente schreiben.
  result := AnzahlDerVorhandenenElemente;
end;
Funktion außerhalb der DLL
Delphi-Quellcode:
var
  MeineElemente: Array of Element;
  Anzahl : Integer;
begin
  Anzahl := Dll_GibWerte(nil, 0);
  SetLength(MeineElemente, Anzahl);
  Dll_GibWerte(@MeineElemente[0], Anzahl);
  [...]
end;
Jens
Mit Source ist es wie mit Kunst - Hauptsache der Künstler versteht's
  Mit Zitat antworten Zitat
Robert Marquardt
(Gast)

n/a Beiträge
 
#3

Re: C++-DLL --> Delphi - dynamischer struct-Array?

  Alt 20. Jun 2007, 14:34
Es ist immer wieder erschreckend wie wenig Ahnung die Leute haben (heute habe ich Lust zum Lamentieren).
"array of" ist Delphi-spezifisch. Ein new von C++ aus erzeugt kein "array of". Das API der DLL ist daher unbrauchbar.
Das von new erzeugte Objekt hat keine Laengeninformation, die Delphi zugreifen koennte.

Die uebliche Loesung ist das man erst per API-Funktion fragt wie viele Elemente denn kommen und dann einen Puffer dieser Groesse bereitstellt (hier von Delphi aus) und ihn dann ausfuellen laesst. SetupDiGetDeviceInterfaceDetail ist z. B. so eine Funktion bei Windows.

Will man in einer DLL dynamisch alloziierte Dinge zurueckliefern, so muss man immer eine Dealloziierungsfunktion bereitstellen. Es arbeiten ueblicherweise zwei Memorymanager. Einer im Hauptprogramm und einer in der DLL. Gibt man speicher vom einen im anderen frei, so sind schnell beide Memorypools korrupt und das Programm stuerzt ab. Man kann natuerlich mit einer win32-funktion alloziieren und freigeben, aber das ist meist ineffizient.
  Mit Zitat antworten Zitat
Benutzerbild von ste_ett
ste_ett

Registriert seit: 10. Sep 2004
Ort: Dülmen
464 Beiträge
 
Delphi 7 Professional
 
#4

Re: C++-DLL --> Delphi - dynamischer struct-Array?

  Alt 20. Jun 2007, 14:43
Änderungen:

1) "packed record" statt "record", da die DLL aus der C-Welt kommt
2) Definition und Deklaration eines typisierten Pointers ("PContactManagerSOAP_ContactType")
3) Funktionsdeklaration angepasst


Beim Aufrufen der Funktion wird in der DLL ein Array erstellt/umkopiert/etc, so dass die Variable auf das erste Array-Element zeigt.
Wie oben schon geschrieben, darf man kein "array of" nutzen!

ContactType zeigt auf das erste Element im Array. Anhand des Rückgabewertes (Name: count) kennt man die Anzahl der Elemente im Array und kann diese In eienr Schleife durchlaufen, in dem man den typisierten Pointer bei jedem Durchlauf weiterschiebt.



Delphi-Quellcode:
type
    PContactManagerSOAP_ContactType = ^ContactManagerSOAP_ContactType;
   ContactManagerSOAP_ContactType = packed record
// a: INT64;
// b: PChar;
      c: Integer;
   end;

function _ContactManagerSOAP_GetContactTypes(result: PContactManagerSOAP_ContactType) : Integer; cdecl; external '../DLL/ObjectWebservice.dll';

implementation

{$R *.dfm}

procedure TDataDisplayForm.btnGetContactTypesClick(Sender: TObject);
var
  ContactTypes: PContactManagerSOAP_ContactType;
  i, count: Integer;
begin
  count := _ContactManagerSOAP_GetContactTypes(ContactTypes);

  for i := 0 to count -1 do
  begin
    ShowMessage(IntToStr(ContactTypes^.c));
    Inc(ContactTypes);
  end;

// TODO:
// der DLL mitteilen, dass der Speicher wieder freigegeben werden kann
end;
Stefan
"Geht nicht!" ist keine Fehlerbeschreibung und "Hab ich schon versucht!" keine Antwort!

Hey, it compiles! Ship it!
  Mit Zitat antworten Zitat
Benutzerbild von SirThornberry
SirThornberry
(Moderator)

Registriert seit: 23. Sep 2003
Ort: Bockwen
12.235 Beiträge
 
Delphi 2006 Professional
 
#5

Re: C++-DLL --> Delphi - dynamischer struct-Array?

  Alt 20. Jun 2007, 14:46
wer gibt denn in dem Fall jetzt den Speicher frei? Ist keine gut durchdachte Variante (ist eben an die Ursprüngliche angelehnt). Es hat schon seinen Sinn das die win32-api das anders handelt. (siehe das von mir und Robert)
Jens
Mit Source ist es wie mit Kunst - Hauptsache der Künstler versteht's
  Mit Zitat antworten Zitat
Robert Marquardt
(Gast)

n/a Beiträge
 
#6

Re: C++-DLL --> Delphi - dynamischer struct-Array?

  Alt 20. Jun 2007, 14:54
Erstens stammt deine DLL aus der C++ Welt und zweitens hat packed nichts damit zu tun. Wie bei Delphi wird das Alignment von Strukturen per Compilerswitch oder Pragma in den Sourcen eingestellt. Das C++ von Microsoft hat weitestgehend die gleichen Defaults wie Delphi beim Alignment. Man weiss aber nie wie es in einer fremden DLL eingestellt ist. Das muss dokumentiert werden.
  Mit Zitat antworten Zitat
Benutzerbild von ste_ett
ste_ett

Registriert seit: 10. Sep 2004
Ort: Dülmen
464 Beiträge
 
Delphi 7 Professional
 
#7

Re: C++-DLL --> Delphi - dynamischer struct-Array?

  Alt 20. Jun 2007, 14:55
Zitat von SirThornberry:
wer gibt denn in dem Fall jetzt den Speicher frei? Ist keine gut durchdachte Variante (ist eben an die Ursprüngliche angelehnt). Es hat schon seinen Sinn das die win32-api das anders handelt. (siehe das von mir und Robert)
Das ist klar, aber welche Variante ist wahrscheinlicher?

1) Die DLL wird umprogrammiert.

2) Man muss es nehmen wie es ist.

?

Freigeben des Speichers muss noch erledigt werden, s. Kommentar im Code.


Ich persönlich finde die Vorgehensweise bei der Win32-API auch bei Weitem besser!
Stefan
"Geht nicht!" ist keine Fehlerbeschreibung und "Hab ich schon versucht!" keine Antwort!

Hey, it compiles! Ship it!
  Mit Zitat antworten Zitat
Legato

Registriert seit: 31. Mai 2007
6 Beiträge
 
Delphi 2006 Enterprise
 
#8

Re: C++-DLL --> Delphi - dynamischer struct-Array?

  Alt 20. Jun 2007, 15:00
Hallo ihr,

vielen Dank - für beide Varianten.

Deine Methode funktioniert toll, SirThornberry - nur der doppelte Aufruf ist unschön: Meine Funktion ruft eine Funktion eines Webservice auf, und das müsste ich dann entweder doppelt machen oder zwischenspeichern.

Robert, dann wirst du vermutlich noch viel bei mir zu lamentieren haben - ich programmiere erst seit ungefähr 2 Monaten Delphi (und das ist auch das erste Mal, dass ich eine DLL baue, von daher wusste ich noch nicht mal, wo es genau scheitert). Find es angesichts dieser Zeit noch nicht besonders erschreckend, schließlich lerne ich noch. Übrigens danke, dass du trotzdem geantwortet hattest.

Ah, und zu letzterem - meine DLL, kann sie frei ändern. Von daher muss ich sie nicht "nehmen wie sie ist".

Mit liebem Gruß,
Tobias
Tobias
The highest sounds are hardest to hear.
Going forward is a way to retreat.
Great talent shows itself late in life.
Even a perfect program still has bugs.
  Mit Zitat antworten Zitat
Benutzerbild von SirThornberry
SirThornberry
(Moderator)

Registriert seit: 23. Sep 2003
Ort: Bockwen
12.235 Beiträge
 
Delphi 2006 Professional
 
#9

Re: C++-DLL --> Delphi - dynamischer struct-Array?

  Alt 20. Jun 2007, 15:06
ok, doppelt aufrufen musst du nicht unbedingt, du kannst auch gleich genügend speicher mitgeben.
Delphi-Quellcode:
var
  MeineElemente: Array of Element;
  Anzahl : Integer;
begin
  Anzahl := 1000; //Wie groß die Zahl ist weißt nur du, ich weiß nicht wieviel werte deine dll maximal liefert
  SetLength(MeineElemente, Anzahl);
  Anzahl := Dll_GibWerte(@MeineElemente[0], Anzahl);
  //Prüfen ob der Speicher gereicht hat, wenn nicht machen wir das ganze diesmal mit der richtigen Anzahl
  if (Anzahl < Length(MeineElemente) then
  begin
    SetLength(MeineElemente, Anzahl);
    Dll_GibWerte(@MeineElemente[0], Anzahl);
  end;
  [...]
end;
Jens
Mit Source ist es wie mit Kunst - Hauptsache der Künstler versteht's
  Mit Zitat antworten Zitat
Legato

Registriert seit: 31. Mai 2007
6 Beiträge
 
Delphi 2006 Enterprise
 
#10

Re: C++-DLL --> Delphi - dynamischer struct-Array?

  Alt 20. Jun 2007, 16:29
Huhu SirThornberry,

vielen Dank für deine Hilfe. Die Idee ist gut.

Gruß,
Tobias
Tobias
The highest sounds are hardest to hear.
Going forward is a way to retreat.
Great talent shows itself late in life.
Even a perfect program still has bugs.
  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 21:39 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