0

I'm creating a new app in XE3 but using some units created in D2007.

I"m getting an error when freeing a TStringList data item. Here's the code that creates the data item FSQL:

procedure TPayorDM.DataModuleCreate(Sender: TObject);
begin
  FPayorDRM := TDRM.Create;
  FSQL := TStringList.Create;
end;

Here's the code that is getting the error:

procedure TPayorDM.DataModuleDestroy(Sender: TObject);
begin
  FreeAndNil(FSQL);
  if T_Payor.Active then T_Payor.Close;
  FreeAndNil(FPayorDRM);
end;

The error occurs on 'FreeAndNil(FSQL);'. I have tried 'FSQL.Free' and I get the same result.

Here's the error I'm getting:

Project: PayorUpdate.exe raised exception class EInvalidPointer with message 'Invalid pointer operation.

When I break blue arrows (debug mode) is pointing to _FreeMem(Pointer(Self)); in the procedure TObject.FreeInstance in System unit as follows:

procedure TObject.FreeInstance;
begin
  CleanupInstance;
  _FreeMem(Pointer(Self));
end;

If I don't free the TStringList data item I would have a memory leak in the app.

Is there possibly a configuration option I need to set? I've search with google and have not found anything that explains what I am doing wrong other than one of the three possibilities:

  • It was allocated by some other memory manager.
  • It had already been freed once before.
  • It had never been allocated by anything.

If I put a try ... except... I'm able to get around the issue, but I prefer not to do this.

BTW, I have another TStringList in different unit and I create and FreeAndNil and I do not get any error.

Here is entire source:


    unit PayorDataMgr;

    interface

    uses
      SysUtils,
      Classes,
      Dialogs,
      NativeXML,
      adscnnct,
      DB,
      adsdata,
      adsfunc,
      adstable,
      ace,
      cbs.drm,
      cbs.utils,
      cbs.LogFiles;

    const
      POLICY_TYPES: array[1..3] of string = ('Primary','Secondary','Tertiary');

    type
      TPayorRecord = Record
        ASSIGNBENEFITS: Boolean;
        AUTHORIZE: Boolean;
        BATCHBILL: Boolean;
        CLAIMMAX: Integer;
        DISCONTINUED: TDateTime;
        DISPENSEUPDATE: Boolean;
        EHRSIGNOFF: Boolean;
        EMCDEST: String;
        FORM: String;
        GOVASSIGN: Boolean;
        HIDE: Boolean;
        IGRPUNIQUE: Integer;
        LEGACYPLAN: String;
        LEGACYTYPE: String;
        LOCALATTN: String;
        LOCALCITY: String;
        LOCALNAME: String;
        LOCALPHONE: String;
        LOCALSTATE: String;
        LOCALSTREET: String;
        LOCALZIP: String;
        MASTERATTN: String;
        MASTERCITY: String;
        MASTERNAME: String;
        MASTERPHONE: String;
        MASTERSTATE: String;
        MASTERSTREET: String;
        MASTERZIP: String;
        MEDIGAPCODE: String;
        MEDIGAPPAYOR: Boolean;
        MEDPLANGUID: String;
        MODIFIED: TDateTime;
        NEICCODE: String;
        NEICTYPESTDC: Integer;
        OWNER: String;
        PAYORGUID: String;
        PAYORSUBTYPESTDC: Integer;
        PAYORTYPESTDC: Integer;
        PAYORUNIQUE: Integer;
        PAYPERCENT: Integer;
        RTCODE: String;
        SRXPLANGUID: String;
        STATEFILTER: String;
        procedure Clear;
      End;

      TPayors = Record
      private
        function _pGetCount: Integer;
      public
        Items: Array of TPayorRecord;
        procedure Add(const aItem:TPayorRecord);
        function CarriersList:TStrings;
        procedure Free;
        function GetPayorGuid(const aPAYORUNIQUE:Integer):String;
        function IndexOfIgrpUnique(Const aIGRPUNIQUE:Integer):Integer;
        function IndexOfPayorUnique(Const aPAYORUNIQUE:Integer):Integer;
        procedure SortByName;
        property Count:Integer Read _pGetCount;
      End;

      TPayorDM = class(TDataModule)
        CommonConnection: TAdsConnection;
        T_Payor: TAdsTable;
        Q_Payor: TAdsQuery;
        procedure DataModuleDestroy(Sender: TObject);
        procedure DataModuleCreate(Sender: TObject);
      private
        FPayorDRM: TDRM;
        FSQL: TStringList;
        function _LoadRecordFromTable:TPayorRecord;
        function _newIDSTRING(const aFormat:String='F'):String;
        { Private declarations }
        procedure _pSetConnectionHandle(const Value: Integer);
        procedure _pSetErrorMessage(const Value: String);
        procedure _psetSQL(const Value: TStringList);

        { Private properties }
        property ErrorMessage:String Write _pSetErrorMessage;
      public
        function AddPayor(var aPAYORRECORD:TPAYORRECORD):Boolean;
        function ExecuteScript(const aTo,aFrom:string):Boolean;
        function FindPayor(const aPAYORGUID:String):Boolean;overload;
        function FindPayor(const aPAYORUNIQUE:Integer):Boolean;overload;
        function GetPayorData:TDRM;
        function GetRecordCount(const aData:String):Integer;
        function LoadCarriers(const aHide:boolean = False):TPayors;
        function LoadPayor:TPayorRecord;
        function OpenTable:Boolean;
        function UpdateFromXML(const aPayorNode:TXMLNode):boolean;
        { Public declarations }
        property ConnectionHandle:Integer Write _pSetConnectionHandle;
        property DynamicPayorFields:TDRM Read FPayorDRM;
        property SQL:TStringList Read FSQL Write _psetSQL;
      end;

    var
      PayorDM: TPayorDM;

    implementation

    {$R *.dfm}

    function TPayorDM.AddPayor(var aPAYORRECORD: TPAYORRECORD): Boolean;
    begin
      Result := False;
      if IsNull(aPAYORRECORD.LOCALNAME) then Exit;
      { Create uniques }

      { Add Record }
      if not T_Payor.Active then
        if not OpenTable  then Exit;
      with T_Payor do
      try
        Insert;
        FieldByName('PAYORGUID').AsString := _newIDSTRING;
        FieldByName('MASTERNAME').AsString := aPAYORRECORD.MASTERNAME;
        FieldByName('MASTERSTREET').AsString := aPAYORRECORD.MASTERSTREET;
        FieldByName('MASTERCITY').AsString := aPAYORRECORD.MASTERCITY;
        FieldByName('MASTERSTATE').AsString := aPAYORRECORD.MASTERSTATE;
        FieldByName('PAYORTYPESTDC').AsInteger := aPAYORRECORD.PAYORTYPESTDC;
        FieldByName('MASTERZIP').AsString := aPAYORRECORD.MASTERZIP;
        FieldByName('MASTERATTN').AsString := aPAYORRECORD.MASTERATTN;
        FieldByName('MASTERPHONE').AsString := aPAYORRECORD.MASTERPHONE;
        FieldByName('NEICCODE').AsString := aPAYORRECORD.NEICCODE;
        FieldByName('RTCODE').AsString := aPAYORRECORD.RTCODE;
        FieldByName('STATEFILTER').AsString := aPAYORRECORD.STATEFILTER;
        FieldByName('NEICTYPESTDC').AsInteger := aPAYORRECORD.NEICTYPESTDC;
        FieldByName('PAYORSUBTYPESTDC').AsInteger := aPAYORRECORD.PAYORSUBTYPESTDC;
        FieldByName('OWNER').AsString := aPAYORRECORD.OWNER;
        FieldByName('HIDE').AsBoolean := aPAYORRECORD.HIDE;
        FieldByName('IGRPUNIQUE').AsInteger := aPAYORRECORD.IGRPUNIQUE;
        FieldByName('FORM').AsString := aPAYORRECORD.FORM;
        FieldByName('GOVASSIGN').AsBoolean := aPAYORRECORD.GOVASSIGN;
        FieldByName('CLAIMMAX').AsInteger := aPAYORRECORD.CLAIMMAX;
        FieldByName('MEDIGAPCODE').AsString := aPAYORRECORD.MEDIGAPCODE;
        FieldByName('EMCDEST').AsString := aPAYORRECORD.EMCDEST;
        FieldByName('ASSIGNBENEFITS').AsBoolean := aPAYORRECORD.ASSIGNBENEFITS;
        FieldByName('BATCHBILL').AsBoolean := aPAYORRECORD.BATCHBILL;
        FieldByName('MEDIGAPPAYOR').AsBoolean := aPAYORRECORD.MEDIGAPPAYOR;
        FieldByName('MEDPLANGUID').AsString := aPAYORRECORD.MEDPLANGUID;
        FieldByName('SRXPLANGUID').AsString := aPAYORRECORD.SRXPLANGUID;
        FieldByName('PAYPERCENT').AsInteger := aPAYORRECORD.PAYPERCENT;
        FieldByName('LOCALNAME').AsString := aPAYORRECORD.LOCALNAME;
        FieldByName('LOCALSTREET').AsString := aPAYORRECORD.LOCALSTREET;
        FieldByName('LOCALCITY').AsString := aPAYORRECORD.LOCALCITY;
        FieldByName('LOCALSTATE').AsString := aPAYORRECORD.LOCALSTATE;
        FieldByName('LOCALZIP').AsString := aPAYORRECORD.LOCALZIP;
        FieldByName('LOCALATTN').AsString := aPAYORRECORD.LOCALATTN;
        FieldByName('LOCALPHONE').AsString := aPAYORRECORD.LOCALPHONE;
        FieldByName('EHRSIGNOFF').AsBoolean := aPAYORRECORD.EHRSIGNOFF;
        FieldByName('DISCONTINUED').AsDateTime := aPAYORRECORD.DISCONTINUED;
        FieldByName('MODIFIED').AsDateTime := Now;
        FieldByName('LEGACYPLAN').AsString := aPAYORRECORD.LEGACYPLAN;
        FieldByName('LEGACYTYPE').AsString := aPAYORRECORD.LEGACYTYPE;
        FieldByName('AUTHORIZE').AsBoolean := aPAYORRECORD.AUTHORIZE;
        FieldByName('DISPENSEUPDATE').AsBoolean := aPAYORRECORD.DISPENSEUPDATE;
        Post;
        aPAYORRECORD.PAYORUNIQUE := FieldByName('PAYORUNIQUE').AsInteger;
        aPAYORRECORD.PAYORGUID := FieldByName('PAYORGUID').AsString;
        Close;
        Result := True;
      except on E: EADSDatabaseError do
      begin
        ErrorMessage := 'AddPayor: ERRORCODE: ' + IntToStr(e.ACEErrorCode) +
          ' ERROR: ' + e.Message;
      end;
      end;
    end;

    procedure TPayorDM.DataModuleCreate(Sender: TObject);
    begin
      FPayorDRM := TDRM.Create;
      FSQL := TStringList.Create; { FSQL Created }
   end;

    procedure TPayorDM.DataModuleDestroy(Sender: TObject);
    begin
      try
        FSQL.Free; { FSQL destroyed - work around to get unit to run without error}
      except

      end;
      if T_Payor.Active then T_Payor.Close;
      FreeAndNil(FPayorDRM);
    end;

    function TPayorDM.ExecuteScript(const aTo, aFrom: string):Boolean;
    begin
      Result := False;
      if FSQL.Count = 0 then exit;
      with Q_Payor do
      try
        if Active then Close;
        SQL := FSQL;
        ParamByName('to').Text := aTo;
        ParambyName('from').Text := aFrom;
        ExecSQL;
        if Active then Close;
        Result := True;
      except on E: EADSDatabaseError do
      begin
        ErrorMessage := 'ExecuteScript: ERRORCODE: ' + IntToStr(e.ACEErrorCode) +
          ' ERROR: ' + e.Message + ' SQL: ' + Q_Payor.SQL.Text;
      end;
      end;
    end;

    function TPayorDM.FindPayor(const aPAYORUNIQUE: Integer): Boolean;
    begin
      T_Payor.IndexName := 'PAYORUNIQUE';
      Result := T_Payor.FindKey([aPAYORUNIQUE]);
    end;

    function TPayorDM.FindPayor(const aPAYORGUID: String): Boolean;
    begin
      T_Payor.IndexName := 'PAYORGUID';
      Result := T_Payor.FindKey([aPAYORGUID]);
    end;

    function TPayorDM.GetPayorData: TDRM;
    begin
      if FPayorDRM.Count = 0 then
        FPayorDRM.BuildDRMList(T_Payor);
      Result := FPayorDRM;
    end;


    function TPayorDM.GetRecordCount(const aData:string): Integer;
    begin
      Result := 0;
      if FSQL.Count = 0 then exit;
      with Q_Payor do
      try
        if Active then Close;
        SQL := FSQL;
        ParamByName('data').AsString := aData;
        Open;
        Result := RecordCount;
        Close;
      except on E: EADSDatabaseError do
      begin
        ErrorMessage := 'GetRecordCount: ERRORCODE: ' + IntToStr(e.ACEErrorCode) +
          ' ERROR: ' + e.Message;
      end;
      end;

    end;

    function TPayorDM.LoadCarriers(const aHide: boolean): TPayors;
    begin
      OpenTable;
      Result.Free;
      with T_Payor do
      begin
        First;
        while not EOF do
        begin
          if T_Payor.FieldByName('HIDE').AsBoolean = aHide then
            Result.Add(_LoadRecordFromTable);
          Next;
        end;
        First;
        Result.SortByName;
      end;
    end;

    function TPayorDM.LoadPayor: TPayorRecord;
    begin
      Result.Clear;
      try
        if not T_Payor.active then exit;
        if T_Payor.RecNo = 0 then exit;
        Result := _LoadRecordFromTable;
      except on E: EADSDatabaseError do
      begin
        ErrorMessage := 'LoadPayor: ERRORCODE: ' + IntToStr(e.ACEErrorCode) +
          ' ERROR: ' + e.Message;
      end;
      end;
    end;

    function TPayorDM.OpenTable: Boolean;
    begin
      Result := False;
      with T_Payor do
      try
        if not Active then Open;
        FPayorDRM.BuildDRMList(T_Payor);
        FPayorDRM.LoadValues(T_Payor); { test }
        FPayorDRM.ExportDRMList; { test }
        Result := True;
      except on E: EADSDatabaseError do
      begin
        ErrorMessage := 'OpenTable: ERRORCODE: ' + IntToStr(e.ACEErrorCode) +
          ' ERROR: ' + e.Message;
      end;
      end;
    end;

    function TPayorDM.UpdateFromXML(const aPayorNode: TXMLNode): boolean;
    var
      fKeyData:TXMLNode;
      Idx,fPAYORUNIQUE:Integer;
    begin
      Result := False;
      if not Assigned(aPayorNode) then Exit;
      try
        if FPayorDRM.Count = 0 then
          FPayorDRM.BuildDRMList(T_Payor);
        FPayorDRM.ClearValues;
        fKeyData := aPayorNode.FindNode('KeyData');
        FPayorDRM.FindRecordFromKeyData(fKeyData,T_Payor);
        fPAYORUNIQUE := FPayorDRM.FieldByName('PAYORUNIQUE').AsInteger;
        FPayorDRM.LoadValues(aPayorNode);
        if fPAYORUNIQUE = 0 then
        begin
          FPayorDRM.FieldByName('PAYORUNIQUE').AsInteger := 0;
          FPayorDRM.FieldByName('PAYORGUID').AsString := _newIDSTRING;
          FPayorDRM.FieldByName('MODIFIED').AsDate := Now;
          FPayorDRM.AddRecord(T_Payor)
        end
        else
        begin
          FPayorDRM.FieldByName('MODIFIED').AsDate := Now;
          FPayorDRM.UpdateRecord(T_Payor);
        end;
      except on e:exception do
      begin
        ErrorMessage := 'UpdateFromXML: ERROR: ' + e.Message;
      end;
      end;
    end;

    function TPayorDM._LoadRecordFromTable: TPayorRecord;
    begin
      with T_Payor do
      begin
        Result.PAYORUNIQUE := FieldByName('PAYORUNIQUE').AsInteger;
        Result.PAYORGUID := FieldByName('PAYORGUID').AsString;
        Result.MASTERNAME := FieldByName('MASTERNAME').AsString;
        Result.MASTERSTREET := FieldByName('MASTERSTREET').AsString;
        Result.MASTERCITY := FieldByName('MASTERCITY').AsString;
        Result.MASTERSTATE := FieldByName('MASTERSTATE').AsString;
        Result.PAYORTYPESTDC := FieldByName('PAYORTYPESTDC').AsInteger;
        Result.MASTERZIP := FieldByName('MASTERZIP').AsString;
        Result.MASTERATTN := FieldByName('MASTERATTN').AsString;
        Result.MASTERPHONE := FieldByName('MASTERPHONE').AsString;
        Result.NEICCODE := FieldByName('NEICCODE').AsString;
        Result.RTCODE := FieldByName('RTCODE').AsString;
        Result.STATEFILTER := FieldByName('STATEFILTER').AsString;
        Result.NEICTYPESTDC := FieldByName('NEICTYPESTDC').AsInteger;
        Result.PAYORSUBTYPESTDC := FieldByName('PAYORSUBTYPESTDC').AsInteger;
        Result.OWNER := FieldByName('OWNER').AsString;
        Result.HIDE := FieldByName('HIDE').AsBoolean;
        Result.IGRPUNIQUE := FieldByName('IGRPUNIQUE').AsInteger;
        Result.FORM := FieldByName('FORM').AsString;
        Result.GOVASSIGN := FieldByName('GOVASSIGN').AsBoolean;
        Result.CLAIMMAX := FieldByName('CLAIMMAX').AsInteger;
        Result.MEDIGAPCODE := FieldByName('MEDIGAPCODE').AsString;
        Result.EMCDEST := FieldByName('EMCDEST').AsString;
        Result.ASSIGNBENEFITS := FieldByName('ASSIGNBENEFITS').AsBoolean;
        Result.BATCHBILL := FieldByName('BATCHBILL').AsBoolean;
        Result.MEDIGAPPAYOR := FieldByName('MEDIGAPPAYOR').AsBoolean;
        Result.MEDPLANGUID := FieldByName('MEDPLANGUID').AsString;
        Result.SRXPLANGUID := FieldByName('SRXPLANGUID').AsString;
        Result.PAYPERCENT := FieldByName('PAYPERCENT').AsInteger;
        Result.LOCALNAME := FieldByName('LOCALNAME').AsString;
        Result.LOCALSTREET := FieldByName('LOCALSTREET').AsString;
        Result.LOCALCITY := FieldByName('LOCALCITY').AsString;
        Result.LOCALSTATE := FieldByName('LOCALSTATE').AsString;
        Result.LOCALZIP := FieldByName('LOCALZIP').AsString;
        Result.LOCALATTN := FieldByName('LOCALATTN').AsString;
        Result.LOCALPHONE := FieldByName('LOCALPHONE').AsString;
        Result.EHRSIGNOFF := FieldByName('EHRSIGNOFF').AsBoolean;
        Result.DISCONTINUED := FieldByName('DISCONTINUED').AsDateTime;
        Result.MODIFIED := FieldByName('MODIFIED').AsDateTime;
        Result.LEGACYPLAN := FieldByName('LEGACYPLAN').AsString;
        Result.LEGACYTYPE := FieldByName('LEGACYTYPE').AsString;
        Result.AUTHORIZE := FieldByName('AUTHORIZE').AsBoolean;
        Result.DISPENSEUPDATE := FieldByName('DISPENSEUPDATE').AsBoolean;
      end;
    end;

    function TPayorDM._newIDSTRING(const aFormat: String): String;
    begin
      Result := '';
      try
        with Q_Payor do
        try
          SQL.Clear;
          SQL.Add('SELECT NEWIDSTRING( "' + aFormat + '" ) AS GUID FROM system.iota');
          Open;
          Result := FieldByName('GUID').AsString;
          Close;
        except on E: EADSDatabaseError do
        begin
          ErrorMessage := '_newIDSTRING: ERRORCODE: ' + IntToStr(e.ACEErrorCode) +
            ' ERROR: ' + e.Message;
        end;
        end;
      finally

      end;
    end;

    procedure TPayorDM._pSetConnectionHandle(const Value: Integer);
    begin
      if T_Payor.Active then T_Payor.Close;
      CommonConnection.SetHandle(Value);
      OpenTable;
    end;

    procedure TPayorDM._pSetErrorMessage(const Value: String);
    begin
      WriteError('[TPayorDM]' + Value,LogFilename);
    end;

    procedure TPayorDM._psetSQL(const Value: TStringList);
    begin
      FSQL := Value;
    end;

    { TPayorRecord }

    procedure TPayorRecord.Clear;
    begin
      PAYORUNIQUE := 0;
      PAYORGUID := '';
      MASTERNAME := '';
      MASTERSTREET := '';
      MASTERCITY := '';
      MASTERSTATE := '';
      PAYORTYPESTDC := 0;
      MASTERZIP := '';
      MASTERATTN := '';
      MASTERPHONE := '';
      NEICCODE := '';
      RTCODE := '';
      STATEFILTER := '';
      NEICTYPESTDC := 0;
      PAYORSUBTYPESTDC := 0;
      OWNER := '';
      HIDE := False;
      IGRPUNIQUE := 0;
      FORM := '';
      GOVASSIGN := False;
      CLAIMMAX := 0;
      MEDIGAPCODE := '';
      EMCDEST := '';
      ASSIGNBENEFITS := False;
      BATCHBILL := False;
      MEDIGAPPAYOR := False;
      MEDPLANGUID := '';
      SRXPLANGUID := '';
      PAYPERCENT := 0;
      LOCALNAME := '';
      LOCALSTREET := '';
      LOCALCITY := '';
      LOCALSTATE := '';
      LOCALZIP := '';
      LOCALATTN := '';
      LOCALPHONE := '';
      EHRSIGNOFF := False;
      DISCONTINUED := 0;
      MODIFIED := 0;
      LEGACYPLAN := '';
      LEGACYTYPE := '';
      AUTHORIZE := False;
      DISPENSEUPDATE := False;
    end;

    { TPayors }

    procedure TPayors.Add(const aItem: TPayorRecord);
    begin
      SetLength(Items,Count + 1);
      Items[Count - 1] := aItem;
    end;

    function TPayors.CarriersList: TStrings;
    var
      I: Integer;
    begin
      Result := TStringList.Create;
      Result.Clear;
      SortbyName;
      try
      for I := 0 to Count - 1 do
        Result.Add(Items[I].LOCALNAME);
      finally

      end;
    end;

    procedure TPayors.Free;
    begin
      Items := Nil;
    end;

    function TPayors.GetPayorGuid(const aPAYORUNIQUE: Integer): String;
    var
      Idx:Integer;
    begin
      Result := '';
      Idx := IndexOfPayorUnique(aPAYORUNIQUE);
      if not (Idx = -1) then
        Result := Items[Idx].PAYORGUID;
    end;

    function TPayors.IndexOfIgrpUnique(const aIGRPUNIQUE: Integer): Integer;
    var
      I: Integer;
    begin
      Result := -1;
      for I := 0 to Count - 1 do
        if Items[I].IGRPUNIQUE = aIGRPUNIQUE then
        begin
          Result := I;
          Break;
        end;
    end;

    function TPayors.IndexOfPayorUnique(const aPAYORUNIQUE: Integer): Integer;
    var
      I: Integer;
    begin
      Result := -1;
      for I := 0 to Count - 1 do
        if Items[I].PAYORUNIQUE = aPAYORUNIQUE then
        begin
          Result := I;
          Break;
        end;
    end;

    procedure TPayors.SortByName;
    var
      fSort:TStringList;
      fParse:TStrings;
      I,Idx: Integer;
      fTempPayor:TPayors;
    begin
      fSort := TStringList.Create;
      fParse := TStringList.Create;
      fTempPayor.Items := Self.Items;
      fSort.Sorted := True;
      try
        for I := 0 to Count - 1 do
          fSort.Add(Items[I].LOCALNAME + #9 + IntToStr(I));
        Items := Nil;
        for I := 0 to fSort.Count - 1 do
          begin
            cbs.utils.ParseDelimited(fParse,fSort[I],#9);
            Idx := StrToInt(fParse[1]);
            Add(fTempPayor.Items[Idx]);
          end;
      finally
        fTempPayor.Free;
        fParse.Free;
        fSort.Free;
      end;
    end;

    function TPayors._pGetCount: Integer;
    begin
      Result := Length(Items);
    end;

    end.

Danilo Casa
  • 506
  • 1
  • 9
  • 18
Rich R
  • 367
  • 4
  • 15
  • 1
    The error is not in the code you have shown – David Heffernan Jul 17 '14 at 20:48
  • @Mason As well as another question related to a keyboard hook... – Jerry Dodge Jul 17 '14 at 21:56
  • 2
    @JerryDodge Keyboard hooks are not necessarily evil. In that specific case Rich was mistaken in believing that a keyboard hook was needed to handle input events in his own app. There's no sign of malware here, and I think that the comments in response to Rich's question have been way out of line. – David Heffernan Jul 18 '14 at 09:09
  • @DavidHeffernan: I agree. The fact that the name TDRM is used does not have to mean anything, nor does the question about keyboard hooks. – Rudy Velthuis Jul 18 '14 at 09:13
  • You present three possible causes. Without seeing all the code, it is not possible to see which one it is, but the most likely of these three is point two: **it has already been freed before**. – Rudy Velthuis Jul 18 '14 at 09:14
  • 3
    @Rich I believe your problem to be valid, but your question is currently not answerable. As I said in my very first comment, the error is not in the code that you show. You need to give us enough detail to be able to diagnose the problem. Clearly it is normal to create an object and then subsequently destroy it. Something else must be interfering. – David Heffernan Jul 18 '14 at 09:15
  • 1
    I guess I should not mention the issue of using FreeAndNil. – Rudy Velthuis Jul 18 '14 at 09:29
  • @Rich Try installing a copy of FastMM4 (freeware replacement memory manager from SourceForge) in your project and enable its FullDebugMode flag in its Inc file. FDM writes a signature around allocated memory blocks that enables it to detect memory overwrites. Also it can detect "double-frees", speaking of which, if you put a breakpoint on FreeAndNil(FSQL) in TPayorDM.DataModuleDestroy, how many times does it trip? – MartynA Jul 19 '14 at 06:08
  • Rudy, I am showing the code related to the variable FSQL, there is no other reference to this variable in the unit. TO ALL: this unit was developed with D2007 and worked without error. It did not get an error until compiled with Delphi XE3. – Rich R Jul 21 '14 at 14:53
  • TO ALL: I have included the entire code for the PayorDataMgr unit. If you can find where I free FSQL at another location, please let me know, I am unable to find it. – Rich R Jul 21 '14 at 16:16

1 Answers1

7

You are (most probably) double freeing a stringlist (and never freeing at least one). The problem is in the setter of your 'SQL' property (which is backed by the 'FSQL' field):

procedure TPayorDM._psetSQL(const Value: TStringList);
begin
  FSQL := Value;
end;

Here you are loosing the reference to the already existing stringlist (LHS). Consider the below scenario:

You call

PayorDM.SQL := AStringList;

and the reference to the private field you created in the constructor is gone, instead you keep a reference to 'AStringList'. After that at some point you destroy 'AStringList', now the 'FSQL' field is a stale pointer. When in the destructor you call

FSQL.Free;

you get an invalid pointer operation.

Change your setter to:

procedure TPayorDM._psetSQL(const Value: TStringList);
begin
  FSQL.Assign(Value);
end;
Sertac Akyuz
  • 54,131
  • 4
  • 102
  • 169
  • Sertac. thanks. That is awesome. I've had issues with this before this may be an issue with several of my apps. This worked perfect. Again thanks. Rich – Rich R Jul 21 '14 at 21:46