Autor |
Beitrag |
doll1
Hält's aus hier
Beiträge: 3
Win7, Linux
Delphi XE, VS2010
|
Verfasst: Di 06.03.12 15:45
Guten Tag,
ich habe recherchiert und weiß, dass schon einiges zum Thema C++-DLL's und Delphi geschrieben wurde. Leider hat es mir nicht sehr geholfen. Das kann auch daran liegen, dass das Thema Delphi an sich für mich relativ neu ist.
Ich habe hier eine C++-DLL, die mir Funktionen zur Kommunikation mit einem externen Gerät zur Verfügung stellt. Die kann ich mit C# z.B. auch wunderbar benutzen. Es gelingt mir auch, die Funktionen von Delphi aus aufzurufen. Es sieht aber so aus, als ob die Parameter-Übergabe nicht funktioniert.
Vom Entwickler der DLL habe ich die Info, dass sie mit 'stdcall' kompiliert ist. Ich habe auch das .h-File.
Ich denke, mein Problem sind die Parameter in der Funktionsdeklaration im Delphi-Quelltext.
Es sollen ein paar Integers und zwei Zeiger auf array of structure übergeben werden. Rückgabewert ist ein String.
Ich habe mal ein paar Code-Schnippsel zusammengesetzt um es zu verdeutlichen.
Die C++-Deklaration sieht so aus:
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:
| typedef struct _Scale { int masterAddress; LPWSTR ipAddress; int txPort; int rxPort; LPWSTR model; LPWSTR display; LPWSTR section; int group; LPWSTR logsPath; }Scale;
typedef struct _Item { int code; int directKey; double price; LPWSTR name; int type; int section; LPWSTR expiryDate; int alterPrice; int number; int priceFactor; LPWSTR textG; }Item;
extern "C" // Exportable functions { DIBALSCOP_API LPSTR WINAPI RegistersSend (Scale * myScales, int iNumScales, Register myRegisters[], int numRegisters, int iShowWindow, int iCloseTime); DIBALSCOP_API LPSTR WINAPI ItemsSend (Scale * myScales, int numScales, Item * myItems, int numItems, int showWindow, int closeTime); DIBALSCOP_API LPSTR WINAPI DataSend (void); DIBALSCOP_API int WINAPI ReadRegister (int * iServerHandle, char * sReceiveBuffer, char *scaleIpAddress, int scalePortTx,LPWSTR * pcIpAddress, int pcPortRx, int timeOut, char * pathLogs); DIBALSCOP_API int WINAPI CancelReadRegister(int *iServerHandle, char * pathLogs); } |
Wie gesagt, es werden Zeiger auf Arrays solcher Strukturen erwartet. Mein letzter Versuch in Delphi sieht so aus:
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:
| interface
type _Scale = record masterAddress: integer; ipAddress: PChar; txPort: integer; rxPort: integer; model: PChar; display: PChar; section: PChar; group: integer; logsPath: PChar; end;
type _Artikel = record code: integer; directKey: integer; price: double; itemName: PChar; wheighty: integer; section: integer; expiryDate: PChar; alterPrice: integer; plu: integer; priceFactor: integer; gText: PChar; end;
function ItemsSend(myScales: Pointer; numScales: integer; myItems: Pointer; numItems: integer; showWindow: integer; closeTime: integer): PChar; stdcall; function RegistersSend(myScales: Pointer; numScales: integer; myRegisters: Pointer; numRegisters: integer; showWindow: integer; closeTime: integer): PChar; stdcall;
implementation
function ItemsSend(myScales: Pointer; numScales: integer; myItems: Pointer; numItems: integer; showWindow: integer; closeTime: integer): PChar; external 'Dibalscop.dll'; function RegistersSend(myScales: Pointer; numScales: integer; myRegisters: Pointer; numRegisters: integer; showWindow: integer; closeTime: integer): PChar; external 'Dibalscop.dll';
procedure TBWDForm.ArtikelEintragenAendernButtonClick(Sender: TObject); var ergebnis: string; artikelName: widestring; myScales: array of _Scale; myArticles: array of _Artikel; begin Setlength(myScales, 1); ScalesInit(myScales);
artikelName := widestring(ArtikelNameEdit.Text);
Setlength(myArticles, 1); myArticles[0].code := StrToInt(ArtikelNummerEdit.Text); myArticles[0].directKey := StrToInt(ArtikelTasteEdit.Text); myArticles[0].price := StrToFloat(ArtikelPreisEdit1.Text); myArticles[0].itemName := @artikelName; myArticles[0].wheighty := 0; myArticles[0].section := 0; myArticles[0].expiryDate := '29/02/2012'; myArticles[0].alterPrice := 0; myArticles[0].plu := StrToInt(ArtikelTasteEdit.Text); myArticles[0].priceFactor := 0;
ergebnis := ItemsSend(@myScales, 1, @myArticles, 1, 1, 2);
ArtikelNameEdit.Text := ergebnis; end; |
Alles, was ich bis jetzt hinbekommen habe, ist ein Kommunikations-Statusfenster, in dem die Einträge, die ich aus meinen C#-Versuchen kenne, fehlen. Dann schmiert das Programm ab. Deswegen vermute ich eine misslungene Parameter-Übergabe.
Sorry, dass ich, kaum registriert, gleich mit sowas komme, aber ich komm da grad so nicht weiter.
Bin für jeden Hinweis dankbar.
Ach ja, ich hoffe, ich habs im richtigen Unterforum gepostet. Moderiert von Narses: Topic aus Sonstiges (Delphi) verschoben am Di 06.03.2012 um 14:58
|
|
uall@ogc
      
Beiträge: 1826
Erhaltene Danke: 11
Win 2000 & VMware
Delphi 3 Prof, Delphi 7 Prof
|
Verfasst: Mi 07.03.12 23:18
Du solltest PACKED RECORD verwenden und PWideChar für LPWSTR (in den Records). Außerdem @myScales[0] übergeben wenn du dynamische Array verwendest.
_________________ wer andern eine grube gräbt hat ein grubengrabgerät
- oder einfach zu viel zeit
Für diesen Beitrag haben gedankt: doll1
|
|
GuaAck
      
Beiträge: 378
Erhaltene Danke: 32
Windows 8.1
Delphi 10.4 Comm. Edition
|
Verfasst: Do 08.03.12 00:24
Hallo,
vielleicht hast Du ja ein klein wenig Verständnis für Assembler-Code. Dann hilft folgender Weg:
Breakpoint auf den Aufruf einer DLL-Funktion setzten, dann nach Auflaufen auf den Breakpoint das Debug-Fenster CPU-Fenster einschalten und Code schrittweise ausführen.
Dann kannst Du verfolgen, wie der Delphi-Code die Variablen auf den Stack packt und der C++ Code es wieder abholt bzw. nutzt. Stimmt die Datenlänge der enzelnen Daten? (z. B. Integer gibt es als 16 Bit, 32 Bit und 64 Bit). Wird ein Pointer abgelegt oder der Zahlenwert? Stimmt die Reihenfolge? Und schließlich: Wer räumt den Stack am Ende der Funktion auf, die DLL-Funktion oder das aufrufende Programm?
Meine Assemblerzeit liegt mehr als 20 Jahre zurück, dennoch reichen meine Kenntnisse dafür, es sind also wirklich nur Grundkenntnisse nötig. Ich bin jedenfalls bisher auf diesem Weg immer schnell zum Ziel gekommen.
Gruß
GuaAck
Für diesen Beitrag haben gedankt: doll1
|
|
doll1 
Hält's aus hier
Beiträge: 3
Win7, Linux
Delphi XE, VS2010
|
Verfasst: Do 08.03.12 16:03
uall@ogc hat folgendes geschrieben : | Du solltest PACKED RECORD verwenden und PWideChar für LPWSTR (in den Records). Außerdem @myScales[0] übergeben wenn du dynamische Array verwendest. |
Da hab ich wieder was gelernt  Vielen Dank dafür. Geht!
Jetzt habe ich nur noch das Problem, dass der String, den die Funktion zurückgeben soll, ein nicht lesbarer ist.
Quelltext 1:
| DIBALSCOP_API LPSTR WINAPI ItemsSend (Scale * myScales, int numScales, Item * myItems, int numItems, int showWindow, int closeTime); |
Wegen dem LPSTR in der Deklaration habe ich die Funktion in Delphi mal als PChar deklariert. Deklariere ich sie gleich als ansistring, schmiert sie mir auch gleich ab.
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| function ItemsSend(myScales: Pointer; numScales: integer; myItems: Pointer; numItems: integer; showWindow: integer; closeTime: integer): PChar; stdcall;
ergebnis: PChar;
ergebnis := ItemsSend(@myScales[0], 1, @myArticles[0], 1, 1, 10);
ArtikelNameEdit.Text := ergebnis^; ArtikelNameEdit.Text := ergebnis; ArtikelNameEdit.Text := widestring(ergebnis^); ArtikelNameEdit.Text := ansistring(ergebnis^); ArtikelNameEdit.Text := ansistring(ergebnis); |
Wo denke ich da schon wieder falsch?
Ach ja, im Erfolgsfall sollte da einfach 'OK' und im Fehlerfall eine IP-Adresse erscheinen... (Tut es auch, jedenfalls mit C#)
GuaAck hat folgendes geschrieben : | Hallo,
vielleicht hast Du ja ein klein wenig Verständnis für Assembler-Code. Dann hilft folgender Weg:
[...]
Meine Assemblerzeit liegt mehr als 20 Jahre zurück, dennoch reichen meine Kenntnisse dafür, es sind also wirklich nur Grundkenntnisse nötig. Ich bin jedenfalls bisher auf diesem Weg immer schnell zum Ziel gekommen.
Gruß
GuaAck |
Ich hab mal ausgiebig in 8052- und 68k-Assembler programmiert. Danke für den Tipp.
|
|
Martok
      
Beiträge: 3661
Erhaltene Danke: 604
Win 8.1, Win 10 x64
Pascal: Lazarus Snapshot, Delphi 7,2007; PHP, JS: WebStorm
|
Verfasst: Do 08.03.12 21:16
Du hast XE, steht in deinem Profil. Dann wäre der passende Typ PAnsiChar.
_________________ "The phoenix's price isn't inevitable. It's not part of some deep balance built into the universe. It's just the parts of the game where you haven't figured out yet how to cheat."
Für diesen Beitrag haben gedankt: doll1
|
|
doll1 
Hält's aus hier
Beiträge: 3
Win7, Linux
Delphi XE, VS2010
|
Verfasst: Fr 09.03.12 10:32
Martok hat folgendes geschrieben : | Du hast XE, steht in deinem Profil. Dann wäre der passende Typ PAnsiChar. |
Wow. Danke, geht. Vielleicht kann ich mich ja doch noch irgendwann mit Delphi anfreunden
Mit dem Forum auf jeden Fall.
|
|
|