Access Violation on Procedure Exit lazarus / 67-Windows ---------------------------------------------------------------------- therealhades · 2024-05-29 07:28 Hello everyone, i have the following problem and hope that somebody has an idea what i'm doing wrong. I defined a record: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i TStringVar = record    VarName: String;    Handle: LongWord;    Data: String;end;  and a procedure to read a String Value from a PLC: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i 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[1]);  if ads = 0 then aVar.Data:= PlcStringToString(tmp);  ShowMessage('in Procedure: ' + aVar.Data);end;  I call this procedure in another procedure (btn[0] is of type TStringVar): Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i ReadStringVar(btn[0]);ShowMessage('after procedure: ' + btn[0].Data);  Now i have the following Situation: If i compile this code for Win32 or Win64 everything works fine. But if I compile this code for WinCE, only the ShowMessage inside the ReadStringVar procedure is called (with the correct Value from PLC) and then I got an Access Violation and the ShowMessage from the original procedure is not called. Can anybody tell me what I'm doing wrong? As I said, this only happens with WinCE, on Win32 everything works like a charm. Best regards Bjoern PS: Lazarus Version is 3.2, fpc is 3.2.2 ---------------------------------------------------------------------- Zvoni · 2024-05-29 07:38 Line 11, last Parameter looks fishy to me. shouldn't that be @tmp[0]? tmp is dynamic array of char, and first char should be in Member 0 ---------------------------------------------------------------------- therealhades · 2024-05-29 07:49 You're right, it was [1] because i tried with Ansistring first. I changed it to Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i ads:= AdsSyncReadReq(@AMS, ADSIGRP_SYM_VALBYHND, aVar.Handle, Length(tmp), @tmp[0]); and got the same behavior (Access Vioalation after Procedure Exit) ---------------------------------------------------------------------- cdbc · 2024-05-29 07:58 Hi Line 7: you're using 'Length(aVar.VarName) + 1' & 'aVar.VarName[1]', when you haven't allocated *any* memory to 'aVar.VarName'  Try to insert this line just before Line 7:Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i SetLength(aVar.VarName,255); ...and maybe skip the +1 part in 'Length(aVar.VarName) + 1', I dunno... Regards Benny ---------------------------------------------------------------------- Zvoni · 2024-05-29 08:07 Quote from: cdbc on May 29, 2024, 09:58:24 amHi Line 7: you're using 'Length(aVar.VarName) + 1' & 'aVar.VarName[1]', when you haven't allocated *any* memory to 'aVar.VarName'  Try to insert this line just before Line 7:Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i SetLength(aVar.VarName,255); ...and maybe skip the +1 part in 'Length(aVar.VarName) + 1', I dunno... Regards Benny VarName is a string, so self-managed. But you might be right. Accessing external hardware is usually done with Pointer to chars, which need to be allocated ---------------------------------------------------------------------- therealhades · 2024-05-29 08:07 I allocated the memory before the procedure call, sorry for not showing this. Here is the complete procedure which calls the ReadString procedure: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TfrmMain.ReadButtonConfig;var  i, j: integer;  AdsError: LongInt;  tmp: string;begin   AdsError:= AdsPortOpen();  //ShowMessage('AdsPort: ' + AdsError.ToString);   if AMS.port <> 0 then begin    for i:= 0 to 7 do begin      j:= i + 1;      btn[i].VarName:= 'Config.Btn_Grp' + j.ToString;      btn[i].Handle:= 0;    end;  end;   ReadStringVar(btn[0]);  ShowMessage('after procedure: ' + btn[0].Data);   for i:= 1 to 7 do begin    ReadStringVar(btn[i]);  end;  btnGrp1.Caption:= btn[0].Data;  btnGrp2.Caption:= btn[1].Data;  btnGrp3.Caption:= btn[2].Data;  btnGrp4.Caption:= btn[3].Data;  btnGrp5.Caption:= btn[4].Data;  btnGrp6.Caption:= btn[5].Data;  btnGrp7.Caption:= btn[6].Data;  btnGrp8.Caption:= btn[7].Data;end;  I think Line 19 is executed fine, because I got the MessageBox from the end of the procedure, but before Line 20 is executed I got the AccessViolation (only in WinCE, Win32 works fine). The decalaration of btn: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i var  frmMain: TfrmMain;  btn: array[0..7] of TStringVar; ---------------------------------------------------------------------- Thaddy · 2024-05-29 08:11 That record is wrong anyway. I would define it as: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i TStringVar = record    VarName: String[255]; // to avoid it is a pointer type    Handle: LongWord;    Data: String;end;This assumes the string is never longer than 255 bytes, because it is a ShortString. It has no indirections, no pointers. All data is part of the record. But misusing strings to catch data from lines is not a smart way anyway. You should always catch that in binary format. Which means use a stream or a large enough buffer. ---------------------------------------------------------------------- therealhades · 2024-05-29 08:20 I changed it to Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i   TStringVar = record    VarName: String[255];    Handle: LongWord;    Data: String;  end;  Same effect. I changed the calling procedure to the following for a test: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TfrmMain.ReadButtonConfig;var  i, j: integer;  AdsError: LongInt;  tmp: string;begin   AdsError:= AdsPortOpen();  //ShowMessage('AdsPort: ' + AdsError.ToString);   if AMS.port <> 0 then begin    for i:= 0 to 7 do begin      j:= i + 1;      btn[i].VarName:= 'Config.Btn_Grp' + j.ToString;      btn[i].Handle:= 0;    end;  end;   ReadStringVar(btn[0]);  ReadStringVar(btn[0]);end;  The effect is that the first procedure call is executed and i get the MessageBox, then i get the AccessViolation and not the second MessageBox. ---------------------------------------------------------------------- Thaddy · 2024-05-29 08:27 Really? Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i var  tmp: array of char;Why not:Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i var  tmp: string[255] // and start your index at 1Without seeing more code I can't reply with any other suggestions, because I don't have your PLC. But it transmits binary data, so your code should handle the data in the binary domain. NOT as string. ---------------------------------------------------------------------- Zvoni · 2024-05-29 08:28 Single-step through your code, and report the exact line you get the AV ---------------------------------------------------------------------- Zvoni · 2024-05-29 08:37 Wait a sec..... https://infosys.beckhoff.com/english.php?content=../content/1033/tc3_a dsdll2/117520779.html&id=7570310429928352764 QuoteAdsSyncReadWriteReq Writes data synchronously into an ADS server and receives data back from the ADS device. LONG AdsSyncReadWriteReq(      PAmsAddr  pAddr,      ULONG  nIndexGroup,      ULONG  nIndexOffset,      ULONG  nReadLength,      PVOID  pReadData,      ULONG  nWriteLength,      PVOID  pWriteData ); Parameter pAddr [in] Structure with NetId and port number of the ADS server. nIndexGroup [in] Index Group. nIndexOffset [in] Index Offset. nReadLength [in] Length of the data, in bytes, returned by the ADS device. pReadData [out] Buffer with data returned by the ADS device. nWriteLength [in] Length of the data, in bytes, written to the ADS device. pWriteData [out] Buffer with data written to the ADS device.4th Parameter: Your passing SizeOf(aVar.Handle), which is a Longword, which is how many bytes? and in 5th Param you expect a handle back https://infosys.beckhoff.com/english.php?content=../content/1033/tc3_a dsdll2/117518731.html&id= QuoteAdsSyncReadReq Reads data synchronously from an ADS server. LONG AdsSyncReadReq(      PAmsAddr  pAddr,      ULONG  nIndexGroup,      ULONG  nIndexOffset,      ULONG  nLength,      PVOID  pData); Parameter pAddr [in] Structure with NetId and port number of the ADS server. nIndexGroup [in] Index Group. nIndexOffset [in] Index Offset. nLength [in] Length of the data in bytes. pData [out] Pointer to a data buffer that will receive the data.3rd Parameter expects an offset, and you pass the handle ---------------------------------------------------------------------- therealhades · 2024-05-29 08:45 Quote from: Zvoni on May 29, 2024, 10:28:54 amSingle-step through your code, and report the exact line you get the AV Since the AV only happended with WinCE target I have to build gdb server for WinCE on X86 right? Because the Device is a X86 WinCE device. Are there any X86 WinCE Binaries for gdb server? Quote3rd Parameter expects an offset, and you pass the handleYes, because in the example they use the handle as offset. The Value is read correctly, because I get the Messagebox with the correct Value if I call the procedure. ---------------------------------------------------------------------- therealhades · 2024-05-29 11:01 Quote from: Thaddy on May 29, 2024, 10:27:48 amWithout seeing more code I can't reply with any other suggestions, because I don't have your PLC. But it transmits binary data, so your code should handle the data in the binary domain. NOT as string. Here is the whole unit: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i unit main; {$mode objfpc}{$H+}//{$MODE Delphi} interface uses  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ExtCtrls, StdCtrls, Buttons,  IniFiles,  {$ifdef windows}  {$ifndef wince}  tcadsdef, tcadsapi  {$endif}  {$endif}  {$ifdef wince}  tcadsdef_CE, tcadsapi_CE  {$endif}  ; type   TStringVar = record    VarName: String[255];    Handle: LongWord;    Data: String;  end;   { TfrmMain }   TfrmMain = class(TForm)    btnRes2: TButton;    btnRes4: TButton;    btnRes3: TButton;    btnBeenden: TButton;    btnRes1: TButton;    FlowPanel1: TFlowPanel;    lblDate: TLabel;    lblTime: TLabel;    lblController: TLabel;    Panel1: TPanel;    Panel2: TPanel;    Panel3: TPanel;    cycle1000ms: TTimer;    btnGrp1: TSpeedButton;    btnGrp2: TSpeedButton;    btnGrp3: TSpeedButton;    btnGrp4: TSpeedButton;    btnGrp5: TSpeedButton;    btnGrp6: TSpeedButton;    btnGrp7: TSpeedButton;    btnGrp8: TSpeedButton;    procedure btnBeendenClick(Sender: TObject);    procedure cycle1000msTimer(Sender: TObject);    procedure FormCreate(Sender: TObject);  private    AMS: TAmsAddr;    procedure EndProgram;    procedure StartProgram;    procedure ReadConfigFile;    procedure ReadGroupStatus;    procedure ReadButtonConfig;    procedure ReadStringVar(var aVar: TStringVar);    function PlcStringToString(APlcString: array of char): string;  public   end; var  frmMain: TfrmMain;  btn: array[0..7] of TStringVar; implementation {$R *.lfm}  { TfrmMain } procedure TfrmMain.btnBeendenClick(Sender: TObject);begin  EndProgram;end; procedure TfrmMain.cycle1000msTimer(Sender: TObject);begin  lblDate.Caption:= FormatDateTime('dd.mm.yyyy', now);  lblTime.Caption:= FormatDateTime('hh:nn:ss', now);end; procedure TfrmMain.FormCreate(Sender: TObject);begin  StartProgram;end; procedure TfrmMain.EndProgram;var  i: integer;begin  for i:= 0 to 7 do begin     AdsSyncWriteReq( @AMS, ADSIGRP_RELEASE_SYMHND, $0000, sizeof( btn[i].Handle), @btn[i].Handle );  end;  AdsPortClose();  Application.Terminate;end; procedure TfrmMain.StartProgram;begin  Width:= 800;  Height:= 480;  Left:= 0;  Top:= 0;  ReadConfigFile;end; procedure TfrmMain.ReadConfigFile;var  ini: TIniFile;  sa: TStringArray;  s: string;  i: integer;begin  ini:= TIniFile.Create(Application.Location + 'Config.ini');  try    i:= ini.ReadInteger('ADS_Connection', 'Port', 0);    AMS.port:= i;    s:= ini.ReadString('General', 'ControllerName', '');    lblController.Caption:= s;    s:= ini.ReadString('ADS_Connection', 'NetID', '');    sa:= s.Split('.');    for i:= 0 to length(sa) - 1 do begin      AMS.netId.b[i]:= sa[i].ToInteger;    end;    ReadButtonConfig;  finally    FreeAndNil(ini);  end;end; procedure TfrmMain.ReadGroupStatus;begin end; procedure TfrmMain.ReadButtonConfig;var  i, j: integer;  AdsError: LongInt;begin   AdsError:= AdsPortOpen();  //ShowMessage('AdsPort: ' + AdsError.ToString);   if AMS.port <> 0 then begin    for i:= 0 to 7 do begin      j:= i + 1;      btn[i].VarName:= 'Config.Btn_Grp' + j.ToString;      btn[i].Handle:= 0;    end;  end;   ReadStringVar(btn[0]); // working, got Messagebox (last line of procedure (Line 202))  ShowMessage('test'); // not working, got AV   //for i:= 1 to 7 do begin  //  ReadStringVar(btn[i]);  //end;  //btnGrp1.Caption:= btn[0].Data;  //btnGrp2.Caption:= btn[1].Data;  //btnGrp3.Caption:= btn[2].Data;  //btnGrp4.Caption:= btn[3].Data;  //btnGrp5.Caption:= btn[4].Data;  //btnGrp6.Caption:= btn[5].Data;  //btnGrp7.Caption:= btn[6].Data;  //btnGrp8.Caption:= btn[7].Data;end; 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; 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; end.  the ADS functions are defined in the tcadsapi_ce (which is provided by PLC Vendor) unit as dll calls: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i unit tcadsapi_CE; {$MODE Delphi} interfaceuses sysutils,LCLIntf, LCLType, LMessages, TcAdsDef_CE;{TcAdsDLL Prototypes}function AdsGetDllVersion():Longint; stdcall; external 'TcAdsDllCe.dll' name 'AdsGetDllVersion'; function AdsPortClose():Longint;stdcall; external 'TcAdsDllCe.dll' name 'AdsPortClose'; function AdsPortOpen():Longint; stdcall; external 'TcAdsDllCe.dll' name 'AdsPortOpen'; function AdsGetLocalAddress( pAddr:PAmsAddr ):Longint; stdcall; external 'TcAdsDllCe.dll' name 'AdsGetLocalAddress'; function AdsSyncWriteReq(  pAddr:PAmsAddr;                             indexGroup, indexOffset, length :Longword;                             pData:Pointer ):Longint; stdcall; external 'TcAdsDllCe.dll' name  'AdsSyncWriteReq'; function AdsSyncReadReq(     pAddr:PAmsAddr;                             indexGroup, indexOffset, length:Longword;                             pData:Pointer ):Longint; stdcall; external 'TcAdsDllCe.dll' name 'AdsSyncReadReq'; function AdsSyncReadReqEx(   pAddr:PAmsAddr;                           indexGroup, indexOffset, length:Longword;                           pData:Pointer;                             pcbReturn :PLONGWORD ):Longint; stdcall; external 'TcAdsDllCe.dll' name 'AdsSyncReadReqEx';  function AdsSyncReadWriteReq(  pAddr:PAmsAddr;                               indexGroup, indexOffset, cbReadLength:Longword;                               pReadData:Pointer;                               cbWriteLength:Longword;                               pWriteData:Pointer ):Longint; stdcall; external 'TcAdsDllCe.dll' name 'AdsSyncReadWriteReq'; function AdsSyncReadWriteReqEx( pAddr:PAmsAddr;                                indexGroup, indexOffset, cbReadLength:Longword;                                pReadData:Pointer;                                cbWriteLength:Longword;                                pWriteData:Pointer;                                pcbReturn :PLONGWORD ):Longint; stdcall; external 'TcAdsDllCe.dll' name 'AdsSyncReadWriteReqEx';  function AdsSyncReadDeviceInfoReq( pAddr:PAmsAddr;                                   pDevName:PAnsiChar;                                   pVersion:PAdsVersion ):Longint;stdcall; external 'TcAdsDllCe.dll' name  'AdsSyncReadDeviceInfoReq'; function AdsSyncWriteControlReq( pAddr:PAmsAddr;                                 nAdsState, nDeviceState:Word;                                 nLength:Longword;                               pData:Pointer ):Longint; stdcall; external 'TcAdsDllCe.dll' name 'AdsSyncWriteControlReq'; function AdsSyncReadStateReq( pAddr:PAmsAddr;                              pAdsState, pDeviceState:PWORD ):Longint; stdcall; external 'TcAdsDllCe.dll' name 'AdsSyncReadStateReq'; function AdsSyncAddDeviceNotificationReq( pAddr:PAmsAddr;                                        indexGroup, indexOffset:Longword;                                        pNoteAttrib:PAdsNotificationAttrib;                                        pNoteFunc:PAdsNotificationFuncEx;                                        hUser:Longword;                                        pNotification:PLONGWORD ):Longint; stdcall; external 'TcAdsDllCe.dll' name 'AdsSyncAddDeviceNotificationReq'; function AdsSyncDelDeviceNotificationReq( pAddr:PAmsAddr;                                        hNotification:Longword ):Longint; stdcall; external 'TcAdsDllCe.dll' name 'AdsSyncDelDeviceNotificationReq'; function AdsSyncSetTimeout( nMs:Longint ):Longint; stdcall; external 'TcAdsDllCe.dll' name 'AdsSyncSetTimeout';    function AdsAmsRegisterRouterNotification(  pNoteFunc: PAmsRouterNotificationFuncEx ):Longint;  stdcall; external 'TcAdsDllCe.dll' name 'AdsAmsRegisterRouterNotification'; function AdsAmsUnRegisterRouterNotification ():Longint; stdcall; external 'TcAdsDllCe.dll' name 'AdsAmsUnRegisterRouterNotification'; ---------------------------------------------------------------------- Thaddy · 2024-05-29 13:07 - string[255] should be replaced with array[0..255] of char. (or byte) Essentially a PChar, but with a size and initialized memrory. - tmp should be of type pchar and allocated with tmp:=allocmem(256); - on exit of the method you should call freemem(tmp); The issue is that the dll has no concept of any Pascal string type, as I already suspected. They need to be PChar's or arra[0..length-1] of char /bytes (NO dynamic arrays) and they need to be initialized memory, hence allocmem. ---------------------------------------------------------------------- therealhades · 2024-05-29 14:23 Quote from: Thaddy on May 29, 2024, 03:07:47 pm- string[255] should be replaced with array[0..255] of char. (or byte) Essentially a PChar, but with a size and initialized memrory. - tmp should be of type pchar and allocated with tmp:=allocmem(256); - on exit of the method you should call freemem(tmp); The issue is that the dll has no concept of any Pascal string type, as I already suspected. They need to be PChar's or arra[0..length-1] of char /bytes (NO dynamic arrays) and they need to be initialized memory, hence allocmem. Thanks Thaddy for your help and effort. I changed the procedure to this one to have a minimalistic version: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TfrmMain.ReadStringVar(var aVar: TStringVar);var  test: array[0..15] of char;  ads: longint;  tmp_handle: LongWord;begin   // test with array of char instead string[255]  test[0]:= 'C';  test[1]:= 'o';  test[2]:= 'n';  test[3]:= 'f';  test[4]:= 'i';  test[5]:= 'g';  test[6]:= '.';  test[7]:= 'B';  test[8]:= 't';  test[9]:= 'n';  test[10]:= '_';  test[11]:= 'G';  test[12]:= 'r';  test[13]:= 'p';  test[14]:= '1';  test[15]:= Chr($00);   tmp_handle:= aVar.Handle;;  if tmp_handle = 0 then    ads:= AdsSyncReadWriteReq(@AMS, ADSIGRP_SYM_HNDBYNAME, $0000, sizeof(tmp_handle), @tmp_handle, sizeof(test), @test[0])   showMessage('Handle: ' + tmp_handle.ToString);  aVar.Handle:= tmp_handle;end;  the procedure call is: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TfrmMain.ReadButtonConfig;var  i, j: integer;  AdsError: LongInt;begin   AdsError:= AdsPortOpen();   ReadStringVar(btn[0]);  ReadStringVar(btn[0]);end;  The Result is the same. I got a Messagebox with the created Handle from the 1st Call and then the AV. I tried other PLCs from the Vendor with this Code and the Result is: CPU Atom E3815, OS WinCE (compiled with -T WinCE, -P i386) -> AVCPU Atom E3815, OS Win10 1607 LTSB (compiled with -T Win32, -P i386) -> OKCPU Arm Cortex A8, OS WinCE (compiled with -T WinCE, -P ARM) -> OK So it seems that something with my environment is problematic. I installed all CrossCompilers via fpcupdeluxe, except the x86 WinCE combo, because this was not possible. (fpcupdeluxe said "No valid CPU/OS crosscompiler found"). Therefore i built the compiler manually with informations i found on the wiki/internet. ---------------------------------------------------------------------- Thaddy · 2024-05-29 16:25 On Windows CE Pchar <> PAnsiChar but PUnicodeChar/PWideChar. Change all PChar declarations to explicit PAnsiChar and all Chars to explicit AnsiChar. Last time I programmed for CE is a long time ago, so plz consider that an oversight. CE is a unicode system since at least CE v6, which means that the string types are interpreted accordingly. ---------------------------------------------------------------------- Remy Lebeau · 2024-05-29 17:13 Quote from: therealhades on May 29, 2024, 01:01:03 pmCode: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i 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. Quote from: therealhades on May 29, 2024, 01:01:03 pmCode: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i 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: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i 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: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i function TfrmMain.PlcStringToString(APlcString: array of char): string;begin  SetString(Result, PChar(APlcString), Length(APlcString));  Result := TrimRight(Result);end; Quote from: therealhades on May 29, 2024, 01:01:03 pmCode: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i 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: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i 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: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i TStringVar = record    VarName: AnsiString;    ...end;... ads := AdsSyncReadWriteReq(..., Length(aVar.VarName) + 1, PAnsiChar(aVar.VarName));