title: Delphi - timer inside thread generates AV
body: <p>I have the following thread code which executes correct first time. After that from time to time I get an AV on the Execute method of the thread, e.g </p>
  
  <blockquote>
    <p>Debug Output: TProcesses.Execute Access violation at address 00409C8C
    in module 'ListenOutputDebugString.exe'. Read of address 08070610
    Process ListenOutputDebugString.exe (740)</p>
  </blockquote>
  
  <p>I don't know what is generating this AV...</p>
  
  <pre><code>unit Unit3;
  
  interface
  
  uses
    Classes,
    StdCtrls,
    Windows,
    ExtCtrls,
    SysUtils,
    Variants,
    JvExGrids,
    JvStringGrid;
  
  type
    TProcesses = class(TThread)
    private
      { Private declarations }
      FTimer :  TTimer;
      FGrid  :  TJvStringGrid;
      FJobFinished : Boolean;
      procedure OverrideOnTerminate(Sender: TObject);
      procedure DoShowData;
      procedure DoShowErrors;
      procedure OverrideOnTimer(Sender: TObject);
    protected
      procedure Execute; override;
    public
      constructor Create(aGrid : TJvStringGrid);overload;
    end;
  
  implementation
  
  {TProcesses }
  
  var SharedMessage : String;
      ErrsMess      : String;
      lp            : Integer;
  
  constructor TProcesses.Create(aGrid : TJvStringGrid);
  begin
   FreeOnTerminate := True;
   FTimer := TTimer.Create(nil);
   FTimer.OnTimer := OverrideOnTerminate;
   FTimer.OnTimer := OverrideOnTimer;
   FTimer.Interval := 10000;
   FGrid := aGrid;
   inherited Create(false);
   FTimer.Enabled := true;
   FJobFinished := true;
  end;
  
  procedure TProcesses.DoShowData;
  var wStrList : TStringList;
      wi,wj : Integer;
  begin
  // FMemo.Lines.Clear;
   for wi := 1 to FGrid.RowCount-1 do
    for wj := 0 to FGrid.ColCount-1 do
     FGrid.Cells[wj,wi] := '';
   try
    try
    wStrList := TStringList.Create;
    wStrList.Delimiter := ';';
    wStrList.StrictDelimiter := true;
    wStrList.DelimitedText := SharedMessage;
  //  outputdebugstring(PChar('Processes list '+SharedMessage));
    FGrid.RowCount := wStrList.Count div 4;
    for wi := 0 to wStrList.Count-1 do
      FGrid.Cells[(wi mod 4), (wi div 4)+1] := wStrList[wi];
    Except on e:Exception do
     OutputDebugString(Pchar('TProcesses.DoShowData '+e.Message));
    end;
   finally
    FreeAndNil(wStrList);
   end;
  end;
  
  procedure TProcesses.DoShowErrors;
  begin
  // FMemo.Lines.Add('Error '+ ErrsMess);
   FGrid.Cells[1,1] := 'Error '+ ErrsMess;
   ErrsMess := '';
  end;
  
  procedure TProcesses.Execute;
    function EnumProcess(hHwnd: HWND; lParam : integer): boolean; stdcall;
    var
      pPid : DWORD;
      title, ClassName : string;
    begin
      //if the returned value in null the
      //callback has failed, so set to false and exit.
      if (hHwnd=NULL) then
      begin
        result := false;
      end
      else
      begin
        //additional functions to get more
        //information about a process.
        //get the Process Identification number.
        GetWindowThreadProcessId(hHwnd,pPid);
        //set a memory area to receive
        //the process class name
        SetLength(ClassName, 255);
        //get the class name and reset the
        //memory area to the size of the name
        SetLength(ClassName,
                  GetClassName(hHwnd,
                               PChar(className),
                               Length(className)));
        SetLength(title, 255);
        //get the process title; usually displayed
        //on the top bar in visible process
        SetLength(title, GetWindowText(hHwnd, PChar(title), Length(title)));
        //Display the process information
        //by adding it to a list box
        SharedMessage := SharedMessage +
          (className +' ;'+//'Class Name = ' +
           title +' ;'+//'; Title = ' +
           IntToStr(hHwnd) +' ;'+ //'; HWND = ' +
           IntToStr(pPid))+' ;'//'; Pid = ' +
           ;//         +#13#10;
        Result := true;
      end;
    end;
  begin
  if FJobFinished  then
   begin
    try
     FJobFinished := false;
    //define the tag flag
     lp := 0; //globally declared integer
    //call the windows function with the address
    //of handling function and show an error message if it fails
    SharedMessage := '';
    if EnumWindows(@EnumProcess,lp) = false then
     begin
        ErrsMess := SysErrorMessage(GetLastError);
        Synchronize(DoShowErrors);
     end
     else
      Synchronize(DoShowData);
     FJobFinished := true;
    Except on e:Exception do
     OutputDebugString(Pchar('TProcesses.Execute '+e.Message));
    end;
   end
  end;
  
  procedure TProcesses.OverrideOnTerminate(Sender: TObject);
  begin
   FTimer.Enabled := false;
   FreeAndNil(FTimer);
  end;
  
  procedure TProcesses.OverrideOnTimer(Sender: TObject);
  begin
    Self.Execute;
  end;
  
  end.
  </code></pre>