Delphi XE3试图释放FSQL时无效指针(TStringList)
我在XE3中创建了一个新应用程序,但使用了在D2007中创建的一些单元。
释放TStringList数据项时出现错误,下面是创建数据项FSQL的代码:
procedure TPayorDM.DataModuleCreate(Sender: TObject);
begin
FPayorDRM := TDRM.Create;
FSQL := TStringList.Create;
end;
这是得到错误的代码:
procedure TPayorDM.DataModuleDestroy(Sender: TObject);
begin
FreeAndNil(FSQL);
if T_Payor.Active then T_Payor.Close;
FreeAndNil(FPayorDRM);
end;
'FreeAndNil(FSQL);'发生错误。 我已经尝试过'FSQL.Free',我得到了同样的结果。
这是我得到的错误:
项目:PayorUpdate.exe引发异常类EInvalidPointer消息'无效的指针操作。
当我打破蓝色箭头(调试模式)指向_FreeMem(指针(Self)); 在System单元中的程序TObject.FreeInstance中,如下所示:
procedure TObject.FreeInstance;
begin
CleanupInstance;
_FreeMem(Pointer(Self));
end;
如果我没有释放TStringList数据项,我会在应用程序中发生内存泄漏。
是否有可能需要设置的配置选项? 我搜索谷歌,并没有发现任何解释我做错了什么,而不是以下三种可能性之一:
如果我尝试......除了......我可以解决这个问题,但我不想这样做。
顺便说一句,我有另一个TStringList在不同的单位,我创建和FreeAndNil,我没有得到任何错误。
这里是完整的来源:
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.
你(最有可能)双释放一个字符串列表(并且永远不会释放至少一个)。 问题出在你的'SQL'属性的设置器(由'FSQL'域支持):
procedure TPayorDM._psetSQL(const Value: TStringList);
begin
FSQL := Value;
end;
在这里,您将丢失对现有字符串列表(LHS)的引用。 考虑以下情况:
你打电话
PayorDM.SQL := AStringList;
并且您在构造函数中创建的私有字段的引用已消失,而是保留对“AStringList”的引用。 之后,在某些时候你销毁'AStringList',现在'FSQL'字段是一个陈旧的指针。 当你在调用析构函数时
FSQL.Free;
你会得到一个无效的指针操作。
改变你的二传手:
procedure TPayorDM._psetSQL(const Value: TStringList);
begin
FSQL.Assign(Value);
end;
链接地址: http://www.djcxy.com/p/35017.html
上一篇: Delphi XE3 Invalid Pointer when trying to free FSQL (TStringList)