AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Fragen zur API-Entwicklung

Offene Frage von "Sherlock"
Ein Thema von blackdrake · begonnen am 23. Aug 2011 · letzter Beitrag vom 29. Aug 2011
Antwort Antwort
blackdrake

Registriert seit: 21. Aug 2003
Ort: Bammental
618 Beiträge
 
Delphi 10.3 Rio
 
#1

AW: Fragen zur API-Entwicklung

  Alt 23. Aug 2011, 23:32
Hallo omata,

Meinst du sowas?

Delphi-Quellcode:
unit MyAPI2;
 
interface
 
uses MyAPI1; // enthält Deklaration von TMyType

// Oder:
// {$I MyAPI1.inc}

{$EXTERNALSYM MyFunction}
function MyFunction: TMyType; cdecl;
 
implementation
 
function MyFunction; external 'MyDll.dllname 'MyFunction';
 
end.
Das müsste zwar funktionieren, aber es ist ja nicht sonderlich "schön", oder? Die Leute würden sich dann wundern, wieso ich die API in 2 PAS-Dateien verschachelt habe. Außerdem ist es ja schon verwunderlich wieso man API1.pas und API2.pas braucht... Mein Vorbild ist beispielsweise die Windows.h bzw. Windows.pas, die ja alles in 1 H/PAS Datei enthält.

Gruß
Daniel
Daniel Marschall

Geändert von blackdrake (24. Aug 2011 um 15:29 Uhr) Grund: [delphi]-tag anstelle [code]
  Mit Zitat antworten Zitat
blackdrake

Registriert seit: 21. Aug 2003
Ort: Bammental
618 Beiträge
 
Delphi 10.3 Rio
 
#2

AW: Fragen zur API-Entwicklung

  Alt 24. Aug 2011, 00:16
/Update:

Ich habe nun gemäß deines Vorschlags folgende Struktur verwendet. Das ist wohl die Best-Practise, die man mit Delphi hinbekommen kann:

Die Alternative mit *.inc ist nicht so gut, da man dann auf das syntaxhighlighting verzichten müsste.

Code:
Gemeinsame Typdeklarationen - myapi_h.pas:

   interface
      type declarations...

   implementation
      nichts

API Entwicklung - myapi_impl.pas:

   interface
      uses myapi_h.pas;
      Funktionen vollständig deklarieren (REDUNDANT*)

   implementation
      Funktionen implementieren

API Entwicklung - myapi.dpr (dll):

   uses myapi_impl.pas
   exports funktionsnamen;
   begin
   end.

API Benutzung - myapi.pas:

   interface
      uses myapi_h.pas;
      Funktionen vollständig deklarieren (REDUNDANT*)
      Zusätzlich: {$EXTERNALSYM} für alle funktionen

   implementation
      Funktionen importieren aus DLL

API Benutzung - myprogram.dpr (exe):

   uses myapi.pas
   begin
      // Nutzen der Funktionen
   end.
* = Schade ist, dass die kompletten Funktionsdeklarationen nun in myapi.pas und myapi_impl.pas immer noch redundant sind. In C könnte ich die Funktions-Köpfe einfach in die *.h schreiben und sie später in *.c entweder implementieren oder per Library-Verweis nutzen. Kann man da noch was rausholen?

Gruß
Daniel
Daniel Marschall

Geändert von blackdrake (24. Aug 2011 um 02:14 Uhr)
  Mit Zitat antworten Zitat
omata

Registriert seit: 26. Aug 2004
Ort: Nebel auf Amrum
3.154 Beiträge
 
Delphi 7 Enterprise
 
#3

AW: Fragen zur API-Entwicklung

  Alt 24. Aug 2011, 09:06
Hier mal mein Beispiel...
Angehängte Dateien
Dateityp: zip API.zip (2,3 KB, 6x aufgerufen)
  Mit Zitat antworten Zitat
blackdrake

Registriert seit: 21. Aug 2003
Ort: Bammental
618 Beiträge
 
Delphi 10.3 Rio
 
#4

AW: Fragen zur API-Entwicklung

  Alt 24. Aug 2011, 15:26
Hallo,

danke für dein Beispiel. So habe ich es im großen und Ganzen auch.

Die Unterscheidung

{$IFNDEF LINUX} stdcall {$ELSE} cdecl {$ENDIF};

scheint nützlich zu sein. Ich schaue mir das mal genauer an.

Allerdings sind bei dir die Funktionsköpfe auch redundant. Ich würde die am liebsten nach C-Manier in die "MyAPI_H" Datei pflanzen (mit einer Art Unit-Übergreifenden "forward"), aber dann möchte Delphi, dass ich sie auch gleich definiere.

API Benutzung
Delphi-Quellcode:
unit MyAPI;

interface

uses
  MyAPI_H;

{$EXTERNALSYM function_1}
{$EXTERNALSYM function_2}
...
{$EXTERNALSYM function_n}

// Redundante Information: Funktionsköpfe
// Nach C-Manier gehören die in die "H"-Datei
procedure function_1(args: cardinal); stdcall;
procedure function_2(args: cardinal); stdcall;
...
procedure function_n(args: cardinal); stdcall;

implementation

procedure function_1; external 'mydll.dllname 'function_1';
procedure function_2; external 'mydll.dllname 'function_2';
...
procedure function_n; external 'mydll.dllname 'function_n';

end.
API Entwicklung
Delphi-Quellcode:
unit MyAPI_Impl;

interface

uses
  MyAPI_H;

// Redundante Information: Funktionsköpfe
// Nach C-Manier gehören die in die "H"-Datei
procedure function_1(args: cardinal); stdcall;
procedure function_2(args: cardinal); stdcall;
...
procedure function_n(args: cardinal); stdcall;

implementation

// Implementierung

end.
Ich denke, dafür bietet die Pascal-Strukturierung keine Lösung (mit Ausnahme einer *.inc, was ich nicht so toll finde wegen fehlendem Syntax-Highlighting)

Gruß
Daniel
Daniel Marschall

Geändert von blackdrake (24. Aug 2011 um 15:29 Uhr) Grund: [delphi]-tag anstelle [code]
  Mit Zitat antworten Zitat
Florian Hämmerle
(Gast)

n/a Beiträge
 
#5

AW: Fragen zur API-Entwicklung

  Alt 24. Aug 2011, 15:43
Hab ich mich auch erst kürzlich gefragt: Link

mfg Florian
  Mit Zitat antworten Zitat
blackdrake

Registriert seit: 21. Aug 2003
Ort: Bammental
618 Beiträge
 
Delphi 10.3 Rio
 
#6

AW: Fragen zur API-Entwicklung

  Alt 28. Aug 2011, 05:02
Die Lösungen haben leider doch nicht funktioniert.

Meine vorherige Lösung hatte den Schwachpunkt, dass man im Anwendungsfall "MyAPI.pas" (für Funktionen) UND "MyAPI_H" (für Typen) einbinden muss. Das ist eine Unit zu viel. Im Gegensatz zu C scheint Delphi sehr unflexibel zu sein, da die Implementierung immer an das Interface gekoppelt ist...

Die Include-Lösung ist noch katastrophaler. Delphi prüft nämlich zuerst die Funktionen und bindet danach erst die Include ein. Er sagt also, dass er "TMyRecord" bei "function x: TMyRecord" nicht kennt, obwohl der Typ in der Include-Datei drin steht. Schreibt man vor dem {$I} noch ein "type", kommt Delphi ebenfalls durcheinander weil es zu Syntaxfehlern kommt. (Die Include enthält types und consts)...

Ich habe nach extrem langer Zeit die Lösung gefunden:


Die Unit MyAPI.pas enthält alles was benötigt wird. Alle Typen sowie die DLL-Importe. Diese PAS wird im Anwendungsfall verwendet - logisch.

Für die DLL-Entwicklung wird MyAPI_Impl.pas entworfen. Es use'd die MyAPI.pas . Anschließend werden die Funktionen, die vorher aus der DLL importiert wurden nochmal definiert und implementiert. Aus irgendeinem Grund meckert Delphi NICHT wegen einer doppelten Deklaration!!! (Stand: Turbo Delphi, unbekannt ob Verhalten auch in Delphi 7)

Durch das Smart-Linking wird die DLL auch nicht sich selbst importieren (Import Table), da auf die Import-Funktionen nicht zugegriffen wird. Stattdessen werden die Funktionen exportiert, die implementiert wurden.

Kurz: Bei der API-Entwicklung importiert man die Funktionen _UND_ implementiert sie nochmal. Delphi "entscheidet" sich dann für die Implementierung und gibt keinen Konflikt aus; auch kein overload ist nötig.




Delphi-Quellcode:
unit MyAPI;

interface

type
  TMyRecord = record
    foo: PAnsiChar;
  end;

function myfunc: TMyRecord; stdcall;

implementation

// Die DLL importiert sich dank Smart-Linking nicht selbst
function myfunc: TMyRecord; stdcall; external 'MyDLL.dllname 'myfunc';

end.
---

Delphi-Quellcode:
unit MyAPI_Impl;

interface

uses
  MyAPI;

// Seltsam, seltsam... Kein Namenskonflikt mit MyAPI.myfunc (imported)!
function myfunc: TMyRecord; stdcall;

implementation

function myfunc: TMyRecord;
begin
  result.foo := 'bar';
end;

end.
---

Delphi-Quellcode:
library MyDLL;

uses
  MyAPI_Impl in 'MyAPI_Impl.pas';

exports
  myfunc;

begin
end.
---

Delphi-Quellcode:
program MyProg;

uses
  MyAPI in 'MyAPI.pas';

var
  x: TMyRecord;

begin
  x := myfunc;
end.

Es ist seltsam, dass dieses merkwürdige Verhalten (Symbolkonflikt, der keiner ist) nicht dokumentiert ist. Auch ist es seltsam, dass noch niemand zuvor das Problem der Coderedundanz bei DLL-Entwicklung mit gleichzeitiger Nutzung gestoßen ist.


===> Kann bitte jemand bestätigen, dass dieses Verhalten auch in Delphi 6 und 7 existiert? Ich möchte den Code wegen OpenSource gerne bis mindestens D6 kompatibel halten.






Offen sind noch meine Fragen 2 und 3. Weiß denn niemand Rat?


Gruß
Daniel Marschall
Daniel Marschall
  Mit Zitat antworten Zitat
Benutzerbild von sx2008
sx2008

Registriert seit: 15. Feb 2008
Ort: Baden-Württemberg
2.332 Beiträge
 
Delphi 2007 Professional
 
#7

AW: Fragen zur API-Entwicklung

  Alt 28. Aug 2011, 12:30
Jeder einigermassen moderne Compiler kann heutzutage COM/ActiveX-Bibliotheken einbinden.
Wenn du eine Schnittstelle (API) als Typbibliothek auslieferst, dann sind sämtliche Metadaten bekannt.
Ein fremder Compiler/IDE liest einfach nur die Typbibliothek ein und kennt anschliesend alle Funktionen, Parameter, Konstanten, Strukturen und Schnittstellen.

COM/ActiveX ist ab Delphi 5 aufwärts sinnvoll einsetzbar (mit Einschränkungen D4).
  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 11:17 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