ReadStringVar(btn[0]); // working, got Messagebox (last line of procedure (Line 202))
ShowMessage('test'); // not working, got AV
That implies you are corrupting memory or the call stack.
function TfrmMain.PlcStringToString(APlcString: array of char): string;
var
i: integer;
begin
Result:= '';
for i:= 0 to length(APlcString) do begin
if APlcString[i] <> Chr($00) then
Result:= Result + APlcString[i]
else exit;
end;
end;
This is a buffer overflow waiting to happen if
APlcString is not null-terminated. An open array is 0-indexed, so your loop needs to use
length(APlcString)-1 (or
High(APlcString)) instead, otherwise you go out of bounds.
Rather than doing a concatenation on every loop iteration, I would suggest using
SetString() instead, eg:
function TfrmMain.PlcStringToString(APlcString: array of char): string;
var
len: integer;
begin
for len := 0 to Length(APlcString)-1 do begin
if APlcString[len] = Chr($00) then Break;
end;
SetString(Result, PChar(APlcString), len);
end;
Alternatively:
function TfrmMain.PlcStringToString(APlcString: array of char): string;
begin
SetString(Result, PChar(APlcString), Length(APlcString));
Result := TrimRight(Result);
end;
procedure TfrmMain.ReadStringVar(var aVar: TStringVar);
var
tmp: array of char;
ads: longint;
begin
if aVar.Handle = 0 then
ads:= AdsSyncReadWriteReq(@AMS, ADSIGRP_SYM_HNDBYNAME, $0000, sizeof(aVar.Handle), @aVar.Handle, Length(aVar.VarName) + 1, @aVar.VarName[1])
else ads:= 0;
SetLength(tmp, 255);
if ads = 0 then
ads:= AdsSyncReadReq(@AMS, ADSIGRP_SYM_VALBYHND, aVar.Handle, Length(tmp), @tmp[0]);
if ads = 0 then aVar.Data:= PlcStringToString(tmp);
ShowMessage('in Procedure: ' + aVar.Data);
end;
There is no need to allocate
tmp dynamically.
More importantly, a
ShortString is not null-terminated, but you are passing in a pointer directly to its characters, and passing in
+1 for its length as if a null terminator were present. You need to pass in a valid null-terminated string, eg:
procedure TfrmMain.ReadStringVar(var aVar: TStringVar);
var
sVarName: AnsiString;
tmp: array[0..255] of AnsiChar;
ads: longint;
begin
if aVar.Handle = 0 then begin
sVarName := aVar.VarName;
ads := AdsSyncReadWriteReq(@AMS, ADSIGRP_SYM_HNDBYNAME, $0000, sizeof(aVar.Handle), @aVar.Handle, Length(sVarName) + 1, PChar(sVarName));
end else
ads := 0;
if ads = 0 then begin
ads := AdsSyncReadReq(@AMS, ADSIGRP_SYM_VALBYHND, aVar.Handle, Length(tmp), @tmp[0]);
if ads = 0 then aVar.Data := PlcStringToString(tmp);
end;
ShowMessage('in Procedure: ' + aVar.Data);
end;
In which case, consider changing
TStringVar back to using
(Ansi)String instead of
String[255] for its
VarName field:
TStringVar = record
VarName: AnsiString;
...
end;
...
ads := AdsSyncReadWriteReq(..., Length(aVar.VarName) + 1, PAnsiChar(aVar.VarName));