Autor Beitrag
Atoll
Hält's aus hier
Beiträge: 9



BeitragVerfasst: Di 02.10.07 17:56 
Hallo,

ich habe folgendes problem: ich moechte eine funktion aus einer c++ library verwenden. Die funktion hat ein struct (record in c++) als Parameter. Das Problem besteht darin das das struct ein Feld namens 'function' enthaelt und dieser Bezeichner von delphi bereits verwendet wird. Gibt es eine Moeglichkeit die dll funktion trotzdem zu verwenden?



Atoll
Lossy eX
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1048
Erhaltene Danke: 4



BeitragVerfasst: Di 02.10.07 18:07 
Das sind doch nur Bezeichner innerhalb deiner Programmsrache. Damit Delphi weiß auf welches Feld du zugreifen möchtest. Im echten Programm befinden sich keine Bezeichner mehr dort wird nur noch direkt auf den Speicherbereich zugeriffen.

Mit anderen Worten du kannst es "knoedeltroeten" nenne. Das juckt niemanden außer den der deinen Code lesen muss. ;)

_________________
Nur die Menschheit ist arrogant genug, um zu glauben sie sei die einzige intelligente Lebensform im All. Wo nicht mal das nachhaltig bewiesen wurde.
Atoll Threadstarter
Hält's aus hier
Beiträge: 9



BeitragVerfasst: Mi 03.10.07 03:56 
okay danke fuer die antwort.

es will allerdings immer noch nicht funktionieren. ich nehme anscheinend falsche typen.

Das hier ist der c++ typ einer funktion

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
Data Type: gsl_function
    This data type defines a general function with parameters.

    double (* function) (double x, void * params)
        this function should return the value f(x,paramsfor argument x and parameters params 
    void * params
        a pointer to the parameters of the function


diese funktion wird an eine andere funktion uebergeben:

ausblenden C#-Quelltext
1:
2:
3:
int gsl_integration_qags (const gsl_function * f, double a, double b,
double epsabs, double epsrel, size t limit, gsl_integration workspace *
workspace, double * result, double * abserr)


bis auf die gsl_function habe ich alle typen ordentlich definiert in delphi. aber bei der gsl_function hapert es. wie wuerdet ihr die definieren?

Hier noch ein c++ beispielprogramm zu gsl_integration_qags:


ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
#include <stdio.h>
#include <math.h>
#include <gsl/gsl_integration.h>
double f (double x, void * params) {
double alpha = *(double *) params;
double f = log(alpha*x) / sqrt(x);
return f;
}
int
main (void)
{
gsl_integration_workspace * w
= gsl_integration_workspace_alloc (1000);
double result, error;
double expected = -4.0;
double alpha = 1.0;
gsl_function F;
F.function = &f;
F.params = α
gsl_integration_qags (&F, 0101e-71000,w, &result, &error);
printf ("result = % .18f\n", result);
printf ("exact result = % .18f\n", expected);
printf ("estimated error = % .18f\n", error);
printf ("actual error = % .18f\n", result - expected);
printf ("intervals = %d\n", w->size);
return 0;
}



die DLL ist uebrigends die Gnu Scientific Library (libgsl)

Danke im vorraus

Atoll

Moderiert von user profile iconNarses: Code- durch C#-Tags ersetzt
Stefan.Buchholtz
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 612

WIN 2000, WIN XP, Mac OS X
D7 Enterprise, XCode, Eclipse, Ruby On Rails
BeitragVerfasst: Mi 03.10.07 11:07 
Ok, gsl_function definiert also einen Zeiger auf eine Funktion, die einen double und einen untypisierten Pointer als Argumente bekommt und ein double zurückgibt.

Das sieht in Delphi so aus:

ausblenden Delphi-Quelltext
1:
2:
type
  TGslFunction = function(x: Double; params: Pointer): Double; stdcall;



Die Funktion gs_integration_qags müsse dann so definiert werden:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
function gsl_integration_qags(f: TGslFunction; 
                              a, b, epsabs, epsrel: Double; 
                              limit: Cardinal;
                              workspace: PGslIntegration;
                              var result: Double;
                              var abserr: Double): Integer; stdcallexternal 'libgsl.dll';


Bei limit bin ich mir aber nicht ganz sicher - ist size_t in C ein 32 Bit oder 64 Bit Typ?

Stefan

_________________
Ein Computer ohne Windows ist wie eine Schokoladentorte ohne Senf.
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: Mi 03.10.07 20:01 
u.U auch beachten, welches Speicheralignment benutzt wird.

Bei Dlphi kann man für einzelne Record-Typen das Alignment mit Packed Record abschalten.

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
Atoll Threadstarter
Hält's aus hier
Beiträge: 9



BeitragVerfasst: Mi 03.10.07 20:30 
Sollte GSL_function nicht eher von folgender struktur sein? :

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
type 
   evalfunc = function(x:double; param:pointer):double;
   gslfunc = record
       func : ^evalfunc;
       params : pointer;
   end;


zumindest ist Gsl_function in dem c++ beispielprogram ein record typ

Moderiert von user profile iconNarses: Code- durch Delphi-Tags ersetzt
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: Mi 03.10.07 21:56 
Funktionspointer OHNE ^ vor'm Typbezeichner.

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
Atoll Threadstarter
Hält's aus hier
Beiträge: 9



BeitragVerfasst: Do 04.10.07 03:58 
Danke fuer die Hilfe, jetzt klappt es.

Falls jemand interesse hat die dll zu benutzen hier ein wenig code

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
type

    TGSLfunction = record
      func : function(x:double; params:pointer):double; CDECL;
      params : pointer;
    end;

    TWorkspace = record
    limit : LongWord;
    size : LongWord;
    nrmax : LongWord;
    i : LongWord;
    maximum_level : LongWord;
    alist : Array of double;
    blist : Array of double;
    rlist : Array of double;
    elist : Array of double;
    order : Array of LongWord;
    level : Array of LongWord;
    end;

var

function mathfunction(x:double; params:pointer):double;CDECL;

//differentiation function

function gsl_diff_central (f:pointer;
                           x:double;
                           result:pointer;
                           abserr:pointer):integer;stdcallexternal 'libgsl';

//integration function

function gsl_integration_workspace_alloc (n:LongWord):pointer; CDECLexternal 'libgsl';

function gsl_integration_qags(f: pointer;
                              a, b, epsabs, epsrel: Double;
                              limit: Cardinal;
                              workspace: pointer;
                              var result: Double;
                              var abserr: Double): Integer; stdcallexternal 'libgsl.dll';

procedure gsl_integration_workspace_free(w:pointer); CDECLexternal 'libgsl';


...



function mathfunction(x:double; params:pointer):double; CDECL;
var parameter:Array of double;
begin
Setlength(parameter,1);
parameter := params;
mathfunction := ln(parameter[0]*x) / sqrt(x);
end;

procedure TSDIAppForm.Button2Click(Sender: TObject);
var w:^TWorkspace;
    result,error : double;
    functest : TGSLfunction;
    parameters : Array of double;

begin
  //define test-function
  Setlength(parameters,1);
  parameters[0]:=2;
  functest.func := mathfunction;
  functest.params := parameters;

  gsl_diff_central (@functest, 4.0, @result, @error);

  w:=gsl_integration_workspace_alloc(1000);
  gsl_integration_qags(@functest, 0100.00000011000, w, result, error);
  gsl_integration_workspace_free(w);

  label1.Caption:=floattostr(result);
end;



benutzt die funktionen zum integrieren und differenzieren aus der library


ich denke es ging vorher nicht da ich der mathfunction nicht CDECL nachgestellt hatte.

Atoll

Moderiert von user profile iconNarses: Code- durch Delphi-Tags ersetzt
Lossy eX
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1048
Erhaltene Danke: 4



BeitragVerfasst: Do 04.10.07 09:23 
cdecl vs stdcall: Die Übergabe der Parameter bei stdcall und cdecl sind eigentlich gleich. Bei cdecl werden sie nur von dem wieder entsorgt der sie an die Funktion übergeben hat. Wenn du also eine cdelc funktion hast und diese als stdcall aufrufst bleiben unweigerliche Parammeter auf dem Stack liegen. Wenn diese funktionen sehr häufig aufgerufen werden läuft dir irgendwann der Stack voll. Überprüfe bitte GENAU welche Aufrufkonvention benutzt wird. Und setze diese dann einheitlich für alle deine Funktionen ein. Ich habe noch nie eine DLL gesehen bei der unetrschiedliche Konventionen gleichzeitig benutzt wurden.

TWorkspace: Bei den offenen Arrays handelt es sich normal nur um Pointer. Und wenn ich mich nicht vertue dann packt Delphi vor dem ersten Element noch die Größe mit in den Speicher. Wenn du also versuchst die Größe der Arrays abzufragen sollte es unweigerlich knallen, da C++ das höchstwahrscheinlich anders löst. (Das weiß ich nicht genau) Aber mit offen arrays wäre ich vorsichtig.

mathfunction: Da machst du etwas komisches. Du setzt die Länge eines arrays auf 1 und überschreibst es anschließend. Mich wundert es gerade, dass delphi das so ohne weiters schluckt. Aber für deinen Fall wäre wohl eher etwas wie folgendes das Bessere.
ausblenden Delphi-Quelltext
1:
2:
3:
4:
function mathfunction(x:double; params:pointer):double; CDECL;
begin
  mathfunction := ln(pDouble(parameter)^ * x) / sqrt(x);
end;

Bzw dann genügt es auch wenn du den Pointer auf ein einfaches Double übergibst. Und wenn du ein Array brauchst dann solltest du den Parameter als pDoubleArray casten und das benutzen.
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
type
  pDoubleArray = array of Double;

//  pDoubleArray = array [0..$FFFF] of Double;
  // oder so, weil es sich sonst wieder um offene Arrays handelt. Siehe oben.
  // Nur dann kannst du die Größe nicht sinnvoll abfragen.

  pDoubleArray(parameter)^[0]

_________________
Nur die Menschheit ist arrogant genug, um zu glauben sie sei die einzige intelligente Lebensform im All. Wo nicht mal das nachhaltig bewiesen wurde.
Atoll Threadstarter
Hält's aus hier
Beiträge: 9



BeitragVerfasst: Fr 05.10.07 00:56 
bloede frage,

aber wo kann ich die aufrufkonvention CDECL oder stdcall anhand der library erkennen?
Lossy eX
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1048
Erhaltene Danke: 4



BeitragVerfasst: Fr 05.10.07 09:17 
Diese Frage ich nicht blöd sondern bei C++ durchaus berechtigt. In Pascal steht die Konvention immer hinter der funktion. In C++ eher immer davor. Aber es wird eigentlich grundsätzlich immer per Präprozessor gelöst.

Als kleines Beispiel mal ein Ausschnitt aus einem Header von mir.
ausblenden Quelltext
1:
2:
3:
4:
5:
6:
7:
#define TSAPI __declspec(dllimport)

// diverse typdefinitionen

// viele viele Konstanten....

TSAPI tsBool tsInit (tsEnum Names);

Wie du siehst steht bei der Methode noch das Define TSAPI davor. Der Präprozessor von C/C++ ersetzt das Define durch dessen Inhalt. __declspec(dllimport) bedeutet cdecl. Es gibt aber auch so etwas wie __cdecl das muss dann aber zwischen Rückgabewert und Methodennamen stehen. Bedeutet aber eigentlich das gleiche. Ansonsten gibt es noch so etwas wie __stdcall. Bzw gibt es noch das Standarddefine WINAPI was auch nur wieder auf __stdcall zeigt. Und wenn gar nichts angegeben ist dann sollte es auch stdcall sein. Aber das kann man sicherlich auch noch global in den Projekteinstellungen beinflussen. Also es gibt leider viel zu viele Möglichkeiten das einzustellen.

Aber es ist normal immer einheitlich in einer Library. Und spezielle Windows DLL sind eher stdcall wohingegen open source Bibliotheken eher cdecl benutzen. Da Linux normal mit cdecl arbeitet und man die dann der einfach heit auch so lässt.

Im Zweifel benutzt mal cdecl als Konvention. Da dadurch der Aufrufende die Paramater wegräumt werden im Falle einer stdcall methode die Parameter 2 mal weggeräumt und dabei zerschießt du dir recht schnell den Stack. Wenn also Fehler auftreten ist es vermutlich eine stdcall Methode. Wenn nicht und die methode auch arbeitet scheint es sich um cdecl zu handeln. Aber es ist logischerweise besser es vorher zu wissen. ;)

_________________
Nur die Menschheit ist arrogant genug, um zu glauben sie sei die einzige intelligente Lebensform im All. Wo nicht mal das nachhaltig bewiesen wurde.