PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : C++ to Delphi: DLLs nutzen


Kennung Eins
2003-03-03, 17:57:48
Kann mir jemand helfen, dieses
(..)
#define BROT_CORE_API __declspec(dllimport)
(..)aus Zeckis Brotmaschinen-Interface (http://home.t-online.de/~zsack/brot.zip) nach Delphi übersetzen?
Ich hab keine Idee, wie ich das in Delphi ausdrücken kann :(

Ok, es geht um eine Konstante BROT_CORE_API, aber was für ein Wert wird dieser zugewiesen?

Demirug
2003-03-03, 18:05:20
Mit __declspec(dllimport) sagt man dem Compiler das die folgende Funktion in einer DLL liegt.

Bei Delphi macht man das mit external 'DLLname' index "nummer des elements'; Das __declspec(dllimport) entfällt dadurch.

Eine gute Anleitung zum umsetzten von C Header nach Delphi:

http://www.drbob42.com/delphi/headconv.htm

Kennung Eins
2003-03-03, 18:07:33
Ah, diese Seite hatte ich auch schon gefunden, jedoch nicht erkannt, daß das schon ist, was ich suche.

Ok, nun Fragen dazu:

Was ist der Index?
Was bedeutet "Nummer des Elements"?

[edit]
Ist folgendes äquivalent zu dem C++ Code?
function BROT_CORE_API: Integer; stdcall;
external 'brot_core.dll' name 'BROT_CORE_API';

Demirug
2003-03-03, 18:43:31
Zuerst brauchst du einen "Dependency Viewer". Dieser müsste eigentlich funktionieren: http://www.volweb.cz/pvones/delphi/index.htm

Damit muss man dann die DLL öffnen und bei den Exports die gewüschten Funktionen suchen. Die Nummer die du suchst sollte normalerweise in der Spalte "Ordinal" stehen.

Kennung Eins
2003-03-03, 18:53:38
Hmm ... irgendwas scheint an dieser Konstante BROT_CORE_API anders zu sein.
Diese ist ja keine Exportierte Funktion (so sehe ich das zumindest), sondern eben nur eine Konstante.
Ich hab den Dependency Viewer angeschmissen, er listet die BROT_CORE_API nicht auf (wohl weil es keine exportierte Funktion ist).

[edit]
Ein paar mehr Zeilen aus dem SRC:

#ifdef BROT_CORE_EXPORTS
#define BROT_CORE_API __declspec(dllexport)
#else
#define BROT_CORE_API __declspec(dllimport)
#endif

#define BROT_CALL

#ifdef BROT_CORE_EXPORTS
class Context;
typedef Context* bc_context;
#else
typedef unsigned int bc_context;
struct Place {ubyte dont_touch[100];};
#endif


#define BROT_FUNCTION(name,return_type,argument_list) BROT_CORE_API return_type BROT_CALL name argument_listDer Wert der Variablen wird nur ein einziges mal (letzte Zeile) benötigt. Kommt man da vielleicht anders ran? (oder sollte ich das vielleicht Zecki fragen?)

Kennung Eins
2003-03-03, 19:18:58
Ach shice, sorry, das Problem hat sich von selbst erledigt.

Das, was ich da tun wollte ist für mich überhaupt nicht von Belang :bonk: Ich versuchte da was zu importieren, was aber überhaupt nicht Sinn und Zweck des Ganzen war.

zeckensack
2003-03-03, 21:09:19
Ach hier haste auch was aufgemacht! :D

Ich hoffe die zahlreichen PMs waren hilfreich ;)

Xmas
2003-03-03, 21:12:43
Um das mal noch zu klären:

#define BROT_CORE_API __declspec(dllexport)

bedeutet lediglich, dass der Text 'BROT_CORE_API' überall im folgenden durch '__declspec(dllexport)' ersetzt wird. Dieses Text-Ersetzen macht der C-Preprozessor, beim Compiler kommt nie ein 'BROT_CORE_API' an.

__declspec(dllexport) ist wiederum keine Funktion, sondern ein Funktionsmodifizierer, ähnlich wie z.B. inline, __forceinline oder __fastcall z.B.

Also die Funktion, die mit BROT_CORE_API deklariert ist (dahinter steht), befindet sich in einer DLL.

Kennung Eins
2003-03-03, 21:17:06
Originally posted by zeckensack
Ach hier haste auch was aufgemacht! :D

Ich hoffe die zahlreichen PMs waren hilfreich ;) Jau, waren sie! Doch eine Sache fehlt mir noch:

Kannst du mir nochmal den Unterschied zwischen

const ubyte* const palette
const ubyte* const
const ubyte*

erklären, bitte? Das ist mir nicht ganz klar geworden.
und wie stelle ich die unteren beiden dar? (der erste mittels "type pal=^byte", das geht klar)

zeckensack
2003-03-03, 21:20:01
Nochmal öffentlich, wer weiß ...
#ifdef BROT_CORE_EXPORTS
#define BROT_CORE_API __declspec(dllexport)
#else
#define BROT_CORE_API __declspec(dllimport)
#endif

#define BROT_CALL

#ifdef BROT_CORE_EXPORTS
class Context;
typedef Context* bc_context;
#else
typedef unsigned int bc_context;
struct Place {ubyte dont_touch[100];};
#endif


#define BROT_FUNCTION(name,return_type,argument_list) BROT_CORE_API return_type BROT_CALL name argument_list
Das sind Präprozessor-Makros. Das mache ich deswegen, weil ich gerne den gleichen Header für den DLL-Bau benutzen will, wie für das Erzeugen eines 'Clients', ie einem Programm das die DLL benutzt. So spare ich mir Updates an zwei verschiedenen Stellen, und mögliche Fehler.

BROT_CORE_API ist keine Konstante. Der Präprozessor ersetzt Zeichenfolgen, bevor der Compiler überhaupt anfängt.
Auch die letzte Zeile macht für sich genommen garnichts. Sie definiert ein reines Präprozessor-Makro, das später auch benutzt wird. Der Compiler selbst bekommt das nicht zu sehen.
Bsp://set palette cycling speed in palette entries per second. Both positive and negative values are valid
BROT_FUNCTION(bc_set_palette_cycling_speed,void,(bc_context c,float speed));
//set a new generator (=optimization strategy) by enumerant
BROT_FUNCTION(bc_set_generator_type,int,(bc_context c,int type));

Nachdem der Präprozessor da dran war, bleibt das hier übrig und wird kompiliert:
__declspec(dllimport) void bc_set_palette_cycling_speed(bc_context c,float speed);
__declspec(dllimport) int bc_set_generator_type(bc_context c,int type);

Beim Bauen der DLL ist übrigens BROT_CORE_EXPORTS definiert, wodurch aus dllimport dllexport wird, und der Typ bc_context seine wahre Bedeutung (die die Client-App aber nicht wissen soll!) bekommt.

zeckensack
2003-03-03, 21:31:03
Originally posted by Kennung Eins
Jau, waren sie! Doch eine Sache fehlt mir noch:

Kannst du mir nochmal den Unterschied zwischen

const ubyte* const palette
const ubyte* const
const ubyte*

erklären, bitte? Das ist mir nicht ganz klar geworden.
und wie stelle ich die unteren beiden dar? (der erste mittels "type pal=^byte", das geht klar)
Rückwärts:
4 ;) ) ubyte ist meine private typedef, und heisst eigentlich 'unsigned char', was mir etwas unelegant erscheint.

3)const ubyte* ist ein Zeiger auf ein ubyte, der nicht zum Schreiben benutzt werden darf. Dieses 'nicht dürfen' wird unter C++ vom Compiler forciert und ist für andere Sprachen evtl bedeutungslos. Ergo: in anderen Sprachen wie ein einfaches ubyte* behandeln, aber bitte nicht dorthin schreiben.

2)const ubyte* const ist das gleiche wie const ubyte*. Zusätzlich verspricht man dem Compiler, nicht nur die verwiesenen Daten, sondern auch den Zeiger selbst nicht zu verändern. Das ist ehrlich gesagt in diesem Header total überflüssig, weil's nur zu Modul-interner Optimierungsarbeit überhaupt einen Beitrag haben kann. Ergo: nach belieben durch const ubyte* ersetzen.

1)const ubyte* const palette ist das gleiche wie 2. Naja fast. 2tens ist der Typ, dies hier ist eine Variable dieses Typs. In diesem Fall habe ich aus Nettigkeit meinen Funktionsparametern Namen gegeben, damit man leichter ihren Sinn durchschauen kann. Als extra-Schmankerl können viele moderne IDEs direkt beim Code-Eintippen die Parameterliste anzeigen. Da macht es sich halt nett, wenn ein möglichst deskriptiver Name dabei ist.

Kennung Eins
2003-03-03, 21:45:28
Originally posted by zeckensack

Rückwärts:
4 ;) ) ubyte ist meine private typedef, und heisst eigentlich 'unsigned char', was mir etwas unelegant erscheint.

3)const ubyte* ist ein Zeiger auf ein ubyte, der nicht zum Schreiben benutzt werden darf. Dieses 'nicht dürfen' wird unter C++ vom Compiler forciert und ist für andere Sprachen evtl bedeutungslos. Ergo: in anderen Sprachen wie ein einfaches ubyte* behandeln, aber bitte nicht dorthin schreiben.

2)const ubyte* const ist das gleiche wie const ubyte*. Zusätzlich verspricht man dem Compiler, nicht nur die verwiesenen Daten, sondern auch den Zeiger selbst nicht zu verändern. Das ist ehrlich gesagt in diesem Header total überflüssig, weil's nur zu Modul-interner Optimierungsarbeit überhaupt einen Beitrag haben kann. Ergo: nach belieben durch const ubyte* ersetzen.

1)const ubyte* const palette ist das gleiche wie 2. Naja fast. 2tens ist der Typ, dies hier ist eine Variable dieses Typs. In diesem Fall habe ich aus Nettigkeit meinen Funktionsparametern Namen gegeben, damit man leichter ihren Sinn durchschauen kann. Als extra-Schmankerl können viele moderne IDEs direkt beim Code-Eintippen die Parameterliste anzeigen. Da macht es sich halt nett, wenn ein möglichst deskriptiver Name dabei ist. Also so wie ich das jetzt sehe, muss ich demnach ja dann immer (ausser für 4.) :) ) folgendes verwenden:

ausBROT_FUNCTION(bc_set_palette,void,(bc_context c,const ubyte* const palette));machtype pal = ^byte;
procedure bc_set_palette(c:Integer;palette:pal); stdcall;
external 'brot_core.dll' name 'bc_set_palette';
, egal ob da nun "const ubyte* const palette", "const ubyte* const" oder "const ubyte*" steht.

Ich wüsste zumindest nicht, wie ich diese ganzen anderen Fälle sonst darstellen könnte...