Ergebnis 1 bis 6 von 6

Thema: record/struct als Rückgabewert eine DLL-Funktion

Hybrid-Darstellung

Vorheriger Beitrag Vorheriger Beitrag   Nächster Beitrag Nächster Beitrag
  1. #1
    Zitat Zitat von Ineluki Beitrag anzeigen
    hm ... schwierig .. Intersprachenoperabilitaet ist etwas, um das ich mich lange Zeit gedrueckt habe ...

    Zum einen .. Im Header definierst du keinen Variablentyp TMyRecord, sondern einen struct vom Typ MyRecord und eine Variable TMyRecord vom typ MyRecord.
    (Falls ich gerade Bloedsinn schreibe, bitte ignorieren .. bin noch etwas Schlaftrunken ...)

    Zum anderen solltest du mal nachsehen, ob stdcall fuer die Uebergabe das nonplusultra ist. Sowohl in Pascal als auch in C/++ muessen beide Funktionen die selbe Aufrufkonvention haben. Sprich ob sie selber den Stack aufraeumen, in welcher Reihenfolge sie Parameter uebergeben, etc.

    Im Zweifelsfall machs, wie alle, und arbeite mit Handles. Erstelle in der Funktion einen Pointer auf deinen Record im Heap, gib den als funktionswert zurueck und mache eine Funktion, die den als Parameter bekommt und es am ende Frei gibt. Effektiv ist die Arbeit mit Interfaces auch nichts anderes ...
    Allesklar, danke. Die Aufrufkonvention habe ich total vergessen. Hatte irgendwie im Kopf, dass bei C/++ stdcall Standart wäre. Ich habe nun die Variabeldeklaration weggelassen und einfach nur den Type definiert. Nun geht es.

    Nun meine Frage, was ist denn die Standart-Aufrufkonvetion in C/++? Scheinbar mag mein Compiler die .lib-Datei nicht mehr, seitdem ich die Aufrufkon. auf __stdcall gesetzt habe. Dahher versuche ich lieber die Funktionen entsprechend in Pascal so zu exportieren, dass C/++ am wenigsten Probleme machen.

  2. #2
    Das kommt auf die Funktion an ... stdcall ist glaub ich Standard fuer Windows API funktionen. Normales C/++ verwendet iirc cdecl.

    Im Zweifelsfalle auf keine Standards verlassen und immer angeben, was genau du haben willst. Du kannst in C/++ genau so Funktionen mit Pascal kodierung verwenden, wie du in Pascal Funktionen aus C/++ oder der API benutzen kannst. Der Linker muss nur genau wissen, welche der etwa 5 bis 10 verschiedenen Standards du nun benutzt. Und natuerlich sollten die auf beiden Seiten gleich sein.

    Zitat Zitat
    Die Industrie liebt Standards. Deswegen hat jede Firma ihren eigenen.

  3. #3
    Zitat Zitat von Ineluki Beitrag anzeigen
    Im Header definierst du keinen Variablentyp TMyRecord, sondern einen struct vom Typ MyRecord und eine Variable TMyRecord vom typ MyRecord.
    (Falls ich gerade Bloedsinn schreibe [...])
    Ja, tust du. :P

    Code:
    typedef struct MyRecord {
        int A;
        int B;
    } TMyRecord;
    Hier wird die Struktur MyRecord definiert und ihr "Alias" TMyRecord. TMyRecord ist aber keine Definition einer Variablen im Speicher.


    @Desmulator:

    In Win32 ist die Aufrufkonvention für exportierte Funktionen aus DLLs __stdcall und das ist Pflicht. Die Definitionen dieser Funktionen innerhalb der DLLs und die Deklarationen in den ABIs müssen selbstverständlich in der Aufrufkonvention übereinstimmen. Man sollte sich jedoch nicht darauf verlassen, dass jeder Compiler/jedes Projekt dieselben Einstellungen besitzt und die Aufrufkonvention explizit angeben.

    Die Aufrufkonvention ist allerdings nur eine Hürde von ABIs, eine weitere wäre die Speicherausrichtung. Wenn du verschiedene Compiler zulassen möchtest (das gilt sowohl für die FreePascal-Compiler, als auch für die C/C++-Compiler), musst du sicherstellen, dass Padding für zusammengesetzten Datentypen äquivalent aussieht. Eine Möglichkeit dies zu tun wäre Padding ganz auszuschalten, indem du die Ausrichtung während der Deklaration auf '1' setzt, allerdings mit dem bitteren Nachgeschmack, dass die Anweisungen dafür compilerabhängig sind und, dass fehlende Speicherausrichtung die Performance drücken kann, falls man mit den nicht ausgerichteten Datentypen in performancekritischen Schleifen arbeitet.
    Für das letztere Problem, falls es eintreten kann, kannst du einfach Objekte mit nicht ausgerichteten Membern in Objekte mit ausgerichteten Membern umwandeln.
    Für das erstere Problem musst du mit Präprozessordirektiven den Compiler feststellen und z.B. wie folgt (in C/C++) auflösen:

    Code:
    #ifdef _MSC_VER // VC++
    #pragma pack(push, 1)
    struct STRUCT_NAME
    {
        STRUCT_BODY
    };
    #pragma pack(pop)
    #else // assume gcc
    struct STRUCT_NAME
    {
        STRUCT_BODY
    } __attribute__((packed));
    #endif
    Was DLLs angeht, solltest du unbedingt auch aufpassen die DLL-Boundary nicht zu verletzen, also Daten, die innerhalb der DLL alloziert wurden auch innerhalb der DLL wieder freigeben.

    Geändert von Kyuu (27.06.2009 um 16:50 Uhr)

  4. #4
    Zitat Zitat von Kyuu Beitrag anzeigen
    Ja, tust du. :P

    Code:
    typedef struct MyRecord {
        int A;
        int B;
    } TMyRecord;
    Hier wird die Struktur MyRecord definiert und ihr "Alias" TMyRecord. TMyRecord ist aber keine Definition einer Variablen im Speicher.
    Ah ... ich hatte das typedef ueberlesen. Ohne das Typedef haette er eben die Klasse MyRecord definiert und gleichzeitig eine Variable TMyRecord erzeugt. Wie gesagt, ich hab damals meinen Post im Halbschlaf verfasst, sorry.

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •