Entwickler-Ecke
Delphi Language (Object-Pascal) / CLX - Unterschied von PChar zwischen DelphiXE und Delphi2007
chrissi68 - Do 27.10.11 18:58
Titel: Unterschied von PChar zwischen DelphiXE und Delphi2007
Hallo,
unter Delphi2007 hatte ich ein Programm zur Kommunikation mit RFID-Antennen geschrieben. Die externe Dll besitzt folgenden Funktionsaufruf:
Delphi-Quelltext
1:
| function FECOM_SetPortPara(iPortHnd: Integer; cPara: PChar; cValue: PChar): Integer; stdcall; external 'Fecom.DLL'; |
Aufgerufen habe ich die Funktion mit:
Delphi-Quelltext
1: 2: 3: 4: 5:
| var rBaudRate: PAnsiChar; . . cRet:=FECOM_SetPortPara(Reader.iPortHnd, 'Baud', rBaudRate); |
Mittlerweile benutze ich Delphi XE und das Programm funzt nicht mehr :? weil PChar jetzt Unicode-fähig ist. Anscheinend soll PChar mit PWideChar ersetzt werden. Dies
habe ich auch gemacht.....
Delphi-Quelltext
1:
| function FECOM_SetPortPara(iPortHnd: Integer; cPara: PWideChar; cValue: PWideChar): Integer; stdcall; external 'Fecom.DLL'; |
und die Variable "var rBaudRate: PWideChar" entsprechend geändert.
Leider klappt auch das nicht :? .
Ersetze ich aber PWideChar durch PAnsiChar........
Delphi-Quelltext
1: 2: 3: 4:
| function FECOM_SetPortPara(iPortHnd: Integer; cPara: PAnsiChar; cValue: PAnsiChar): Integer; stdcall; external 'Fecom.DLL'; . . cRet:=FECOM_SetPortPara(Reader.iPortHnd, 'Baud', '38400'); |
.... und rufe die Function mit dem statischen Wert auf, so klappt die Übergabe an die DLL!! :?: :?:
Vielleicht hat von Euch jemand eine Idee wie man die Parameterübergabe in Delphi XE hin bekommt, wäre klasse!
Viele Grüße
Chrissi
bummi - Do 27.10.11 19:28
der einzige Fehler dürfte sein dass Du rBaudRate: PAnsiChar; auf eine String nicht auf einen AnsiString zeigen lässt.
Wenn Du für Para und Value AnsiStrings nimmst und diese über para[1] oder PAnsiChar(para) übergibst sollte es durchlaufen.
Vielleicht kannst Du an dem Beispiel sehen was ich meine
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15:
| Procedure ShowIt(p:PAnsiChar); begin Showmessage(p); end;
procedure TForm1.Button1Click(Sender: TObject); var s:String; s2:AnsiString; begin s := 'Test'; s2 := 'Test'; ShowIt(PAnsichar(s)); ShowIt(PAnsichar(s2)); end; |
Delete - Do 27.10.11 19:49
Wenn die DLL AnsiChars haben will, dann sollte man ihr auch welche geben, weil eventuell kommt sie mit WideChars nicht zu recht.
bummi - Do 27.10.11 20:11
Fecom.DLL und Ferwa.DLL sind definitiv steinnalt
jaenicke - Fr 28.10.11 06:19
chrissi68 hat folgendes geschrieben : |
Anscheinend soll PChar mit PWideChar ersetzt werden. Dies
habe ich auch gemacht..... |
Um das einmal klarzustellen:
Nein, das ist falsch. Bis Delphi 2007 entsprach PChar = PAnsiChar. Seit Delphi 2009 entspricht PChar = PWideChar.
PChar in einer Schnittstellendefinition für eine DLL zu benutzen, war aber schon immer ein Programmierfehler, da es nicht dem konkreten Typ entspricht. Das gilt genauso für andere Metatypen wie Integer, Boolean usw., die dort auch nichts zu suchen haben. Stattdessen sollte immer ein konkreter Typ wie DWord, WordBool, ... benutzt werden um exakt zu definieren welche Größe die Datentypen haben.
Dies wurde auch schon viele Jahre vor der Umstellung auf Unicode gesagt, aber viele haben nicht darauf gehört.
(Wie auch auf die Warnungen vor dem Schreiben ins Exe-Verzeichnis z.B., beides mussten diejenigen mit der UAC in Vista bzw. Unicode in Delphi dann eben auf die harte Tour lernen.)
Wenn du jedenfalls in einer alten Schnittstelle PChar findest, ist dort immer PAnsiChar gemeint. An der Stelle musst du dann aber nach dem Ersetzen auch die Warnungen beachten, denn bei einem Cast von string (= UnicodeString ab Delphi 2009) auf PAnsiChar sollte eine Warnung vor einer bedenklichen Typumwandlung kommen.
chrissi68 - Fr 28.10.11 10:41
IHR SEID GROSSARTIG!!!!!!!!!!!!! :D :D :D :D :D :D :D :D :D :D
Vielen herzlichen Dank, jetzt funzt meine Function wieder!
Habe die PChar durch PAnsiChar ersetzt und übergebe jetzt AnsiString. Die Rückgabe erfolgt jetzt durch ein Array of AnsiChar, früher Array of Char
Hier der vollständige Code:
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:
| function TFTestRFID.OpenRFIDPort(var Reader: TReader):boolean; var cRet : Integer; cBaud : Array[0..127] of AnsiChar; cTimeOut : Array[0..127] of AnsiChar; rBaudRate : AnsiString; rFrame : AnsiString; rTimeout : AnsiString; rTxTimeControl : AnsiString; rTxDelayTime : AnsiString; rCharTimeoutMpy : AnsiString;
begin Result:=True; cRet:=0; cBaud:=#0; cTimeOut:=#0; rBaudRate:=''; rFrame:=''; rTimeOut:=''; rTxTimeControl:=''; rTxDelayTime:=''; rCharTimeoutMpy:=''; cRet:=FECOM_DetectPort(Reader.iPortNr); if cRet = 0 then begin Reader.iPortHnd:=FECOM_OpenPort(PAnsiChar(IntToStr(Reader.iPortNr))); if Reader.iPortHnd >= 0 then begin rBaudRate:=IntToStr(Reader.iBaudRate); rFrame:=Reader.sFrame; rTimeout:=IntToStr(Reader.iTimeout); rTxTimeControl:=IntToStr(1); rTxDelayTime:=IntToStr(10); rCharTimeoutMpy:=IntToStr(5); cRet:=FECOM_SetPortPara(Reader.iPortHnd, 'Baud', PAnsiChar(rBaudRate)); cRet:=FECOM_SetPortPara(Reader.iPortHnd, 'Frame', PAnsiChar(rFrame)); cRet:=FECOM_SetPortPara(Reader.iPortHnd, 'Timeout', PAnsiChar(rTimeout)); cRet:=FECOM_SetPortPara(Reader.iPortHnd, 'TxTimeControl', PAnsiChar( rTxTimeControl)); cRet:=FECOM_SetPortPara(Reader.iPortHnd, 'TxDelayTime', PAnsiChar( rTxDelayTime)); cRet:=FECOM_SetPortPara(Reader.iPortHnd, 'CharTimeoutMpy', PAnsiChar( rCharTimeoutMpy)); cRet:=FECOM_GetPortPara(Reader.iPortHnd, 'Baud', cBaud); cRet:=FECOM_GetPortPara(Reader.iPortHnd, 'Timeout', cTimeout); DisplayRFIDData('Baudrate : ' + cBaud); DisplayRFIDData('Timeout : ' + cTimeout); DisplayRFIDData('TxTimeControl : ' + rTxTimeControl); DisplayRFIDData('TxDelayTime : ' + rTxDelayTime); DisplayRFIDData('CharTimeoutMpy : ' + rCharTimeoutMpy); DisplayRFIDData('Frame : ' + rFrame); end else Result:=False; end else Result:=False; end; |
@bummi: Ja, die DLL's sind uralt, aber soweit ich weiss hat sich an der Funktionalität im Wesentlichen auch nichts großartiges geändert und
sie funktionieren noch immer, wenn nicht Embarcadero die Datentypen ändert........... :roll:
Viele Grüße
Chrissi
jaenicke - Fr 28.10.11 11:54
chrissi68 hat folgendes geschrieben : |
wenn nicht Embarcadero die Datentypen ändert........... :roll: |
Embarcadero hat sicher schon einiges falsch gemacht, aber hier nicht. Es wurden nur die Typen geändert, die dafür vorgesehen waren, wie gesagt. Dass in der Definition der DLL-Schnittstelle die falschen Typen (eben die Metatypen statt der konkreten Typen) verwendet wurden, dafür kann Embarcadero ja nichts... :roll:
Es hat eben einen Grund weshalb schon immer (gut, bei den ganz alten Versionen wie Delphi 1 weiß ich es nicht) in Delphi einmal die Unicodevariante einer API-Funktion und einmal die Ansivariante eingebunden wurde und die ohne A oder W am Ende (die man in der Regel benutzt, z.B. ShellExecute) auf die entsprechende gemappt wird (eben auf A am Ende bis Delphi 2007, z.B. ShellExecuteA, und auf W am Ende ab Delphi 2009, z.B. ShellExecuteW).
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!