Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Wer kann mir diese C Funktion uebersetzen? (https://www.delphipraxis.net/62021-wer-kann-mir-diese-c-funktion-uebersetzen.html)

mika 29. Jan 2006 19:15


Wer kann mir diese C Funktion uebersetzen?
 
Hallo Delphi-Praxis!

Ich hab ein Problem nämlich das ich eine DLL schreiben muss für eine Anwendung. Jetzt
habe ich allerdings Probleme beim auslesen der Parameter, soweit ich das mitbekommen
habe wird als einziger Parameter ein Pointer auf eine mir bekannte Struktur übergeben.

Als Beispiel habe ich in der Hilfe der Anwendung diesen Beispiel C Code gefunden der
erklärt wie das ganze vonstatten gehen soll. Allerdings sind meine C Kenntnisse arg
begrenzt ebenso wie mein Wissen über Pointer unter Delphi :oops:

Könnte mir jemand aus dieser C Methode mal eine Delphi Methode schreiben? Dann wär ich
schon n ganzes Stück weiter!

Code:
struct TEST_SUB_PARAMS  // This structure represents the parameters passed to
{                        // the Log_B_of_X function.
   double  base;
   double  x;
   HWND    hwnd;   // Note: the handle to the frame window is always tacked on
                     // as a final parameter (even if there are no others).
};

extern "C" // This makes this a C function rather than a C++ function!
{
   // Borland & Microsoft add a leading underscore to a 'C' name for export!
   // All ProModel XSUB calls must go to a function with this signature.
   double _export Log_B_of_X(void *p)
   {
      MessageBox(GetTopWindow(hWndFrame),"Executing Log_B_of_X function.","XSUB",MB_OK);

      // Parameters come in in a structure pointed to by p;
      TEST_SUB_PARAMS *params;
      params = (TEST_SUB_PARAMS*)p;
      hWndFrame = params->hwnd;
      return log(params->x) / log(params->base);
   }
}
Danke schonmal an euch :hi:

[edit=alcaeus]SQL- in C-Tags umgewandelt. Mfg, alcaeus[/edit]
[edit=mika]Wir haben C Format BB-Codes? Wusst ich gar nicht :-)[/edit]

marabu 30. Jan 2006 08:29

Re: Wer kann mir diese C Funktion uebersetzen?
 
Ich habe C zur Seite gelegt, als TP auf den Markt kam, aber das hier könnte eine Ausgangsbasis für dich sein:

Delphi-Quellcode:
library Test;

uses
  Windows,
  Math,
  SysUtils,
  Classes;

{$R *.res}

type
  PTEST_SUB_PARAMS = ^TTEST_SUB_PARAMS;
  TTEST_SUB_PARAMS = record
    base: double;
    x: double;
    h: HWND;
  end;

function Log_B_of_X(var p): Double; cdecl;
var
  params: PTEST_SUB_PARAMS;
begin
  params := @p;
  MessageBox(GetTopWindow(params.h), 'Executing Log_B_of_X function.' , 'XSUB',MB_OK);
  Result := ln(params.x) / ln(params.base);
end;

exports
  Log_B_of_X name '_Log_B_of_X'; // prüfen

end.
Grüße vom marabu

Robert Marquardt 30. Jan 2006 08:52

Re: Wer kann mir diese C Funktion uebersetzen?
 
Marabu hat das ja soweit richtig gemacht, aber er hat die Zuweisung an hWndFrame unterschlagen, da diese Variable in der C Source nicht deklariert ist.
Das duerfte Nebeneffekte verursachen. Alles in allem ist die C Funktion ziemlich schlecht implementiert.

marabu 30. Jan 2006 09:27

Re: Wer kann mir diese C Funktion uebersetzen?
 
Hallo Robert,

ich hatte mehrfach hin und her überlegt, wozu die globale Variable hWndFrame gut sein könnte, aber angesichts der gegebenen Funktion und der Verwendung der Variable darin konnte ich keinen Sinn entdecken. Erkennst du da etwas?

Freundliche Grüße vom marabu

Robert Marquardt 30. Jan 2006 11:40

Re: Wer kann mir diese C Funktion uebersetzen?
 
Das ist offensichtlich eine globale Variable anderswo.
Deshalb bin ich ja der Meinung die C-Funktion taugt nichts. Die C-Implementation ist mit Nebeneffekten gesegnet und merkwuerdig im Design.
Es waere besser alles von vorne zu implementieren.

mika 30. Jan 2006 14:12

Re: Wer kann mir diese C Funktion uebersetzen?
 
Hallo und erstmal danke für die Antworten,

das mit der Messagebox ist gar nicht so wichtig, ich habe das halt nur nicht hinbekommen die
Parameter zu ermitteln die das aufrufende Programm mir übergeben will.

Delphi-Quellcode:
type
  PTEST_SUB_PARAMS = ^TTEST_SUB_PARAMS;
  TTEST_SUB_PARAMS = record
    base: double;
    x: double;
    h: HWND;
  end;

function Log_B_of_X(var p): Double; cdecl;
var
  params: PTEST_SUB_PARAMS;
begin
  params := @p;
  MessageBox(GetTopWindow(params.h), 'Executing Log_B_of_X function.' , 'XSUB',MB_OK);
  Result := ln(params.x) / ln(params.base);
end;
So hatte ich das auch gemacht allerdings glaube ich das ich vor dem
Delphi-Quellcode:
  params := @ params;
noch ein
Delphi-Quellcode:
  new(params);
gemacht hab...

Leider kann ich das jetzt nicht mehr testen da ich das aufrufende Programm nicht hier habe :evil:
Allerdings schien ich ja schon auf der richtigen Spur zu sein...

Sobald ich wieder testen kann schreib ich euch ob ich das inzwischen hinbekommen habe!


Danke für eure Hilfe, Michael.

<edit>
Jetzt sehe ich grade das du als parameter gar keinen typ angegeben hast in der funktion und ausserdem
nicht stdcall verwendest sondern cdecl! Ist das sehr wichtig?
Delphi-Quellcode:
    function Log_B_of_X(var p): Double; cdecl;
Hab grade noch mal nachgeschaut, meine Funktion so sah so aus:
Delphi-Quellcode:
    function Log_B_of_X(p: pointer): Double; stdcall;
    var
      params: PTEST_SUB_PARAMS;
    begin
      params := @p;
      // Nur als Beispiel jetzt:
      blabla := params^.base;
    end;
Da werden die Unterschiede dann doch schon größer oder was sagt ihr?

</edit>

jbg 30. Jan 2006 14:34

Re: Wer kann mir diese C Funktion uebersetzen?
 
Delphi-Quellcode:
function Log_B_of_X(var params: TTEST_SUB_PARAMS): Double; cdecl;
begin
  MessageBox(GetTopWindow(params.h), 'Executing Log_B_of_X function.' , 'XSUB',MB_OK);
  Result := ln(params.x) / ln(params.base);
end;
Dashier reicht auch schon aus. Was will man der Funktion denn sonst übergeben.

mika 30. Jan 2006 14:42

Re: Wer kann mir diese C Funktion uebersetzen?
 
Ich bin mir nicht sicher da ich das Programm das meine DLL aufruft nicht sonderlich gut kenne und
ich halt nur weiss das es, damit man verschiedene Arten von Methoden aus DLLs aufrufen kann, nur
einen Pointer übergibt.

Die Methode die ich hier als Beispiel genommen habe gibt ja noch was zurück, das machen meine
ganzen Methoden nicht (jedenfalls keine Berechnung). Ich bekomme Daten übergeben die ich in eine
Datenbank speichern soll und je nachdem ob bei mri alles geklappt hat oder nicht gebe ich 0 oder 1
zurück.

[edit]
Ist zwischen stdcall und cdecl ein großer Unterschied?
[/edit]

jbg 30. Jan 2006 14:55

Re: Wer kann mir diese C Funktion uebersetzen?
 
Zitat:

Zitat von mika
Ich bin mir nicht sicher da ich das Programm das meine DLL aufruft nicht sonderlich gut kenne und ich halt nur weiss das es, damit man verschiedene Arten von Methoden aus DLLs aufrufen kann, nur einen Pointer übergibt.

Das kann deiner DLL wurst sein. Wenn du sowieso einen Typecast in deinen TEST_SUB_PARAMS Typ machst, kannst du auch gleich einen Zeiger (var) auf TTEST_SUB_PARAMS als Parameter einbauen. Das ist weniger Tipparbeit und ein MOV-Befehl weniger. Der aufrufende Code hat seine eigene Deklaration, die dort vielleicht einen Zeiger erwartet, aber du akzeptierst ja auch einen Zeiger.

Zitat:

Ist zwischen stdcall und cdecl ein großer Unterschied?
Ja.
StdCall übergibt die Parameter von links nach rechts und die aufgerufene Funktion löscht sie wieder vom Stack.

Cdecl übergibt die Parameter von rechts nach links und der Aufrufer löscht sie wieder vom Stack.

mika 30. Jan 2006 15:00

Re: Wer kann mir diese C Funktion uebersetzen?
 
Alles klar,

hab grad noch einige andere Threads über DLL Aufrufkonventionen über mehrere Sprachen gelesen in denen du
auch geantwortet hast und du scheinst dich da ja auszukennen :coder2:

Ich probier das mal aus, blöd ist halt nur das ich das ganze grad nicht testen kann :-(
Wenn ich am Wochenende die Möglichkeut bekomme das auszuprobieren dann schreib
ich euch sofort wie sich das ganze ausgewirkt hat!


Danke für eure Hilfe!

mika 30. Jan 2006 18:57

Re: Wer kann mir diese C Funktion uebersetzen?
 
So, ich habe mir gedacht ich kann meine DLL ja schon mal umbauen und schreib
mir selber noch n kleines Testprogramm um die ganze Sache einmal auszuprobieren
aber irgendwie klappt das auch nicht so ganz. :evil:

Ich bekomms immer noch nicht hin die Parameter auszulesen. Da ich die Aufrufkonvention
jetzt ja auf cdecl geändert habe muss ich mich doch auch im "Aufrufenden" Programm
um die Speicherverwaltung der Parameter kümmern oder?


In meiner DLL habe ich folgenden Record deklariert

Delphi-Quellcode:
PParameterStructure = ^TParameterStructure;
TParameterStructure = Record
  one,
  two,
  three,
  four: double;
End;
Die Methode die aufgerufen wird sieht folgendermaßen aus:
Delphi-Quellcode:
Function PassParamFunction(Var Parameter: TParamStructure): Double; cdecl;
Var
  Wert1,
  Wert2,
  Wert3,
  Wert4: Double;
Begin
  Wert1 := Parameter.one;
  Wert2 := Parameter.two;
  Wert3 := Parameter.three;
  Wert4 := Parameter.four;
  Result := 0;
End
In meinem Testprogramm das die DLL aufruft ist in meiner "Api"-Unit folgendes angelegt!
Delphi-Quellcode:
PParameterStructure = ^TParameterStructure;
TParameterStructure = Record
  one,
  two,
  three,
  four: double;
End;

Function PassParamFunction(Var Parameter): Double; cdecl;

implementation

Function PassParamFunction(Var Parameter): Double; cdecl; external 'test.dll';
Und bei dem Button mit dem ich den ganzen Kram teste:
Delphi-Quellcode:
Procedure TestIt;
Var
  Parameter: PParameterStructure;

Begin
  GetMem(Parameter, SizeOf(TParameterStructure));
  Parameter.One := 12;
  Parameter.Two := 23;
  Parameter.Three := 34;
  Parameter.Four := 45;
  PassParamFunction(Parameter);
  FreeMem(Parameter);
End

Wisst ihr da weiter?

jbg 30. Jan 2006 19:37

Re: Wer kann mir diese C Funktion uebersetzen?
 
Zitat:

Zitat von mika
Da ich die Aufrufkonvention jetzt ja auf cdecl geändert habe muss ich mich doch auch im "Aufrufenden" Programm
um die Speicherverwaltung der Parameter kümmern oder?

Nein. Das macht der Compiler für dich. Bei DLLs ist unter Windows StdCall geläufiger als Cdecl.

Zitat:

Die Methode die aufgerufen wird sieht folgendermaßen aus:
Delphi-Quellcode:
Function PassParamFunction(Var Parameter: TParamStructure): Double; cdecl;
Var
  Wert1,
  Wert2,
  Wert3,
  Wert4: Double;
Begin
  Wert1 := Parameter.one;
  Wert2 := Parameter.two;
  Wert3 := Parameter.three;
  Wert4 := Parameter.four;
  Result := 0;
End

Ich gehe mal davon aus, dass das nur ein Pseudo-Code ist, denn der Compiler wird dir da einiges wegoptimieren, weil es Unnütz ist.

Zitat:

In meinem Testprogramm das die DLL aufruft ist in meiner "Api"-Unit folgendes angelegt!
Delphi-Quellcode:
PParameterStructure = ^TParameterStructure;
TParameterStructure = Record
  one,
  two,
  three,
  four: double;
End;

Function PassParamFunction(Var Parameter): Double; cdecl;

implementation

Function PassParamFunction(Var Parameter): Double; cdecl; external 'test.dll';

Da es sich um eine Delphi-Unit handelt, kannst du auch beim "Var Parameter" den Typ mit angeben. Dann kann schon mal nichts mehr mit falschen Parametern schief laufen, was du ja im nächsten Code-Block gliech mal falsch machst.

Zitat:

Und bei dem Button mit dem ich den ganzen Kram teste:
Deine Funktion möchte einen TParamStructure in der DLL. Da du aber diese Information in der Import-Unit verheimlichst und ein allgemeingültigen veränderbaren Parameter möchtest, akzeptiert der Compiler hier natürlich auch einen Zeiger(Var) auf einen Zeiger auf eine TParamStructure, was aber falsch ist, denn die DLL mag ja nur einen Zeiger(Var) auf eine TParamStructure. Also ein "Zeiger auf" weniger.

Das mit dem GetMem/FreeMem kannst du dir auch sparen, wenn du einfach eine lokale Variable vom Typ TParamStructure anlegst. Damit ist auch gleich sichergestellt, dass du kein Speicherleck produzierst.


Die Import-Unit muss also besser so aussehen:
Delphi-Quellcode:
type
  PParameterStructure = ^TParameterStructure;
  TParameterStructure = record
    One,
    Two,
    Three,
    Four: Double;
  end;

function PassParamFunction(var Parameter: TParameterStructure): Double; cdecl;

implementation

function PassParamFunction(var Parameter: TParameterStructure): Double; cdecl; external 'test.dll';
Und wenn du die ParameterStructure-Felder nicht verändern willst, kannst du aus dem "var" auch ein "const" machen (dann aber auch in der DLL daraus ein "const" machen).

mika 30. Jan 2006 19:45

Re: Wer kann mir diese C Funktion uebersetzen?
 
Hallo jbg,

hast recht das ganze ist nur pseudocode aber es geht ja auch nur ums verständnis :D


alsooo, du hast recht, nachdem ich in meinem aufrufendem programm mitgeteilt habe
das der Var Parameter vom Typ TParameterStructure ist klappt auch das entgegennehmen
der Parameter sehr gut.

Ich werde jetzt mal weitertesten, meld mich gleich mal wieder....

[edit]
Ich will in meiner DLL die Parameter nicht verändern sondern nur entgegennehmen. Sollte
ich Const nur einsetzen damit es verständlicher ist (in der DLL) oder hat es auch noch
weitere Vorteile?
[/edit]

jbg 30. Jan 2006 20:17

Re: Wer kann mir diese C Funktion uebersetzen?
 
Zitat:

Zitat von mika
Sollte ich Const nur einsetzen damit es verständlicher ist (in der DLL) oder hat es auch noch weitere Vorteile?

Es ist verständlicher. Bei "var" oder "out" geht man immer davon aus, dass der Parameter verändert wird. Gibt man nichts an, so muss der Compiler Code einfügen, der den Record kopiert, damit Änderungen in der Funktion nicht auf die übergebene Variable Auswirkungen haben, was ineffizient ist, wenn man es nicht braucht.

mika 30. Jan 2006 20:24

Re: Wer kann mir diese C Funktion uebersetzen?
 
Alles klar, hab das jetzt auch auf Const geändert und innerhalb meiner Testumgebung funktioniert das ganze auch
sehr gut. Fragt sich bloss wie es mit der richtigen Anwendung aussieht :?

Danke für die Hilfe! :thumb:

mika 6. Feb 2006 19:46

Re: Wer kann mir diese C Funktion uebersetzen?
 
Hallo Delphi Praxis,

inzwischen habe ich das ganze mit der Anwendung die es zu unterstützen gilt getestet und bin leider nicht weitergekommen :-(
Da ich jedoch nun alles hier bei mir habe um zu testen und auch "Fetzen" der alten C-DLL gefunden habe die es zu ersetzen
gilt hoffe ich das ich mit eurer Hilfe das ganze doch noch abeschliessen kann :wink:

Also hier mal n bisschen C Source der alten DLL:
DLL Header Datei
Code:
#ifndef _DLL_H_
#define _DLL_H_

#include <Windows.h>

#ifdef __cplusplus
extern "C"
{
#endif


#if BUILDING_DLL
# define DLLIMPORT __declspec (dllexport)
#else /* Not BUILDING_DLL */
# define DLLIMPORT __declspec (dllimport)
#endif /* Not BUILDING_DLL */

#ifndef DLL_CALL
#define DLL_CALL __stdcall
#endif

struct LSLSimpleParams
{
  int productCode;
  HWND windowsHandle;
};

DLLIMPORT double DLL_CALL lsl_getNumberOfDays(struct LSLSimpleParams   *parameters);

#ifdef __cplusplus
}
#endif


#endif /* _DLL_H_ */
DLL-Code
Code:
DLLIMPORT double DLL_CALL lsl_getNumberOfDays(struct LSLSimpleParams *parameters)
{
  double nofDays = 9999;
  int   atLeastOneLicenceFound = 0;

  if(!parameters || parameters->productCode > maxProductKey)
    nofDays = -9999;

  return nofDays;
}

Diese Funktionen brauch ich zwar in meiner neuen DLL noch nicht, sind aber ein Beispiel für eine Funktionierende Funktion
in der alten DLL! Mir geht es nur um die Parameterübergabe da ich das neue Programm schon soweit habe das es einige von
mir gewünschte Funktionen aufruft, der Code darin ausgeführt wird und weiterläuft. Das einzige was ich nicht schaffe sind
die Parameter auszulesen! Ich bekomme ja einen Pointer auf eine Struktur. Soweit ich es dem C Code entnehmen kann muss
ich einfach nur diese Struktur auslesen, ich muss doch keinen Specherplatz allokieren oder freigeben :gruebel:

Jetzt mal n bisschen Beispielcode von mir

Delphi-Quellcode:
library intelliDLL;

{ Wichtiger Hinweis zur DLL-Speicherverwaltung: ShareMem muß sich in der
  ersten Unit der unit-Klausel der Bibliothek und des Projekts befinden (Projekt-
  Quelltext anzeigen), falls die DLL Prozeduren oder Funktionen exportiert, die
  Strings als Parameter oder Funktionsergebnisse übergeben. Das gilt für alle
  Strings, die von oder an die DLL übergeben werden -- sogar für diejenigen, die
  sich in Records und Klassen befinden. Sharemem ist die Schnittstellen-Unit zur
  Verwaltungs-DLL für gemeinsame Speicherzugriffe, BORLNDMM.DLL.
  Um die Verwendung von BORLNDMM.DLL zu vermeiden, können Sie String-
  Informationen als PChar- oder ShortString-Parameter übergeben. }


uses
  SysUtils,
  Classes;

Type
  TWriteEventStructure = Record
    entityID,
    lkNumber,
    locationNumber,
    resourceNumber,
    vWochenTag,
    vAnzeigeStd,
    vAnzeigeMin,
    vAnzeigeSek: Integer;
    fHandle: THandle;
  End;

Function eventEntityCreate(Const Parameter: TWriteEventStructure): Double; cdecl;
Begin
  AddToLogfile(eventLogName,
    'Methode      : DLL-Methode des Events' + #13#10 +
    'EventNr      : '+IntToStr(uDMEvents.evtEntityCreate) + #13#10 +
    'entityID     : '+IntToStr(Parameter.entityID) + #13#10 +
    'lkNumber     : '+IntToStr(Parameter.lkNumber) + #13#10 +
    'locationNumber: '+IntToStr(Parameter.locationNumber) + #13#10 +
    'resourceNumber: '+IntToStr(Parameter.resourceNumber) + #13#10 +
    'vWochenTag   : '+IntToStr(Parameter.vWochenTag) + #13#10 +
    'vAnzeigeStd  : '+IntToStr(Parameter.vAnzeigeStd) + #13#10 +
    'vAnzeigeMin  : '+IntToStr(Parameter.vAnzeigeMin) + #13#10 +
    'vAnzeigeSek  : '+IntToStr(Parameter.vAnzeigeSek)
    );

  Result := 0;
End;

// Alle exportierten Methoden dieser DLL
exports
  eventEntityCreate;

Function onExitDLL: Boolean;
Begin
  Result := True;
End;

begin
  // Neue Ausstiegsprozedur registrieren
  AddTerminateProc(onExitDLL);
end.
Die Methode AddtoLogfile schreibt mir das ganze in eine textdatei, was auch funktioniert aber die Werte (sollten alle 0 sein)
wirken auf mich wie uninitialsiert, es sind irgendwelche Werte (interessant war auch das die gleich blieben, das heisst
Aufrufendes Programm wurde 3 mal gestartet -> Funktion 3 mal aufgerufen -> jedes mal Quatsch, aber der gleiche).


Vielleicht könnt ihr mir noch weiterhelfen bin ich echt am verzweifeln! Habs schon mit stdcall als Aufrufkonvention probiert oder mit nem Packed Record als Struktur aber einfach kein erfolg!

Bin über jeden Tip dankbar!

mika 6. Feb 2006 20:14

Re: Wer kann mir diese C Funktion uebersetzen?
 
Hmmm ich bin grad am testen und es sieht aus als ob es so wie es in Beitrag Nummer 2 von marabu beschrieben wird funktioniert.
Schreib gleich mehr muss testen :-D

:dp:


Alle Zeitangaben in WEZ +1. Es ist jetzt 01:06 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