Autor Beitrag
chrissi68
Hält's aus hier
Beiträge: 4



BeitragVerfasst: Do 27.10.11 18:58 
Hallo,

unter Delphi2007 hatte ich ein Programm zur Kommunikation mit RFID-Antennen geschrieben. Die externe Dll besitzt folgenden Funktionsaufruf:
ausblenden Delphi-Quelltext
1:
function FECOM_SetPortPara(iPortHnd: Integer; cPara: PChar; cValue: PChar): Integer; stdcallexternal 'Fecom.DLL';					


Aufgerufen habe ich die Funktion mit:
ausblenden 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.....

ausblenden Delphi-Quelltext
1:
function FECOM_SetPortPara(iPortHnd: Integer; cPara: PWideChar; cValue: PWideChar): Integer; stdcallexternal 'Fecom.DLL';					


und die Variable "var rBaudRate: PWideChar" entsprechend geändert.
Leider klappt auch das nicht :? .

Ersetze ich aber PWideChar durch PAnsiChar........
ausblenden Delphi-Quelltext
1:
2:
3:
4:
function FECOM_SetPortPara(iPortHnd: Integer; cPara: PAnsiChar; cValue: PAnsiChar): Integer; stdcallexternal '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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 1248
Erhaltene Danke: 187

XP - Server 2008R2
D2 - Delphi XE
BeitragVerfasst: 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
ausblenden 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;

_________________
Das Problem liegt üblicherweise zwischen den Ohren H₂♂
DRY DRY KISS
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 1248
Erhaltene Danke: 187

XP - Server 2008R2
D2 - Delphi XE
BeitragVerfasst: Do 27.10.11 20:11 
Fecom.DLL und Ferwa.DLL sind definitiv steinnalt

_________________
Das Problem liegt üblicherweise zwischen den Ohren H₂♂
DRY DRY KISS
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19326
Erhaltene Danke: 1749

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Fr 28.10.11 06:19 
user profile iconchrissi68 hat folgendes geschrieben Zum zitierten Posting springen:
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 Threadstarter
Hält's aus hier
Beiträge: 4



BeitragVerfasst: 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:

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:
function TFTestRFID.OpenRFIDPort(var Reader: TReader):boolean;
var
  cRet            : Integer;
  cBaud           : Array[0..127of AnsiChar;
  cTimeOut        : Array[0..127of 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19326
Erhaltene Danke: 1749

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Fr 28.10.11 11:54 
user profile iconchrissi68 hat folgendes geschrieben Zum zitierten Posting springen:
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).