Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Funktionsaufruf von C nach Delphi übersetzen (https://www.delphipraxis.net/96838-funktionsaufruf-von-c-nach-delphi-uebersetzen.html)

Daniel 31. Jul 2007 15:56


Funktionsaufruf von C nach Delphi übersetzen
 
Moin,

ich habe Schwierigkeiten, eine C-DLL aus Delphi (Win32) heraus anzusprechen. Ich habe zu der DLL eine Header-Datei, von der ich annehmen kann, dass sie korrekt ist.

In der Header-Datei sind zum Einen Strukturen (struct) definiert, die ich in packed records überführt habe und die Typen anhand einschlägiger Dokumentation übersetzt habe. Da sind auch wenig schräge Sachen dabei gewesen, es ging um char* -> PChar, double -> Double und long -> Longint, teilweise auch als Arrays.

Nun verbleiben noch drei Funktionsdeklarationen, die vom strukturellen Aufbau der identisch sind, daher hier nur einer dieser Aufrufe als Beispiel:

Code:
extern void __declspec (dllexport) FUNKTIONSNAME(datentyp1*,datentyp2*,long*);
ich habe daraus das Folgende in Delphi gemacht:

Delphi-Quellcode:
procedure(var _1 : datentyp1; var _2: datentyp2; var _3: LongInt) cdecl;
Bedauerlicherweise bekomme ich nur eine Schutzverletzung aus der DLL. Ich gehe davon aus, dass meine Daten nicht richtig in der DLL ankommen, da die DLL selbst mit einer ganzen Reihe an Plausibilitäts-Prüfungen versehen ist. Wenn ich also in den Datenstrukturen Felder falsch initialisiere, so sollte ich Fehlercodes erhalten, aber keine Schutzverletzung.


Irgtendwelche Ideen zu meiner Übersetzung?

SirThornberry 31. Jul 2007 16:14

Re: Funktionsaufruf von C nach Delphi übersetzen
 
aus meiner Sicht völlig korrekt übersetzt. An welcher Adresse beim lesen/schreiben von welcher Adresse kommt die AV?

Daniel 31. Jul 2007 16:26

Re: Funktionsaufruf von C nach Delphi übersetzen
 
hm. Danke für die Bestätigung meiner Übersetzung. Aber Deine Frage nach der Adresse könnte auf die Ursache meines Problems hinweisen.
Zitat:

'Access violation at address 1000F624 in module 'TARIF.DLL'. Write of address 00000000' aufgetreten.
Wenn ich jetzt im Hinterkopf habe, dass die Datenstrukturen unter anderem aus PChars bestehen, könnte der Fehler daraus resultieren, dass ich die nicht alle initialisiert habe, weil ich einie für optional hielt. Ich habe zu Anfang ein FillChar( Variable, SizeOf(VariablenTyp), 0 ) drüber laufen lassen.


*seufz* Na gut, dann schaue ich mal, was ich hier tun könnte. :-)

Robert Marquardt 31. Jul 2007 16:32

Re: Funktionsaufruf von C nach Delphi übersetzen
 
Probier stdcall statt cdecl. Die C Deklaration ist nicht eindeutig, da Projektoptionen die Calling Convention veraendern koennen.
Es ist bei C Deklarationen nicht erkennbar ob man "datentyp * param1" zu "var Param1: datentyp" oder "param1: Pdatentyp" uebersetzen soll. Nur die Dokumentation kann da helfen. Ein Zeiger kann in C Call-by-reference oder Zeiger auf den Beginn eines Arrays bedeuten. Nur die Dokumentation kann da helfen.
"long *" deutet aber ein "var Param3: Longint" an und die uebliche Bedeutung das man eine Arraylaenge darin platziert und der Aufruf dann mit der Anzahl ausgefuellter Array-Elemente zurueckkommt.

Zeig mal wie du die Funktion aufrufst.

Daniel 31. Jul 2007 16:38

Re: Funktionsaufruf von C nach Delphi übersetzen
 
Zitat:

Zitat von Robert Marquardt
Zeig mal wie du die Funktion aufrufst.

Vielen Dank für Deine Antwort, ich werde morgen weiteren Code veröffentlichen können, jetzt bin ich auf dem Sprung zu meinem Fris... Hair-Stylisten und zuhause habe ich noch keinen Zugang zum Internet (grummelt auf eine Telefongesellschaft mit einem A am Anfang).

Robert Marquardt 31. Jul 2007 16:40

Re: Funktionsaufruf von C nach Delphi übersetzen
 
Du sollt die Loesung nicht an den Haaren herbeiziehen!

sirius 31. Jul 2007 16:43

Re: Funktionsaufruf von C nach Delphi übersetzen
 
Zitat:

(grummelt auf eine Telefongesellschaft mit einem A am Anfang).
Vorsicht! Manche Telefongesellschaften müssen den Draht zu deiner Wohnung erst von einer anderen TTelefongesellschaft kaufen (bzw. mieten). Und dieses Kauf-Interface hat ne ganze Menge sleeps mit in der Implementation.
Kann alles ein, muss aber nicht

SirThornberry 31. Jul 2007 17:10

Re: Funktionsaufruf von C nach Delphi übersetzen
 
das schreiben an Adresse 0 deutet wirklich darauf hinn das du einen Pointer ins nichts übergibst oder deine Struktur irgendwo einen Pointer ins nichts hat obwohl da ein Pointer auf Speicher erwartet wird.
Oftmals hilft es dann das CPU-Debug-Window mit einzuschalten und dann in die DLL rein zu steppen.

Christian Seehase 31. Jul 2007 22:01

Re: Funktionsaufruf von C nach Delphi übersetzen
 
Moin Zusammen,

Zitat:

Zitat von Robert Marquardt
Es ist bei C Deklarationen nicht erkennbar ob man "datentyp * param1" zu "var Param1: datentyp" oder "param1: Pdatentyp" uebersetzen soll.

Nur kann man nichts falsch machen, wenn man bei solchen Parametern grundsätzlich "param1: PDatentyp" nimmt, wohingegen die var-Variante, je nachdem, was als Wert möglich ist, durchaus Probleme machen kann.

Zitat:

Zitat von Daniel
jetzt bin ich auf dem Sprung zu meinem Fris... Hair-Stylisten

Zitat:

Zitat von Robert Marquardt
Du sollt die Loesung nicht an den Haaren herbeiziehen!

:mrgreen: :thumb:

(er lässt ja auch herbeiziehen ;-))


Zitat:

Zitat von Daniel
und zuhause habe ich noch keinen Zugang zum Internet (grummelt auf eine Telefongesellschaft mit einem A am Anfang).

Zitat:

Zitat von sirius
Manche Telefongesellschaften müssen den Draht zu deiner Wohnung erst von einer anderen TTelefongesellschaft kaufen

Die haben halt noch nicht den richtigen Draht zu Dir :mrgreen:

Luckie 31. Jul 2007 22:15

Re: Funktionsaufruf von C nach Delphi übersetzen
 
Zitat:

Zitat von Daniel
Wenn ich jetzt im Hinterkopf habe, dass die Datenstrukturen unter anderem aus PChars bestehen,

Hast du auch Speicher für die PChars reserviert?

Christian Seehase 31. Jul 2007 22:34

Re: Funktionsaufruf von C nach Delphi übersetzen
 
Moin Michael,

Zitat:

Zitat von Luckie
Zitat:

Zitat von Daniel
Wenn ich jetzt im Hinterkopf habe, dass die Datenstrukturen unter anderem aus PChars bestehen,

Hast du auch Speicher für die PChars reserviert?

Zitat:

Zitat von Daniel
könnte der Fehler daraus resultieren, dass ich die nicht alle initialisiert habe, weil ich einie für optional hielt. Ich habe zu Anfang ein FillChar( Variable, SizeOf(VariablenTyp), 0 ) drüber laufen lassen.

so geht der Satz weiter... ;-)

Daniel 1. Aug 2007 08:36

Re: Funktionsaufruf von C nach Delphi übersetzen
 
Offensichtlich ist's doch haariger ...

Die Strukturen sehen wie folgt aus - im Original nur etwas länger, aber nur mit PChars, LongInts und Doubles:

Delphi-Quellcode:
TTarifEingabe = packed record
  tarifname: PChar;
  tarifkennung: PChar;
  geburtsdatum: PChar;
  geschlecht: LongInt;
  versicherungsbeginn: PChar;
  beitrag: Double;
  waehrung: LongInt;
  beitragszahlungsweise: LongInt;
end;
Die ersten beiden Parameter für die Funktion nennen sich TarifEingabe und TarifAusgabe. Der dritte Parameter sollte dann der Status sein, da ich einen solchen Status erhalte, nicht jedoch in den Strukturen selbst.

Mein Aufruf schaut wie folgt aus - die Belegung der Felder habe ich hier für diesen Beitrag weggelassen, aber wie es scheint, sollte ich als nächstes versuchen, für jeden der PChars Speicher zu reservieren.

Delphi-Quellcode:
procedure MachWas;
var TEin : TTarifEingabe;
    TAus : TTarifAusgabe;
    stat : longint;
begin
  FillMemory( @TEin, SizeOf(TTarifEingabe), 0 );
  FillMemory( @TAus, SizeOf(TTarifAusgabe), 0 );

  calcFonds( TEin, TAus, stat );
end;

Robert Marquardt 1. Aug 2007 09:16

Re: Funktionsaufruf von C nach Delphi übersetzen
 
Poste doch mal das ganze .h File hier und gleich noch deine Konversion dazu.

Daniel 1. Aug 2007 10:19

Re: Funktionsaufruf von C nach Delphi übersetzen
 
Genau das kann ich aktuell leider nicht tun.

Es handelt sich um die Schnittstelle zu einem Tarifrechner einer Versicherungsgesellschaft. Wenn die das Wort 'Veröffentlichen' schon hören, dann sind sie zu gleichen Teilen empört und entsetzt. Das .h-File an sich wäre zwar in meinen Augen kein kritischer Teil, aber das müsste ich einem aus einer Fachabteilung (= Nicht-Informatiker) klarmachen und dieses Vorhanebn wäre zum Scheitern verurteilt.

Ich habe stattdessen um einen Beispielaufruf in C gebeten. Aus dem Code sollte deutlich werden, wie die Strukturen bestückt werden und sich um den Speicher kümmert.

:-)

hoika 1. Aug 2007 10:23

Re: Funktionsaufruf von C nach Delphi übersetzen
 
Hallo,

ein FillChar initialisiert keine PChars !.
Das sind ja nur Pointer.

wenn ich in der Dll ein

strcpy(TarifEingabe->tarifname, "bla") mache,
gibt es eine Schutzverletzung, weil durch dein FillChar der Pointer NIL (NULL) ist.

Du musst per GetMem für die PChars Speicher anfordern,
wie viel, müsste in der Header-Datei stehen.
Wenn nicht, ausprobierne (255 ist ein guter Start).

Nach dem Aufruf aber auch wieder freigeben ...


Heiko

sirius 1. Aug 2007 10:40

Re: Funktionsaufruf von C nach Delphi übersetzen
 
und dann gäbe es noch die Möglichkeit eines statischen array of char

Daniel 1. Aug 2007 10:52

Re: Funktionsaufruf von C nach Delphi übersetzen
 
Das grundlegende Problem scheint gelöst. Es lag an den PChars, für die ich explizit Speicher mit StrAlloc() reservieren musste. Die Inhalte habe ich dann via StrPCopy() reinkopiert. Da ich keine Ahnung / Dokumentation habe, wie groß die zu erwartenden Werte sind, habe ich pauschal 1 KB pro PChar reserviert. Das scheint zu langen.

Wieso löst sich so ein Knoten eigentlich immer genau dann, wenn man gerade beim Kunden einen Auftrag an dessen IT-Abteilung rausgegeben hat? *seufz*

Im Moment scheinen die verbleibenden Probleme bei der Bestückung der Strukturen zu liegen. Ich erhielt schon brauchbare Fehlercodes aus dem dritten Parameter. Die gelieferten Fehlernummern stimmten mit den Ursachen überein. Bisschen holperig ist's noch, ich erhalte jetzt aber keine Schutzverletzungen mehr, sondern nur noch eine EDivisionByZero aus dem Tarifrechner selbst. Ich denke und hoffe, das rührt bloß daher, dass ich nicht alle benötigten Felder mit sinnvollen Werten belegt habe. Das zum Thema Prüfung der Plausibilitäten.



@Heiko: Dass ich für die PChars den Speicher separat zu reservieren habe, schrieb ich doch schon. ;-)

Robert Marquardt 1. Aug 2007 11:38

Re: Funktionsaufruf von C nach Delphi übersetzen
 
Sag den Idioten mal (hoeflich natuerlich :)) sie sollen ein vernuenftiges API bauen. Was Du bisher gezeigt hast deutet darauf hin das beim Design und der Dokumentation ein Totalversager vorliegt. Man macht keine PChars in ein Record in das Daten ausgegeben werden. Da nimmt man Arrays, damit man nicht extra Alloziieren muss und damit die Puffergroessen definiert sind. abgesehen davon sollte man die nicht so neue C-Syntax mit Parameternamen in den Deklarationen beherrschen.


Alle Zeitangaben in WEZ +1. Es ist jetzt 02:22 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