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.dll'
name '
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