Altro Access violation at address 004cb7c2 (Delphi XE)

mrcamarium

Utente Silver
7 Gennaio 2022
105
24
6
56
Dovendo adattare questo pezzo di codice ad un Form:
Codice:
var
  client: TIdTCPClient;
begin
  client := TIdTCPClient.Create;
  client.Port := 2630;
  client.Host := '127.0.0.1';
  client.ReadTimeout := 10000;
  Writeln('Starting client...');

  while True do
  begin
    try
      if not client.Connected then
      begin
        client.Connect;
        Writeln('Connected!');
        SendHello(client.IOHandler);
      end;

      while client.Connected do
        if not HandleResponse(client.IOHandler) then
          break;

    except
      on E: Exception do
        Writeln(E.ClassName, ': ', E.Message);
    end;
  end;
  Writeln('Closing');
end.
L'ho compilato in questo modo. Ho usato due bottoni uno per la connessione e l'altro per ottenere i dati:
Codice:
procedure TForm1.Button1Click(Sender: TObject);
var
  client: TIdTCPClient;
begin
  client := TIdTCPClient.Create;
  client.Port := 2630;
  client.Host := '127.0.0.1';
  client.ReadTimeout := 10000;
  client.Connect;
  Label1.Caption := 'Connesso'
  end;

procedure TForm1.Button2Click(Sender: TObject);
begin
SendHello(client.IOHandler);
end;

Quando premo il pulsante di connessione procede bene ma quando premo info mi restituisce una finestra con questo errore:
Access violation at address 004cb7c2
allego file completo
 

Allegati

  • Sorgente.zip
    814.3 KB · Visualizzazioni: 4
client è una variabile locale di una funzione, non puoi usarla da un altra e mi sorprende che te lo abbia fatto compilare: fuori da quella funzione non è più accessibile dallo stack, come se non bastasse viene anche distrutto l'oggetto uscendo dallo scope. Sposta la dichiarazione di client tra le variabili globali della unit (rimuovila dal Button1Click):

Codice:
var
    Form1: TForm1;
    client: TIdTCPClient;

Poi se vuoi evitare di fare freeze sulla GUI quando cerchi di ricevere nuovi comandi:

Codice:
function WaitForCommand(args: Pointer): Cardinal; stdcall;
begin
    while client.Connected do
        if not HandleResponse(client.IOHandler) then
            break;
    
    Result := 0;
end;

procedure TForm1.Button2Click(Sender: TObject);
var
    dwThread: Cardinal;
begin
    SendHello(client.IOHandler);
    CreateThread(nil, 0, @WaitForCommand, nil, 0, dwThread);
end;

Nota bene che dalla funzione WaitForCommand (o da funzioni chiamata da essa) non puoi alterare l'interfaccia grafica senza fare un thread synchronize altrimenti avrai bug bizzarri apparentemente casuali: i form VCL sono thread-unsafe.
 
Quello che sto realizzando è un modello che poi devo integrare al progetto che ti ho allegato. Nel progetto che ti ho allegato io per collegarmi uso:
Codice:
procedure TForm1.ConnettiClick(Sender: TObject);
begin
  Label2.Caption := 'Disconnesso';
  client.Disconnect;
  client.Port:=2630;
  client.Host:=edit3.text;
  client.ReadTimeout := 10000;
  client.Connect();
  Label2.Caption := 'Connesso';
end;
Funziona senza problemi, ma anche nel modello che mi hai dato tu si connette. Il problema nasce solo quando premo il Button2. Adesso riguardo al Button2 ho inserito le modiche che mi hai suggerito ma mi da questo errore:
[DCC Error] Unit1.pas(159): E2003 Undeclared identifier: 'HandleResponse'
ho controllato che nella user ci fosse SysUtils.
 

Allegati

  • Sorgente.zip
    838 KB · Visualizzazioni: 4
Problema 1: hai messo un componente di tipo TIdTCPClient da designer con nome client, poi hai dichiarato di nuovo client come variabile globale, quale delle due userà il tuo codice? E che succederà se inizializzi tutto con una e poi usi l'altra che non è connessa?

Problema 2: Basta leggere l'errore: non trovo HandleResponse. Che se ricordi era la funzione che ti avevo passato nel precedente thread.

Ti consiglio di rileggere più volte il codice e gli errori che ti dà, soprattutto quando sono così chiari.
 
Problema 1: hai messo un componente di tipo TIdTCPClient da designer con nome client, poi hai dichiarato di nuovo client come variabile globale, quale delle due userà il tuo codice? E che succederà se inizializzi tutto con una e poi usi l'altra che non è connessa?

Problema 2: Basta leggere l'errore: non trovo HandleResponse. Che se ricordi era la funzione che ti avevo passato nel precedente thread.

Ti consiglio di rileggere più volte il codice e gli errori che ti dà, soprattutto quando sono così chiari.
Riguardo al fatto che ho dichiarato client come variabile è stata solo una prova, che purtroppo non ho corretto prima di inviarti il file. Invece riguarda HandleResponse non riesco a trovare la discussione dove ne abbiamo parlo.
 
Riguardo al fatto che ho dichiarato client come variabile è stata solo una prova, che purtroppo non ho corretto prima di inviarti il file. Invece riguarda HandleResponse non riesco a trovare la discussione dove ne abbiamo parlo.
Adesso il codice viene compilato:
Codice:
function ReadMessage(io: TIdIOHandler; var kind: Byte) : TIdBytes;
var
  len: UInt32;
begin
  len := io.ReadLongWord();
  kind := io.ReadByte;
  SetLength(Result, len);
  io.ReadBytes(Result, len, False);
end;

function BytesToStr(b: TIdBytes): string;
begin
  Result := TEncoding.UTF8.GetString(b);
end;

function StrToBytes(s: string) : TIdBytes;
var
  b: TBytes;
  len: Integer;
begin
  b := TEncoding.UTF8.GetBytes(s);
  len := Length(b);
  SetLength(Result, len);
  CopyMemory(Result, b, len);
end;

function HandleResponse(h: TIdIOHandler): Boolean;
begin
  result:= FALSE;
end;

function WaitForCommand(args: Pointer): Cardinal; stdcall;
begin
    while client.Connected do
        if not HandleResponse(client.IOHandler) then
            break;
    Result := 0;
end;

procedure WriteMessage(io: TIdIOHandler; kind: Byte; msg: TIdBytes);
var
  len: UInt32;
begin
  len := Length(msg);
  io.Write(len);
  io.Write(kind);
  io.Write(msg);
end;

procedure SendHello(io: TIdIOHandler);
var
  cpu: string;
  so: string;
  username: string;
  pcname: string;
  hello: string;
begin
  cpu := Tipo_cpu;
  so := InfoSO;
  username := SysUserName;
  pcname := SysComputerName;
  hello := cpu + '|' + so + '|' + username + '|' + pcname;
  WriteMessage(io, 1, StrToBytes(hello));
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  client: TIdTCPClient;
begin
  client := TIdTCPClient.Create;
  client.Port := 2630;
  client.Host := '127.0.0.1';
  client.ReadTimeout := 10000;
  client.Connect;
  Label1.Caption := 'Connesso'
  end;

procedure TForm1.Button2Click(Sender: TObject);
var
    dwThread: Cardinal;
begin
    SendHello(client.IOHandler);
    CreateThread(nil, 0, @WaitForCommand, nil, 0, dwThread);
end;
Ma continua a darmi lo stesso errore:
Errore.jpg