![]() |
Unerklärbare Zugriffsverletzung
Hallo,
leider ist der Titel nicht ganz passend gewählt und mein Problem etwas undurchsichtig, aber ich versuche es mal bestmöglich darzustellen: Ich habe einen Service, in welchem man Jobs anlegen kann, die verschiedene Events abwarten und bei deren eintreten eine Mail verschicken. Das geht auch mit mehreren Jobs. Sprich: Wenn Event A eintritt, dann schicke eine Mail an Person, welche im Auftrag (Job) A angegeben ist; Wenn Event B eintritt, dann schicke eine Mail an Person, welche im Auftrag B angegeben ist. Zu bestimmten Zeiten, welche ebenfalls im Auftrag festgelegt sind, wird dann ein Report bzw. eine Mail erstellt, welche die Events und Informationen enthält. Jetzt habe ich 2 Jobs angelegt, welche zur selben Zeit ihren Report abschicken sollen. In einer Schleife funktioniert das so:
Delphi-Quellcode:
Die Funktion Log habe ich selbst geschrieben, sie kapselt einfach nur den Zugriff auf eine Textdatei. In der Funktion SendMail wird einfach nur eine TStringList mit Text und Infos gefüllt und später an den MailBody übergeben. Anschließend wird eine DLL von mir aufgerufen, welche die Mail verschickt. Schlussendlich werden am Ende der SendMail-Prozedur noch die bereits geschickten Events aus der Liste der ausstehenden Events entfernt.
if EventCount > 0 then // wenn mehr als 0 Events existieren
begin Log(False, 'EventCount for "' + Jobs[i].AName+ '": ' + IntToStr(EventCount)); // Im Log festhalten, wieviele Events für den Job eingetreten sind Log(False, 'All Events: ' + IntToStr(Length(Events))); // Die Anzahl aller Events im Log festhalten SendMail(i); // Mail schicken; i = Schleifen-Variable end; Die Ausgabe in meinem Log sieht übrigens so aus: EventCount for "Auftrag 1": 3 All Events: 11 [18.03.2014 14:50:05]: INFORMATION: Message to "empfänger_1@googlemail.com" was successfully transmitted EventCount for "Auftrag 2": 8 All Events: 8 [18.03.2014 14:50:09]: INFORMATION: Message to "empfänger_2@isforb.com" was successfully transmitted Es funktioniert alles wie beschrieben: Es existieren zu Beginn 11 Events in der Liste, 3 für Job A. Nach dem verschicken der ersten Mail existeren noch 8, alle für Job B, das ist ja logisch. Bis hierhin klappt auch alles, allerdings war die Ausgabe im Log nur zu Testzwecken, die interessiert mich nicht wirklich. Ich möchte nur wissen, ob die Mail erfolgreich geschickt wurde. Also sieht die Routine jetzt wie folgt aus:
Delphi-Quellcode:
Allerdings erhalte ich jetzt eine Zugriffsverletzung. Das Log dazu sieht so aus:
if EventCount > 0 then // wenn mehr als 0 Events existieren
SendMail(i); // Mail schicken; i = Schleifen-Variable [18.03.2014 14:58:05]: INFORMATION: Message to "empfänger_1@googlemail.com" was successfully transmitted [18.03.2014 14:58:05]: CRITICAL ERROR: [EAccessViolation] "Zugriffsverletzung bei Adresse 0040479F in Modul 'RPU_SRV.exe'. Lesen von Adresse 0324DD9C" Jetzt verstehe ich aber nicht warum ich diese Zugriffsverletzung erhalte. Das Log hat ja rein garnichts mit dem Rest zu tun. In der der Prozedur wird lediglich in eine Textdatei geschrieben. Warum erhalte ich nun beim senden der zweiten Mail einen Fehler? Ich sage vllt. noch dazu, das der Service aus mehreren Threads besteht, aber das war auch das einzige was noch wichtig sein könnte. Ich hoffe ihr könnt mir helfen, natürlich könnte ich auch einfach die Zeilen mit dem Log stehen lassen, das würde aber meine Ehre kränken 8-) P.S: Sorry für den vielen Text... Vielleicht sollte ich Autor werden :lol: Gruß, Lukas |
AW: Unerklärbare Zugriffsverletzung
Leider hast du hier nur die Hälfte des eigentlich interessanten Codes gepostet. Was ist mit der SendMail Procedure? Du befindest dich ja anscheinend in einer For/While/Repeat Schleife. Dort wirst du wohl auf ein Element zugreifen, dass es nicht (mehr) gibt á la Listenindexfehler. Wenn der nicht kommt, kann der Fehler in der Sendmail Procedure auftreten. Schau doch dort noch einmal nach.
|
AW: Unerklärbare Zugriffsverletzung
Die 'Log()'- Aufrufe erzeugen einen zeitlichen Abstand zwischen den 'SendMail()'-Aufrufen.
In deinem Beispiel 4 Sekunden sind eine kleine Ewigkeit. Zitat:
Wenn z.B. die Threads parallel neue Events der Liste hinzufügen und im Hauptthread Events ausgelesen und entfernt werden, ist eine saubere Synchronisation notwendig. |
AW: Unerklärbare Zugriffsverletzung
Zitat:
Sonst erstmal nix schreib, da ja bereits Alles/Vieles gefragt wurde. |
AW: Unerklärbare Zugriffsverletzung
Erstmal danke für die Antworten :)
Also es gibt 3 Threads, den ServiceThread, welcher ja immer aktiv ist, jedoch bei mir keine relevanten Aufgaben hat. Dann gibt es noch einen Überwachungs-Thread, welcher auf Events wartet und diese bearbeitet, und den Mail-Thread. Dieser bekommt von dem Überwachungs-Thread immer die Events zugeschoben. Allerdings ist hier alles schön synchronisiert und ich hatte hier noch nie Probleme. Jobs und Events sind je 2 Arrays. Allerdings nicht ineinander verschachtelt. Sie dienen eigentlich nur zum speichern von den Aufträgen und eben den Ergenissen/Events Die 4 Sekunden enstehen nicht durch das Loggen. Ich habe die besagt Mail-DLL mal aus dem stehgreif runtergetippt. Für jeden Sendevorgang werden die INDY-Komponenten neu initialisiert und einen Verbindung aufgebaut, auch wenn es der gleiche SMTP-Server ist. Klar könnte man das optimieren, aber für meine Zwecke, bei max. 5 Mails in einer Stunde nicht mein primäres Ziel. @himitsu: Debugmodus :lol: Ja hab ich garnicht dran gedacht, aber wie geht das den bei einem Service :gruebel: Meine Vermutung war ja bis jetzt, das die Log Funktion irgendetwas verzögert, allerdings konnte ich das mit Sleep nicht ausgleichen. Wäre schön das nochmal mit dem Debugger durchzugehen. @Aviator: Jop, der Code wird von einer for-Schleife umgeben. Allerdings hat sich mir kein Sinn ergeben warum hier ein Fehler auftreten könnte. Ich zeige gleich nochmal etwas mehr Code. |
AW: Unerklärbare Zugriffsverletzung
Das wäre erstmal die vollständige Schleife von oben:
Delphi-Quellcode:
Hier wäre dann SendMail:
for i := 0 to High(Jobs) do // eben für jeden Job durchgehen
begin EventCount := 0; // Event-Zähler zurücksetzen if Jobs[i].SendWithNextWave = True then { Eine Vorher gesetzte Variable, welche angibt, ob der Job gesendet wird } for j := 0 to High(Events) do if Events[j].AName = Jobs[i].AName then { prüft sozusagen die Zugehörigkeit aller Events zu dem im Moment in Bearbeitung befindlichen Job; Nicht elegant, aber ausreichend } Inc(EventCount); if EventCount > 0 then begin { Log(False, 'EventCount for "' + Jobs[i].Mail + '": ' + IntToStr(EventCount)); Log(False, 'All Events: ' + IntToStr(Length(Events))); } SendMail(i); end; end;
Delphi-Quellcode:
So... Ich hoffe das ist etwas genauer. Ich gehe auch nochmal den Quellcode umgraben.
procedure TMailThread.SendMail(JobID: Integer);
var i: Integer; MMail: TStringList; ID: String; // EventCount = (Thread-)Global begin MMail := TStringList.Create; MMail.Add('Es wurden ' + IntToStr(EventCount) + ' Meldungen für den Auftrag "' + Jobs[JobID].AName + '" gefunden:'); MMail.Add(''); { ... } { Andere Informationen hinzufügen, die hier aber nicht relevant sind (Keine Schleifen, nur stumpfe Zuweisungen von Text } for i := 0 to High(Events) do if Events[i].AName = Jobs[JobID].AName then begin MMail.Add('---'); MMail.Add(Events[i].Info + ' | ' + Events[i].Time + ' | ' + Events[i].Status + ' | ' + Events[i].Date + ' | ' + Events[i].Note); MMail.Add('---'); MMail.Add(''); end else begin MMail.Add('---'); MMail.Add(Events[i].Info + ' | ' + Events[i].Time + ' | ' + Events[i].Status + ' | ' + Events[i].Date + ' | ' + Events[i].Note); MMail.Add('---'); MMail.Add(''); end; { Der Code hierrüber fügt die Events welche dem passenden Job angehören einfach in den MailText ein. Allerdings frage ich mich gerade selbst, was das mit dem 'else' soll. Habe den Code aus einem anderen Projekt von mir übernommen und etwas umgestellt. Hier ergibt es keinen Sinn, ist mir eben erst aufgefallen, als ich es gepostet habe :D Ich lasse es trotzdem hier mal stehen. } MMail.Add('------------------------------------------------------------'); MMail.Add(''); MMail.Add('Dieser Bericht wurde um ' + DateTimeToStr(Now) + ' erstellt.'); MailInfo.AHost := PChar(RPUService.Config.Host); MailInfo.APort := StrToInt(RPUService.Config.Port); { ... } { SMTP- und Mail-Einstellungen } ID := SMTPMail.SendMail(MailInfo); // Meine DLL: Zugriff und abschicken if ID = 'Success' then // Rückgabewert prüfen und bearbeiten begin Jobs[JobID].Sended := True; Jobs[JobID].SendWithNextWave := False; Jobs[JobID].LastTime := TimeOf(Now); Log(True, 'INFORMATION: Message to ' + Jobs[JobID].AMail + ' was successfully transmitted'; end else begin Log(True, 'ERROR [' + Jobs[JobID].AMail + ']: ' + ID); Jobs[JobID].Sended := False; Jobs[JobID].SendWithNextWave := True; end; MMail.Free; if (Length(Events) > 0) and (Jobs[JobID].Sended = True) then for i := High(Events) downto 0 do if Events[i].AName= Jobs[JobID].AName then DeleteEventArrayElement(Events, i); { In den 4 Zeilen hierrüber werden die bearbeiteten Events aus der Liste entfernt } MfG |
AW: Unerklärbare Zugriffsverletzung
Zitat:
du könntest ein zweites "Debug"-Projekt erstellen, das alle Units aus dem Service enthält und eventuell Logausgaben direkt anzeigt. Dieses Programm läuft dann nicht als Service sondern als normale Applikation die dann einfach mit dem Debugger zu verfolgen ist. Ciao, Ralf |
AW: Unerklärbare Zugriffsverletzung
Man muß nur den Debugger/IDE mit den nötigen Rechten starten und schon hat man Zugriff.
Zitat:
Meine letzte gewachsene Variante reagiert darauf wie/wo der Service gestartet wurde und verbiegt den Service dann so, daß er als "normale" Anwendung läuft.
Delphi-Quellcode:
Aber so sind die Rechte natürlich etwas Anderes und auch der "Benutzerkontext", womit da eventuell nicht alle Resourcen gleich verfügbar sind.
uses
..., Forms, SvcMgr, ...; // Forms (vor der SvcMgr), damit man Zugriff auf die Messagebehandlung und auf die normale TForm hat. procedure TMyService.ServiceCreate(Sender: TObject); var Started: Boolean; Temp: TForm; begin LogMessage('Service wird erzeugt', EVENTLOG_INFORMATION_TYPE, 0, 1); ... if IsDebuggerPresent or FindCmdLineSwitch('DEBUG', ['-', '/'], True) then begin MyService := Self; // wird sonst von Application.CreateForm gesetzt, aber durch die Messageloop kommt es dort nicht vorbei Forms.Application.MainFormOnTaskBar := False; // geht leider doch nicht ohne Form Forms.Application.CreateForm(TForm, Temp); // Form zum Beenden und für Eintrag in Taskbar Temp.Caption := 'Debug-Mode: ' + SvcMgr.Application.Title; Temp.OnCloseQuery := DebugServiceClose; Temp.Visible := True; // ab hier der Ersatz für SvcMgr.Application.Run, welches sonst sofort Beenden würde, da es kein echter Service ist if FindCmdLineSwitch('INSTALL', ['-', '/'], True) then TServiceApplicationHack(Application).RegisterServices(True, FindCmdLineSwitch('SILENT', ['-', '/'], True)) else if FindCmdLineSwitch('UNINSTALL', ['-', '/'], True) then TServiceApplicationHack(Application).RegisterServices(False, FindCmdLineSwitch('SILENT', ['-', '/'], True)) else begin Started := True; ServiceStart(Self, Started); if Started then begin ServiceExecute(nil); while not Terminated do try Forms.Application.ProcessMessages; Sleep(10); except on E: Exception do begin LogMessage('Error: ' + E.ClassName + ' = ' + E.Message, EVENTLOG_WARNING_TYPE, 0, 22); Sleep(1000); end; end; end; Forms.Application.Terminate; end; end; end; procedure TMyService.ServiceExecute(Sender: TService); begin LogMessage('Service wird ausgeführt', EVENTLOG_INFORMATION_TYPE, 0, 3); ... while Assigned(Sender) and not Terminated do//warten auf beenden try ServiceThread.ProcessRequests(False); Sleep(10); except on E: Exception do begin LogMessage('Error: ' + E.ClassName + ' = ' + E.Message, EVENTLOG_WARNING_TYPE, 0, 22); Sleep(1000); end; end; LogMessage('Service wurde beendet', EVENTLOG_INFORMATION_TYPE, 0, 5); end; procedure TMyService.DebugServiceClose(Sender: TObject; var CanClose: Boolean); begin if Assigned(MyService) and Assigned(MyService.ServiceThread) then MyService.ServiceThread.Terminate; end; Etwas was im Service läuft, könnte hier nicht laufen. Und andersrum. Zitat:
Delphi-Quellcode:
?
= True
Man kann natürlich aud die IDE und den Debugger mit den nötigen Rechten starten. z.B. als Admin Oder man lässt den Service in einem anderem Benutzerkontext laufen. Wenn man den Service im normalen Benutzerkontext laufen lässt, dann hätte er es eventuell auch einfacher auf den Desktop dieses Benutzers zuzugreifen. |
AW: Unerklärbare Zugriffsverletzung
Ich glaube ich mache ein Debug Projekt, das ist nicht so viel Code, da mach ich mir die "Mühe" :)
@himitsu: Zitat:
Was wills du mir damit sagen :gruebel: |
AW: Unerklärbare Zugriffsverletzung
Das Vergleichen mit
Delphi-Quellcode:
ist doppelgemoppel, denn
true
Delphi-Quellcode:
prüft schon auf
if ... then
Delphi-Quellcode:
und dadurch wird das zu
not false
Delphi-Quellcode:
.
if ( Bedingung = true ) <> not false then
Delphi-Quellcode:
ist definiert als
false
Delphi-Quellcode:
und
0
Delphi-Quellcode:
ist das Gegenteil (alles ausser 0). Der Einfachheit halber wurde
true
Delphi-Quellcode:
(in Delphi) als Konstante mit dem Wert
true
Delphi-Quellcode:
festgelegt. Andere Sprachen verwenden hier andere Werte (z.B.
1
Delphi-Quellcode:
), was egal ist, wenn man eben nicht mit
-1
Delphi-Quellcode:
vergleicht.
true
|
AW: Unerklärbare Zugriffsverletzung
Zitat:
Wenn es direkt beim Starten passiert, kannst du folgendes nutzen, damit der Dienst wartet bis du den Debugger verbunden hast:
Delphi-Quellcode:
Und danach direkt einen Haltepunkt setzen z.B.
while not IsDebuggerPresent do
Sleep(100); |
AW: Unerklärbare Zugriffsverletzung
@Sir_Rufo: Okay, habe mir gedacht das er darauf hinauswill. Merke ich mir für die Zukunft...
@jaenicke: Ja stimmt... Habe ich irgendwie dran vorbei gedacht... Und danke für den Tipp mit dem "IsDebuggerPresent" :thumb: Noch eine Anmerkung: Eben beim experimentieren ist mir folgendes aufgefallen (man betrachte die for-Schleife welche für das Senden verantwortlich ist):
Delphi-Quellcode:
Und hier die "andere" Version;
for i := 0 to High(Jobs) do
begin { ... } if EventCount > 0 then begin Log(False, 'All Events: ' + IntToStr(Length(Events))); // Geht! SendMail(i); end; end;
Delphi-Quellcode:
Ich debug mich da jetzt durch und dann bin ich mal gespannt, was da genau passiert :twisted: Denn der Code von oben hat mich nur nochmehr verwirrt :(
for i := 0 to High(Jobs) do
begin { ... } if EventCount > 0 then begin Log(False, IntToStr(Length(Events))); // GEHT NICHT!!! SendMail(i); end; end; |
AW: Unerklärbare Zugriffsverletzung
Achso, hier nochmal meine Profi Log-Funktion :)
Delphi-Quellcode:
Wenn man in der SendMail-Prozedur eine Zeile hinzufügt funktioniert alles:
procedure Log(ShowDateTime: Boolean; s: String);
var LList: TStringList; i: Integer; begin FLogCritSect.Enter; try LList := TStringList.Create; if not IsFileInUse(AppDataPath + 'Jobs.jlf') then begin try if FileExists(AppDataPath + 'Log.txt') then LList.LoadFromFile(AppDataPath + 'Log.txt'); for i := 0 to Puffer.Count - 1 do LList.Add(Puffer[i]); if ShowDateTime then LList.Add('[' + DateTimeToStr(Now) + ']: ' + s) else LList.Add(s); LList.SaveToFile(AppDataPath + 'Log.txt'); finally LList.Free; Puffer.Text := EmptyStr; end; end else if ShowDateTime then Puffer.Add('[' + DateTimeToStr(Now) + ']: ' + s) else Puffer.Add(s); finally FLogCritSect.Leave; end; end;
Delphi-Quellcode:
Allerdings soll das nicht die Lösung sein... Ich melde mich nochmal! :)
{ ... }
Log(False, ''); // Löst alle Probleme for i := 0 to High(Events) do if Events[i].Mail = Jobs[JobID].Mail then begin { ... } end; { ... } Gruß |
AW: Unerklärbare Zugriffsverletzung
Zitat:
Delphi-Quellcode:
PS:
if not IsFileInUse(AppDataPath + 'Jobs.jlf') then
begin LList := TStringList.Create; try ...
Delphi-Quellcode:
Aber ich würde da eher zu AssignFile+Append+WriteLn raten, oder zumindestens einem FileStream, welcher die Daten direkt anhängt, da muß nicht ständig die ganze Logdatei jedes Mal neu eingelesen werden, sondern man hängt nur die neuen Zeilen an.
//for i := 0 to Puffer.Count - 1 do
// LList.Add(Puffer[i]); LList.AddStrings(Puffer); //Puffer.Text := EmptyStr; Puffer.Clear; Du willst lieber nicht wissen, was seit D2009 beim Laden oder Speichern einer TStringList passiert. (z.B. bis über das 5-Fache des Speicherverbrauchs der Dateigröße) |
AW: Unerklärbare Zugriffsverletzung
Zitat:
Der Mail-Thread liest die Elemente aus Events und löscht diese sogar. ("schön sychronisiert" sollte bedeuten, er tut das ebenfalls innerhalb der selben Criticalsection.) Ich habe keine einzige Zeile in dieser Hinsicht gesehen. Hoffentlich bedeuted das, der gesamte Code läuft innerhalb der Criticalsection... |
AW: Unerklärbare Zugriffsverletzung
@himitsu: Oh :lol: Danke für den Hinweiß. Das ist ein altes Projekt von mir, was ich etwas umgestellt habe. Hat immer gut funktioniert und mir ist der Fehler nie aufgefallen :roll:
Ja, man könnte es auch mit AssignFile+Append+WriteLn... War einfach zufaul das mal in Angriff zu nehmen :mrgreen: @Blup: Habe nur das wichtigste gezeigt. Es läuft alles in CriticalSections :thumb: Und ich habe erste Ergebnisse beim Debugging (hatte erst heute Mittag Zeit - jaja, das Schüler sein :roll:):
Delphi-Quellcode:
Ich könnte mir vorstellen, warum der Fehler auftritt. Das letzte Event (i=5) hat für das Feld "Status" nur Matsch im Wert. Aber ich weiß noch nicht, wo der herkommt :glaskugel: Aufjedenfall eine sehr lange Zeichenkette. Vllt. haut es deshalb nicht hin. Aber warum sollte die eine Log-Zeile das Problem lösen? :glaskugel:
procedure TMailThread.SendMail(JobID: Integer);
var i: Integer; MMail: TStringList; ID: String; begin { ... } Log(False, ''); { Wenn diese Zeile "aktive" ist, läuft alles reibungslos. Ist die Zeile nicht gesetzt, kommt in der unten makierten Zeile ein Fehler beim 2. Durchlauf (6. Durchlauf der for-Schleife, 2. Durchlauf der SendMail-Prozedur ;) ) } for i := 0 to High(Events) do if Events[i].Mail = Jobs[JobID].Mail then begin MMail.Add('---'); MMail.Add(Events[i].Course + ' | ' + Events[i].Span + ' | ' + Events[i].Status + ' | ' + Events[i].Date + ' | ' + Events[i].Note); // Fehler hier! MMail.Add('---'); MMail.Add(''); end; { ... } end; |
AW: Unerklärbare Zugriffsverletzung
Okay, also das Problem ist ziemlich merkwürdig.
Das ist der Anfang der SendMail-Prozedur:
Delphi-Quellcode:
Ich kann mir nicht erklären warum, allerdings wird beim Aufrufen der makierten Zeilen der Text "zermatscht". Beim Aufruf der ersten markierten Zeile wird im Event-Array der letze/höchste Eintrag, in meinem Fall Events[5], im Elemten "Status" verändert. Dort steht z.B. 'Entfall' *. Nach dem aufrufen der ersten markierten Zeile steht dort soetwas wie '#0#0#0#0#0#0#0#0#0#0#0#3#465###0#0#0#0#0#5###5### #y###9#0#0#' mit ~300+ Zeichen. Beim Aufruf der zweiten markiertn Zeile wird in einem anderen Eintrag (Events[2]) ein Element mit dem Namen "Course" im Wert geändert. Statt 'Sport2' steht dort jetzt '---'. Wo das '---' herkommt ist ja offensichtlich, aber warum verstehe ich nicht... Das ergibt einfach keinen Sinn...
procedure TMailThread.SendMail(JobID: Integer);
var i: Integer; MMail: TStringList; ID: String; begin MMail := TStringList.Create; MMail.Add('Es wurden ' + IntToStr(EventCount) + ' Meldungen für den Auftrag "' + Jobs[JobID].Mail + '" gefunden:'); // Hier! 1. MMail.Add(''); MMail.Add('------------------------------------------------------------'); MMail.Add('Kurs | Zeitraum (Schulstd.) | Art | Tag, Datum | Bemerkung'); MMail.Add('------------------------------------------------------------'); MMail.Add(''); // Log(False, ''); // Test! for i := 0 to High(Events) do if Events[i].Mail = Jobs[JobID].Mail then begin MMail.Add('---'); // Hier! 2. MMail.Add(Events[i].Course + ' | ' + Events[i].Span + ' | ' + Events[i].Status + ' | ' + Events[i].Date + ' | ' + Events[i].Note); MMail.Add('---'); MMail.Add(''); end; Wenn ich die Log Zeile übrigens einbinde, werden die besagten Einträge (Events[6] + Events[2]) erst geleert, und beim ersten Durchlauf der darauffolgenden Schleife wieder gefüllt, allerdings mit völligem Käse. Statt dem Zeichensalat steht dann dort 'C:\ProgramData\', das ist der Pfad, unter welchem auch das Log gespeichert wird (es folgt noch ein Unterordner). Also irgendetwas wird hier ganz gewaltig durcheinandergeworfen. Ich habe leider garkeine Vermutung, was das Problem sein könnte :cry: Gruß *Wie man unschwer erkennen kann, arbeite ich an einem Programm, was den Vertretungsplan unserer Schule herrunterläd und per Mail verschickt. Man kann seine Kurse und seine Mail in eine Liste eintragen, das Programm Filtert dann den Vertretungsplan und schickt einen individuell angepassten Report. Das hat bisher immer Fehlerfrei geklappt. Der Fehler ist mir jetzt erst untergekommen, als ich versucht habe, mehrere Jobs anzulegen (Also für mehrere Schüler; In meinem Fall warne es 2 Jobs/Schüler, da hat es schon gekracht). |
AW: Unerklärbare Zugriffsverletzung
Okay, ich habe jetzt den ganzen Tag nichts anderes gemacht... Ich habe alles auf den Kopf gestellt, den EventThread rausgenommen und, und, und... Aber ich finde den Fehler nicht! :wall: :evil: :cry:
Ich weiß nur, dass - aus welchen Gründen auch immer - das EventArray urplötzlich verändert wird. Ich habe aus der Anwendung sogar eine Single-Thread Anwendung gemacht und trotzdem tritt dieser komsiche Fehler auf. Vllt. hat ja jemand einen Geistesblitz, aber im Moment sieht es übel aus :/ |
AW: Unerklärbare Zugriffsverletzung
Eine TStringList selber ist eigentlich sehr robust und fehlerunanfällig.
Wenn da was kapput geht, dann liegt das fast immer an jemand Anderem. - nicht threadsichere Zugriffe (würde ich hier ausschließen, da ja nur in dem einem Thread drauf zugegriffen wird) - Buffer-Overflows, welche die Daten der Stringliste überschreiben und dabei zerstören Oder die StringListe ist eigentlich ganz, aber der Debugger zeigt einfach nur Mist an, weil er z.B. diese Klasse/Variablen nicht richtig auflöst. Aber dieses läßt sich prüfen, indem man den Inhalt der Stringliste z.B. loggt, oder in öfters mal in eine Debug-Datei ausgiebt, welche man sich während der Haltepunkte ansieht, oder mehrere fortlaufende Dateien, wo man sich nachher ansieht, ob und ab wann es kaputt ging. |
AW: Unerklärbare Zugriffsverletzung
Du könntest einmal FastMM einbinden, vielleicht findet das ja etwas, wenn du den FullDebugMode in der mitgelieferten Include-Datei aktivierst.
Wie wäre es denn, wenn du das Programm einfach einmal komplett anhängst, bzw. ein Projekt, das den Teil mit dem Fehler enthält? Wenn das jemand selbst ausprobieren und debuggen kann, wird der Fehler sicher schnell gefunden. ;-) |
AW: Unerklärbare Zugriffsverletzung
Jo mache ich heute Abend :) Ich bin noch etwas am experimentieren und umbasteln.
Habe es ja schonmal erwähnt, das ich ein altes Projekt als Basis genommen habe, das ist natürlich nicht ganz optimal. |
AW: Unerklärbare Zugriffsverletzung
Okay, ich habe das Problem gelöst ( :thumb: ), allerdings kann ich die Lösung nur vermuten ( :lol: ). Also:
So sahen meine beiden Arrays am Anfang aus:
Delphi-Quellcode:
Nachdem ich den Quellcode durchgepflügt, eine Single-Thread Anwendung aus dem Programm gemacht habe und der Fehler immer noch auftrat, war ich erstmal ein bisschen verzweifelt. Allerdings wollte ich noch eine Kleinigkeit optimieren.
TJobData = record
AMail, AStep, ACourses, ATimes: String; ASended, ADecontrol: Boolean; ALastTime: TTime; end; TEventData = record AMail, ACourse, ASpan, AStatus, ADate, ANote, AHash: String; end; TJobArray = array of TJobData; TEventArray = array of TEventData; Aus dem oben gezeigtem Teil wurde folgendes:
Delphi-Quellcode:
Die Events werden jetzt in einem untergeordneten Array von Jobs gespeichert. Eigentlich nur eine kleine Verschachtelung.
TEventData = record
ACourse, ASpan, AStatus, ADate, ANote, AHash: String; end; TEventArray = array of TEventData; TJobData = record AMail, AStep, ACourses, ATimes: String; ASended, ADecontrol: Boolean; ALastTime: TTime; Events: TEventArray; end; TJobArray = array of TJobData; Natürlich hatte die IDE nach dieser Änderung erstmal schön zum Rotstift gegriffen und Zeilen wie
Delphi-Quellcode:
markiert. Ist ja logisch, das Objekt war ja so nicht mehr deklariert.
Events[i].AMail := 'example@gmail.com'
Also habe ich mich durch die Fehlerliste am Rand der IDE geklickt und direkt beim Doppelklick auf den ersten Eintrag hat mich die IDE an folgende Zeile in meinem Code gebracht:
Delphi-Quellcode:
Sieht da jemand irgendwo das Objekt/Array "Events"? Also ich auch nicht :shock: Aber trotzdem war fast alles rot unterstrichen.
function AppDataPath: string;
const SHGFP_TYPE_CURRENT = 0; var path: array [0 .. MaxChar] of char; begin SHGetFolderPath(0, CSIDL_COMMON_APPDATA, 0, SHGFP_TYPE_CURRENT, @path[0]); Result := StrPas(path) + '\VPUpdater\'; end; Nach einem Klick auf STRG + D war auf einmal alles wieder okay (obwohl ich davor auch des öfteren mal formatiert habe). Und der Fehler war auf einmal beseitigt :twisted: Ich würde jetzt einfach mal behaupten, dass ich irgendwann mal die IDE zerschossen habe und der Compiler dann Schrott kompiliert hat. Das würde auch erklären warum in meinem Array auf einmal ein Pfad stand ('C:\Program Files\). Dieser wird nähmlich bei der obenstehenden Funktion ermittelt. Vllt. hat ja jemand eine bessere Erklärung für dieses Phänomen... Naja, hauptsache es geht jetzt. Leider war das dann ja ein Quiz ohne Antwort :roll: Immerhin hat himitsu einen Fehler in meiner Log-Funktion entdeckt und ihr habt mich unterstützt :thumb: Gruß, Lukas |
AW: Unerklärbare Zugriffsverletzung
Die richtige Konstante ist hier 'Max_Path' und nicht 'MaxChar'.
Der Buffer 'path' wird nicht gelöscht und das Ergebnis von 'SHGetFolderPath' nicht ausgewertet. In dieser Kombination kann StrPas einen riesigen String voller Speichermüll zurückgeben oder sogar eine Zugriffsverletzung auslösen. Man könnte das z.B. so lösen:
Delphi-Quellcode:
function AppDataPath: AnsiString;
const SHGFP_TYPE_CURRENT = 0; begin SetLength(Result, Max_Path); FillChar(Result[1], Max_Path, 0); SHGetFolderPath(0, CSIDL_COMMON_APPDATA, 0, SHGFP_TYPE_CURRENT, PAnsiChar(Result)); SetLength(Result, StrLen(PAnsiChar(Result))); Result := Result + '\VPUpdater\'; end; |
AW: Unerklärbare Zugriffsverletzung
Oh... wusste ich nicht. Hat bisher immer funktioniert... Vielleicht ist es ja diemal schiefgegangen :lol:
Danke für den Tipp :thumb: |
Alle Zeitangaben in WEZ +1. Es ist jetzt 08:21 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz