Entwickler-Ecke
Sonstiges (Delphi) - EAccessViolation keine Ahnung warum
Bronstein - Mi 21.11.07 18:50
Titel: EAccessViolation keine Ahnung warum
Hallo,
ich habe ein Problem.
Ich rufe die Funktion siehe unten in einem Thread mehrmals auf und bekomme einen Fehler EAccessViolation.
Wenn ich das die funktion durchgehe (debug), bekomme ich den Fehler erst wenn ich die Funktion verlasse, woran kann das liegen bzw. wo liegt der Fehler?
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104:
| function test(SetupName, LineName: Pchar): Pchar; stdcall; var tmpStr, Spur, Bauteil: ShortString; Dateiname: STring; ini: TiniFile; SL, Datei: TStringList; i, k, z, y, f: Integer; XML, XMLCencorp, tmpXML: String; checkStart: Boolean; xmlDoc: IXmlDocument; SR: TSearchRec; tmpPchar: Pchar; begin result := 'Error'; try FehlerProtokoll(LineName); tmpStr := ExtractFilePath(ParamStr(0)) + 'Cencorp_MobiCheck.ini'; if FileExists(tmpStr) then begin ini:=TIniFile.Create(tmpStr); tmpStr := ''; SL := TStringList.Create; SL.Delimiter := ';'; tmpStr := ''; tmpStr := ini.ReadString('Einstellungen', LineName, tmpStr); SL.DelimitedText := tmpStr;
tmpXML := ''; XML := '<Setup Name="' + SetupName + '" LineName="' + LineName + '">'; for i := 0 to SL.Count-2 do begin tmpXML := ''; XML := XML + '<Module Name="' + SL[i] + '">'; XML := XML + '<FeederTable Name = "1">'; tmpStr := ''; tmpStr := ini.ReadString('Einstellungen', SL[i] + '_Feeder', ''); if tmpStr = '' then begin Application.ProcessMessages; Dateiname := ''; tmpStr := ini.ReadString('Einstellungen', SL[i] + '_works', '');
if FindFirst(tmpStr + '\*' + SetupName + '*.wls', faAnyFile, SR) = 0 then Dateiname := Sr.Name; if FindFirst(tmpStr + '\*' + copy(SetupName, 1, 2) + '_' + copy(SetupName, 3, 3) + '_' + Copy(SetupName, 6, 3) + '*.wls', faAnyFile, SR) = 0 then Dateiname := Sr.Name; Application.ProcessMessages; if Dateiname <> '' then begin Datei := TStringList.Create; Datei.LoadFromFile(tmpStr + '\' + Dateiname); for k:=0 to Datei.Count-1 do begin if pos('#', Datei[k]) > 0 then begin Spur := copy(Datei[k], length(Datei[k])-1, 2); Bauteil := ''; for z:=0 to Length(Datei[k])-1 do begin if Datei[k][z] = '#' then break; if IsValidInteger(Datei[k][z]) then Bauteil := Bauteil + Datei[k][z]; end; if not IstInString(tmpXML, Bauteil) then begin tmpXML := tmpXML + '<ScanTrack Nr="' + Spur + '">'; tmpXML := tmpXML + '<Component>' + Bauteil + '</Component>'; tmpXML := tmpXML + '<Feeder>'; tmpXML := tmpXML + '<FeederTrack>'+Spur+'</FeederTrack>'; tmpXML := tmpXML + '<Pocket>1</Pocket>'; tmpXML := tmpXML + '</Feeder>'; tmpXML := tmpXML + '</ScanTrack>'; end; end; end; Application.ProcessMessages; end else FehlerProtokoll('Keine Programm bei der Maschine:' + SL[i] + ' beim Programm ' + SetupName + ' vorhanden. Pfad: ' + tmpStr); end tmpXML := tmpXML + '<ScanTrack Nr="04"><Component>905552</Component>'; tmpXML := tmpXML + '<Feeder><FeederTrack>04</FeederTrack><Pocket>1</Pocket></Feeder></ScanTrack>';
end; XML := XML + tmpXML; XML := XML + '</FeederTable>'; XML := XML + '</Module>'; end; XML := XML + '</Setup>'; Result := PChar(string(XML));
end; except FehlerProtokoll('GetSetup: unbekannter Fehler'); end; end; |
Moderiert von
jasocul: Topic aus VCL (Visual Component Library) verschoben am Do 22.11.2007 um 07:46
delfiphan - Mi 21.11.07 20:10
Du kannst keinen PChar zurückliefern, der aus einem String gecastet wurde. Der String wird beim Verlassen freigegeben, da out of scope, und somit wird der Pointer ungültig.
Mach's so wie die WinAPI: Der User soll den Speicher allozieren, nicht die Funktion. Achtung Bufferoverflow-Gefahr. Anders geht's fast nicht, da der Delphi-Compiler nicht wissen kann, wann der PChar freigegeben werden kann.
Bronstein - Mi 21.11.07 22:24
Wenn ich aber die Zeilen 32 - 95 auskommentiere funktioniert es!
Wie mach ich das?
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7:
| function test(SetupName, LineName: Pchar): Pchar; stdcall; var pText: Pchar; [...] pText := StrAlloc(Length(XML) + 1); StrPLCopy(pText, XML, Length(XML)); result := pText; |
Wenn ich was mit StrAlloc mache, muss ich das doch auch wieder freigeben (StrDispose) wo mach ich das dann?
delfiphan - Do 22.11.07 00:11
Es funktioniert, weil der Memorymanager den Bereich noch nicht freigegeben hat sondern noch für evtl. weitere Daten warmhält! Grosse Blöcke werden entsprechend sofort freigegeben.
Der Compiler/Memorymanager hat keine Chance rauszufinden, wie lange der PChar gebraucht wird, da er weder referenzgezählt noch sonst wie gegen Memory-Leaks geschützt ist. Den musst du selbst freigeben, sobald du ihn nicht mehr brauchst.
Die Lösung zum Problem habe ich oben beschrieben: User alloziert Memory selbst. Alternativ kannst du die Daten auch über einen Callback zurückstreamen.
Bronstein - Do 22.11.07 08:45
Hallo,
stimmt das wie ich es oben geschrieben habe?
Ich komm einfach nichtmehr weiter!
gispos - Do 22.11.07 19:09
Hallo bronstein,
also eine konkrete Hilfe hab ich nicht, deine Function ist recht abenteuerlich und
Fehler können sich hier an vielen Stellen einschleichen.
z.B. Datei öffnen. Sind denn auch alle Dateien vorhanden?
Versuche den Startpunkt des Debuger in der Schleife ab Zeile 32 zu setzen, dann sollte
es sich doch debugen lassen. Musst natürlich die DLL mit Hostanwendung debugen!
Zweiter Vorschlag, baue ein Try except in die Schleife (33 bis 94) ein, und verschiebe das Except dann immer weiter nach oben bis das Error ausgelößt wird.
Oder mache einfach ein "exit" ab Zeile 33 und verschiebe das "exit" immer weiter nach unten.
Die Stringlisten nicht freigeben, ist das Absicht?
Die ini wird auch nicht frei gegeben!
Wird die Function auch durch "stdcall" in der Anwendung aufgerufen?
In Zeile 87 oder 91 ist ein "end" zuviel!
FindFirst muss im Erfolgsfall durch SysUtils.FindClose frei gegeben werden!
Nachtrag:
Habe z.B. diesen Fehler gefunden:
Delphi-Quelltext
1: 2: 3: 4: 5:
| for z:= 0 to Length(Datei[k])-1 do ??
Richtig dann so: for z:= 1 to Length(Datei[k]) do |
Frage? Was macht dein IsValidInteger(Datei[k][z]) wenn Datei[k][z] = '' ??
Gruß gispos
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2026 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!