Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Stackoverflow finden - wenn es denn einer ist (https://www.delphipraxis.net/187827-stackoverflow-finden-wenn-es-denn-einer-ist.html)

Medium 7. Jan 2016 09:57

Stackoverflow finden - wenn es denn einer ist
 
Hallo DP,

ich bin auf der Suche nach dem Grund für ein ekelhaft schlüpfriges Problem mit einem Programm von mir. Es ist (bzw. war) in Delphi 7 geschrieben und lief über Jahre auf WinXP ohne Probleme im 24/7 Einsatz. Der Kunde hat jetzt neue PCs und dort Win7 64 drauf.
Mein Programm hat scheinbar auch dort funktioniert, ist aber nach recht verlässlich 15-20 Minuten abgestürzt. Windows meldete fast immer nur "ein Problem" und bat mir an es abzuschießen. Ein Mal aber kam ein Infofensterchen, wo der Kunde abgelesen hat dass der Absturz in der "usp10.dll" aus dem SysWOW64 Ordner gemeldet wurde.
Da ich das Programm schon länger gerne zumindest in einer wenig neuere IDE haben wollte, habe ich mir die Zeit genommen es auf D2007 zu portieren. (Bei noch neuer haben wir Probleme mit 3rd-Party Komponenten.) Das Kompilat mit D2007 funktionierte ebenfalls erst problemlos, aber nach 15-20 Minuten wieder Absturz. Dieses Mal habe ich zumindest ein Infofenster gehabt, und laut dem soll es nun in der ntdll.dll passiert sein, mit Anwendungsfehlercode 0xc000005.

Der kann leider ein riesen Haufen von Ursachen haben, da es prinzipiell erstmal nur eine Zugriffsverletzung aussagt... Defekter Speicher wird gerne genannt, jedoch passiert dies auf 3 Panel-PCs in exakt gleicher Weise, so dass ich hieran zweifle. Zumal andere Programme klaglos arbeiten. Andere Stellen im Netz sprechen von Stackoverflows, und dass Windows Programme die solche regelmäßig produzieren in eine Art fehlertoleranten Modus gesetzt werden, bei zu vielen Vorkommnissen pro Stunde es aber dann doch abschießt. (Nie gehört zuvor.) Und was mir auffiel: Es sind oftmals Spiele die o.g. Code produzieren, aber nicht in der ntdll.dll sondern meist in der eigenen EXE. Mein Programm ist jedoch eine ganz normale VCL Anwendung, sogar mit nur einem einzigen Fenster.

Ich habe dann mal alle Methoden in meinem Programm in try..except Blöcke gepackt, in der Hoffnung dass ich dann einen besser lokalisierbaren Fehler bekomme. Zudem habe ich Stack-Frames, Bereichs- und Überlaufprüfung aktiviert. Keine der Maßnahmen schlugen an, und nach 15-20min ist mein Programm wieder mit dem gleichen Fehler abgeschmiert. Kann die Ursache dann eigentlich überhaupt noch in meinem Code liegen? Wo kann ich anfangen nach der Ursache zu suchen? (Eurekalog o.ä. scheitert im Moment erstmal daran, dass der Kunde recht weit weg ist und ich erst in 1-2 Wochen dazu kommen werde dort hin zu fahren um weitere "live-tests" zu machen. Ich würde aber gerne im Vorfeld schon mal etwas tun.)

Wo kann man da jetzt noch ansetzen? (Leider kann ich auf den PCs beim Kunden kein Delphi installieren um durchzusteppen oder auf einen debugbaren Break zu hoffen.)

haentschman 7. Jan 2016 10:01

AW: Stackoverflow finden - wenn es denn einer ist
 
Moin...:P
Zitat:

Leider kann ich auf den PCs beim Kunden kein Delphi installieren um durchzusteppen oder auf einen debugbaren Break zu hoffen.
Da der Fehler "verläßlich" kommt, könntest du mit Remote Debugging was anfangen? Das erfordert keine Delphi Installation.

zagota 7. Jan 2016 10:29

AW: Stackoverflow finden - wenn es denn einer ist
 
- Schon mal mit MadExcept laufen lassen?
- Ab Win7 gibt es für Anwendungen ein Kompatiblitätsmodus, den für dein Programm schon aktiviert?

cu

Bjoerk 7. Jan 2016 10:32

AW: Stackoverflow finden - wenn es denn einer ist
 
Bei StackOverflow denke ich im allg. zuerst an große lokale stat. Arrays oder an Rekursionen.

Lemmy 7. Jan 2016 10:35

AW: Stackoverflow finden - wenn es denn einer ist
 
Zitat:

Zitat von Medium (Beitrag 1326242)
(Eurekalog o.ä. scheitert im Moment erstmal daran, dass der Kunde recht weit weg ist und ich erst in 1-2 Wochen dazu kommen werde dort hin zu fahren um weitere "live-tests" zu machen. Ich würde aber gerne im Vorfeld schon mal etwas tun.)


Eurekalog, MadExcept und co. sind genau für den Fall gedacht, dass man nicht selbst an dem Rechner sitzen kann....

Der schöne Günther 7. Jan 2016 10:46

AW: Stackoverflow finden - wenn es denn einer ist
 
Wahrscheinlich liege ich falsch, aber maxExcept und alles helfen einem doch auch nicht weiter wenn der globale Exception-Handler direkt die gesamte Anwendung killt, oder?

Beispiel: Im
Delphi-Quellcode:
OnTerminate
-Handler eines Threads tritt eine Exception auf:

Delphi-Quellcode:
procedure TForm3.FormCreate(Sender: TObject);
var
   thread: TThread;
begin
   thread := TThread.CreateAnonymousThread(
      procedure()
      begin
         //
      end
   );
   thread.OnTerminate := handleThreadTerminate;
   thread.Start();
end;

procedure TForm3.handleThreadTerminate(Sender: TObject);
begin
   raise EProgrammerNotFound.Create(EmptyStr);
end;
Können Lösungen wie madExcept so etwas noch loggen?

jobo 7. Jan 2016 11:04

AW: Stackoverflow finden - wenn es denn einer ist
 
Was macht denn Dein Programm?
Wenn es iterativ Speicher konsummiert, kann man dem ja nachgehen und aus den gleichen Sourcen ein Testprogramm machen, das nichts anderes tut, natürlich mit Protokollierung.

"neue Rechner" müssen auch nicht unbedingt ok sein, nur weil andere Software läuft. Der Kunde könnte mit eine Linux Live CD booten und einen Memtest machen.

zagota 7. Jan 2016 11:32

AW: Stackoverflow finden - wenn es denn einer ist
 
Findet sich in der Windows Ereignisanzeige ein Hinweis?

cu

Medium 7. Jan 2016 11:41

AW: Stackoverflow finden - wenn es denn einer ist
 
@Lemmy: Das ist wohl richtig, aber leider muss ich dort trotzdem hin um eine mit diesen Tools kompilierte Version zu installieren. (Leider kein Fernzugriff, daher ist auch Remote-Debugging so eine Sache.)

@Günther: Genau das habe ich mich auch gefragt. Wenn sämtliche try..excepts unbeeindruckt bleiben (ich habe wirklich stumpf um ALLE Methoden von begin bis end ge-try-ed), habe ich da auch Zweifel.

@jobo: Gleich bei 3 PCs (von Siemens, die ihre PCs in der Regel vorm Ausliefern diversen Stresstests unterziehen)? Klar, nichts ist unmöglich, aber das wäre schon irre. Der Speicherverbrauch bleibt relativ konstant. Das Programm lief ja sogar schon 2 Jahre (identisches Kompilat auch probiert) auf den alten PCs dort ohne Mucken.

@zagota: Ja, dort wird der o.g. Fehlercode mit Bezug auf mein Programm und die ntdll.dll protokolliert. Leider sonst keine weiteren hilfreichen Infos, und ich kann leider keinen genaueren Dump produzieren ohne vor Ort zu sein. Im selben Eintrag war auch noch ein Verweis auf "0xffffbaad" (Unter "P4" oder so), welches mir bekannt vorkam. Leider produzierte Google bei einer kombinierten Suche nach dem o.g. Code und diesem keine erkennbar relevanten Ergebnisse, und die Ursachen blieben in den meisten Foren im Dunkeln. Oftmals wurde das betroffene Programm neu installiert oder geupdated womit der Fehler verschwand, aber eine konkrete Ursache fand ich nicht. Leider habe ich diese Option nicht =)

Den Kompatibilitätsmodus habe ich noch nicht versucht. Leider krankt aber auch das daran, dass ich das erst machen kann wenn ich wieder Zeit habe da hin zu fahren. (Leider kein kundiges Personal vor Ort, alles Anlagenfahrer die schon mit der bloßen Existenz eines PCs an ihrem Arbeitsplatz überfordert sind.) Zumal es wie gesagt auf mindestens einem anderen Win7 64 PC (beim selben Kunden aber in einem anderen Werk) funktioniert.

Arrays kommen nur sehr vereinzelt vor, und sie sind alle statisch. Das war auch meine erste Idee, vergessen zu sagen. Sorry! Das größte ist 4096 Bytes lang, und es gibt keine Methode die mehrere Arrays nutzt. Ansonsten werden sowohl in Parametern als auch lokalen Variablen ausschließlich elementare Datentypen oder Objekte verwendet. Mit der Ausnahme von einer Hand voll Strings, die ich aber auch mit einer Längenprüfung versehen habe, und die ja ohnehin eigentlich auf dem Heap landen sollten. Es gibt nichtmals von mir erstellte Threads, alles nur im Main-Thread.

Es gibt eine Operation die per Timer zyklisch läuft. Es wird mit einer SPS via Sockets kommuniziert. Dieses Modul setzen wir allerdings in praktisch identischer Form in zig Programmen bei diversen Kunden auf allen möglichen Windows-Versionen seit 10+ Jahren ein, und hatten dieses Problem noch nicht.
Es werden in diesem Fall sogar vergleichsweise mickrige Datenpaketchen ausgetauscht, und die Buffer werden ebenfalls bzgl. ihrer Länge überprüft. Wenn es ein "normaler" Stack-Overflow wäre, bin ich es auch eigentlich gewohnt eine saubere Meldung der RTL zu bekommen, kein "wortloses Wegschießen".

himitsu 7. Jan 2016 11:51

AW: Stackoverflow finden - wenn es denn einer ist
 
Zitat:

Delphi-Quellcode:
procedure TForm3.FormCreate(Sender: TObject);
var
   thread: TThread;
begin
   thread := TThread.CreateAnonymousThread(
      procedure()
      begin
         //
      end
   );
   thread.OnTerminate := handleThreadTerminate;
   thread.Start();
end;

procedure TForm3.handleThreadTerminate(Sender: TObject);
begin
   raise EProgrammerNotFound.Create(EmptyStr);
end;

Das ist aber ein vollkommen korrektes Verhalten, wenn tritt in einem Thread eine Exception auf und rauscht bis zum Windows durch, dann beendet Windows nunmal den kompletten Prozess.
Es ist also ganz normales Verhalten, da TThread nur das Execute per Try-Except absichert und in OnTerminate diese Exception bereit stellt.
Wer sollte denn Die Exception von OnTerminate bekommen, wenn danach nichts mehr kommt? Also gibt es keinen Grund diese Exception abzufangen.

Leider ist die RTL bissl blöd, dass sie diese Exception einfach verschluckt, wenn keiner in OnTerminate darauf reagiert (was fast nie gemacht wird), womit also eigentlich TThread diese Exceptions total falsch behandelt.

Perlsau 7. Jan 2016 12:08

AW: Stackoverflow finden - wenn es denn einer ist
 
Zitat:

Zitat von Medium (Beitrag 1326264)
Zumal es wie gesagt auf mindestens einem anderen Win7 64 PC (beim selben Kunden aber in einem anderen Werk) funktioniert.

Das ist doch wohl ein eindeutiger und unmißverständlicher Hinweis darauf, daß es an diesen drei Siemens-PCs liegen muß. Ich würde deinem Kunden daher einmal folgendes vorschlagen:
  1. Ist der PC im anderen Werk, auf dem es funktioniert, ebenfalls von Siemens?
  2. Besorgen Sie sich einen weiteren PC mit derselben bzw. gleichwertigen Ausstattung, jedoch nicht von Siemens.
  3. Installieren Sie dort dasselbe Betriebssystem.
  4. Installieren Sie dann meine Anwendung und lassen Sie sie laufen.
  5. Wie lange läuft die Anwendung auf diesem vierten PC ohne Probleme?
Nach diesem Test rätst du dann deinem Kunden, die PCs an den Lieferanten zurückzugeben mit dem Hinweis, daß damit irgend etwas nicht in Ordnung sei.

jobo 7. Jan 2016 12:15

AW: Stackoverflow finden - wenn es denn einer ist
 
Zitat:

Zitat von Medium (Beitrag 1326264)
@jobo: Gleich bei 3 PCs (von Siemens, die ihre PCs in der Regel vorm Ausliefern diversen Stresstests unterziehen)? Klar, nichts ist unmöglich, aber das wäre schon irre. Der Speicherverbrauch bleibt relativ konstant. Das Programm lief ja sogar schon 2 Jahre (identisches Kompilat auch probiert) auf den alten PCs dort ohne Mucken.

Ich meine, gerade weil es 3 oder 5 neue Kisten eines Herstellers aus einer Bestellung/Charge sind, kann das vorkommen.
Wir hatten neulich einen "Schwung" Samsung Tablets, bei denen mittels eines Samsung Algorithmus (android) alle die gleiche DeviceID (UUID) bekamen, obwohl sie natürlich unterschiedlich sein sollte. Wäre wahrscheinlich nie aufgefallen, wenn man die Geräte stückweise bei verschiedenen Händlern gekauf hätte.

Namenloser 7. Jan 2016 13:29

AW: Stackoverflow finden - wenn es denn einer ist
 
Wie kommst du eigentlich auf Stackoverflow? Was deutet konkret darauf hin?

Ich würde eher vermuten, dass du an irgendeine WinAPI-Funktion ein ungültiges Objekt übergibst, also z.B. einen ungültigen Pointer. Der Code in der ntdll versucht dann darauf zuzugreifen und es kracht. Weil es in der WinAPI kracht und nicht in deinem eigenen Programm, schlägt dein Exception-Handling nicht an und du kriegst auch keinen aussagekräftigen Call-Stack. Es muss kein Pointer sein, den du direkt übergibt. Der Pointer könnte sich auch in einem nicht korrekt initialisierten Struct verstecken. Das könnte auch erklären, warum es erst ab einer gewissen Windows-Version auftritt, weil Structs ja manchmal reservierte Felder enthalten, die erst ab einer späteren Version interpretiert werden. Vielleicht wird durch fehlende Initialisierung manchmal zufällig ein neues Flag aktiviert, welches es unter XP nicht gab, was dazu führt, dass ein anderes Feld plötzlich als Pointer interpretiert wird o.ä..

Medium 7. Jan 2016 14:00

AW: Stackoverflow finden - wenn es denn einer ist
 
@himitsu: Ich habe aber doch gar keine Threads.

@Perlsau: Das wäre wohl die letzte und auch blödeste Lösung, weil mit mächtig Aufwand verbunden. Ich kann nur hoffen, dass sich der Kunde im Zweifelsfall darauf einlässt. Bevor ich diesen Schritt gehe würde ich aber gerne nichts unversucht lassen.

@jobo: Ja, normalerweise würde ich durchaus zustimmen. Aber Industrie-PCs sind ja gerade deshalb 3-4 mal so teuer wie vergleichbare Consumer-Hardware, weil sie intensiven Tests unterzogen werden. Jeder einzelne. Ausgeschlossen ist es damit zwar nicht, aber dass auf 3 PCs, egal welche Programme vorher gestartet sind, verlässlich immer nur mein kleines Tool genau immer an der gleichen Stelle den kaputten Speicher trifft... da muss selbst für IT-Maßstäbe schon viel Hexerei am Werk sein :)

@Namenloser: Stack-Overflow war in den von mir gefundenen Beiträgen im Netz das konsistenteste "Unterthema". Und ein Mal ist mein Programm auch wirklich mit dieser Meldung abgeschmiert! Also einfach das kleine Fensterchen, dass man von Delphi kennt: "Stapelüberlauf [OK]" (weiss nicht mehr ob auf Deutsch oder Englisch).
Ich selbst benutze keine direkten WinAPI Aufrufe, es läuft alles über die VCL. Wenn, dann müsste in dieser der Fehler liegen, und seit Jahren unbemerkt geblieben sein. Das ist wirklich ein total simples Programm. Keine Threads, bis auf Strings keine dynamischen Strukturen, keine WinAPI, keine Rekursionen, Standard-Projektoptionen, nur Pagecontrol, Listbox, Edits, Labels und Images auf dem Formular, ...nichts was traditionell zu einem Stack-Overflow führen sollte. Ich bin absolut baff.
Aber ich erkenne hier schon: Es scheint zumindest kein übliches Diagnose-Vorgehen zu geben in solchen Fällen. Muss ich den Kunden wohl vorerst vertrösten und später dann mal mit MadExcept/Eurekalog und/oder im Kompatibilitätsmodus laufen lassen, und hoffen dass hier was bei rum kommt. Geschlagen geben ist keine Option.

himitsu 7. Jan 2016 14:09

AW: Stackoverflow finden - wenn es denn einer ist
 
Nja, irgendwe fing hier mit Thread an. :stupid:


Zitat:

nach x minuten Absturz
Programmstarten, warten und dann einfach so peng?
(Timer?)

Oder macht der Benutzer da grade was?


Du kannst dein Programm mit Logging voll packen und dann schauen, wo dein Programm als Letztes vorbei kam und dann ab da weiter suchen.

notAssertor 7. Jan 2016 14:20

AW: Stackoverflow finden - wenn es denn einer ist
 
@Medium, Knochen statt Fleisch :-D

Schmiert das Programm auf allen PCs oder nur auf den Siemens-PCs ab?

Ist in das Programm eine Art XP-Manifest einkompiliert?

In diese beiden Richtungen würde ich zuerst rumstochern :duck:

VG

jobo 7. Jan 2016 14:24

AW: Stackoverflow finden - wenn es denn einer ist
 
Zitat:

Zitat von Medium (Beitrag 1326294)
@jobo: Ja, normalerweise würde ich durchaus zustimmen. Aber Industrie-PCs

Ok, ich will das nicht tot reiten, aber dazu noch ein Hinweis:
Wenn es ein IndustriePC ist, verwendet der jenseits der üblichen verdächtigen Komponenten vielleicht auch andere spezielle Hardware (inkl. Treiber).
Diese Hardware (Steckkarte,.. whatever) hat- Industriepc hin oder her- per se den Nachteil, dass sie eben nicht Standard ist (Häufiger Einsatz, Reifung beim Kunden, .. Robustheit). Zufällig neulich ein Beispiel mitbekommen: USB Chips werden gern von Intel oder Renesas verbaut. Die Teilearbeiten mit völlig unterschiedlichem Verhalten bezüglich Powersave Modus. Intel macht es ganz "aggressiv", Renesas lässiger. Der Fehler geschah nun immer beim Wechsel in den Powersave Mode (USB seitig). Für den Anwender war das scheinbar zufällig bzw. von außen kein Anlass erkennbar. Die Komponente war etwas besonders teures, quasi "Industrieware". Vlt klingelt es da noch mal bei Dir, Stichwort "Powersave nach einer bestimmten Zeit" oder "teurer Industriepc"
Für mich wäre die Frage einfach nur: Wie einfach und billig kann ich oder der Kunde das ausschließen, statt es nur für "unwahrscheinlich" zu erklären.
Inwieweit hier Randbedingungen meines Beispiels mit Deinem Fall übereinstimmen, Thema Wahrscheinlichkeit, musst Du selbst beurteilen.

Medium 7. Jan 2016 14:47

AW: Stackoverflow finden - wenn es denn einer ist
 
Zitat:

Zitat von notAssertor (Beitrag 1326300)
Schmiert das Programm auf allen PCs oder nur auf den Siemens-PCs ab?

Bisher nur auf diesen 3 Baugleichen. Auf einem anderen Panel-PC auch von Siemens in einem anderen Werk ist alles ok.

Zitat:

Ist in das Programm eine Art XP-Manifest einkompiliert?
Das werde ich mal prüfen. Gut möglich. Kann das solche seltsamen Auswirkungen haben!?

@jobo: Wie gesagt, du hast ja prinzipiell Recht. In den PCs ist meines Wissens nach zwar keine Spezialhardware, und sie gehen auch nicht in den Stromsparmodus, aber ich hetze meinen Kunden mal in diese Richtung.

@himi: Das passiert während niemand an der Kiste fummelt. Es guckt noch nichtmals einer drauf =). Feingliedriges Logging ist an sich eine gute Idee. Leider auch nur Ergebnisträchtig wenn ich hin fahre, aber das werde ich wohl als erstes tun.

nahpets 7. Jan 2016 15:12

AW: Stackoverflow finden - wenn es denn einer ist
 
Hast Du in dem Programm die Komponente TApplicationEvents drin (unter Delphi 7 gibt's die, bei neueren weiß ich nicht).

Zitat:

Zitat von Delphi7Hilfe
Beschreibung
Mit TApplicationEvents können die Ereignisse des globalen Anwendungsobjekts Application abgefangen werden. Wenn ein TApplicationEvents-Objekt in ein Formular eingefügt wird, leitet das Anwendungsobjekt alle Ereignisse an das TApplicationEvents-Objekt weiter. Somit ist jedes Ereignis des TApplicationEvents-Objekts mit dem gleichnamigen Ereignis des Objekts Application identisch.

Jedes Formular in einer Anwendung kann ein eigenes TApplicationEvents-Objekt besitzen. Die Anwendungsereignisse treten für alle TApplicationEvents-Objekte im Projekt auf. Die Reihenfolge, in der die einzelnen TApplicationEvents-Objekte Ereignisse empfangen, kann mit der Methode Activate gesteuert werden. Wenn andere TApplicationEvents am Empfang eines bestimmten Ereignisses gehindert werden sollen, verwenden Sie die Methode CancelDispatch.

Die Komponente hat auch ein Ereignis onException, dort solltest Du dann auch die nicht von Dir abgefangenen Exceptions "abbekommen".

Um "nicht auffindbare Fehler" zu finden, nutze ich die Jedis. Dort gibt es unter \install\JVCLInstall\Debug\ einen Dialog, der die Jedi-Fehlerbehandlung kapselt.

ExceptionDlg.pas und ExceptionDlg.dfm.

(Leider nicht ganz fehlerfrei, es fehlt die Konstante
Delphi-Quellcode:
AnsiCrLf = #13#10;
Und die Routine
Delphi-Quellcode:
begin
  if ExceptionShowing then
    Application.ShowException(Thread.SyncException)
  else
  begin
    ExceptionShowing := True;
    try
      ShowException(Thread.SyncException, Thread);
    finally
      ExceptionShowing := False;
    end;
  end;
end;
muss geändert werden in:
Delphi-Quellcode:
class procedure TExceptionDialog.ExceptionThreadHandler(Thread: TJclDebugThread);
begin
  if ExceptionShowing then
    Application.ShowException(Exception(Thread.SyncException))
  else
  begin
    ExceptionShowing := True;
    try
      ShowException(Exception(Thread.SyncException), Thread);
    finally
      ExceptionShowing := False;
    end;
  end;
end;
Ins Programm einbinden reicht, mit ausfühlicher MAP-Datei kompilieren und diese mit ausliefern.

Ein kleines Progrämmelchen, das die Jedi-Fehlerbehandlung enthält hängt an.

Der Dialog lässt sich sicherlich so anpassen, dass das Fehlerprotokoll in eine Datei geschrieben wird, die man Dir dann ggfls. per Mail schicken könnte.

jobo 7. Jan 2016 15:25

AW: Stackoverflow finden - wenn es denn einer ist
 
Zitat:

Zitat von Medium (Beitrag 1326306)
In den PCs ist meines Wissens nach zwar keine Spezialhardware, und sie gehen auch nicht in den Stromsparmodus, aber ich hetze meinen Kunden mal in diese Richtung.

Also einfach mal alles was geht (BIOS, OS) auf "volle Energie", ggF. gerade / vor allem die Netzwerkkarte(>sockets>SPS).

Helmi 7. Jan 2016 18:46

AW: Stackoverflow finden - wenn es denn einer ist
 
Hallo,

wenn du von Siemens-Rechner redest und diese in der Industrie sind:
Das sind aber nicht zufälligerweise Sinumerik 8x0-Anlagen mit PCU50´s?

Medium 7. Jan 2016 19:29

AW: Stackoverflow finden - wenn es denn einer ist
 
@Helmi: Ne, nicht diese Monster. Wenn ich der Optik trauen darf, dann müssten das SIMATIC IPC677D sein. Zumindest sehen die im Produktkatalog dem sehr ähnlich, wenn mich mein visuelles Erinnerungsvermögen nicht völlig verlassen hat.

@naphets: TApplicationEvents habe ich noch nie eingesetzt. (Kein Grund, hab's mir einfach nie genauer angesehen.) Aber riesen Dank für die Tipps bzgl. Jedi - die habe ich immerhin schon drauf! Das probiere ich auch mal. Wobei ich nach wie vor noch immer skeptisch bei den Error-Loggern bin, da das Programm ja scheinbar außerhalb der normalen Fehlerbehandlung aussteigt.

Helmi 7. Jan 2016 19:31

AW: Stackoverflow finden - wenn es denn einer ist
 
Zitat:

Zitat von Medium (Beitrag 1326334)
@Helmi: Ne, nicht diese Monster. Wenn ich der Optik trauen darf, dann müssten das SIMATIC IPC677D sein. Zumindest sehen die im Produktkatalog dem sehr ähnlich, wenn mich mein visuelles Erinnerungsvermögen nicht völlig verlassen hat.

Ich würd bei diesen Dingern etwas aufpassen - die tun so, als wären sie normale Rechner (müssten touch sein, wenn ich mich nicht täusche), sind es aber nicht
läuft da noch was anderes drauf? z. B. die WinCC-RunTime?

prüf auch mal ob alle Treiber aktuell sind (Siemens hat die Eigenart gerne mal was zu verbiegen)

vielleicht hilft dir auch das hier weiter

Medium 7. Jan 2016 19:51

AW: Stackoverflow finden - wenn es denn einer ist
 
Da da wohl wirklich handelsübliche Intel CPUs drin stecken, sollten die zumindest verflucht nah am PC sein. Es läuft auch ein normales Windows darauf. Von Siemens selbst ist dort keine Software installiert, außer eben ggf. Treiber. Das Diag-Tool werde ich mir mal direkt schnappen! Dankeschön!
Das benutzte SCADA System stammt von ProLeit, aber dort habe ich schon mit einem Wissenden gesprochen. Deren System ersetzt zwar die Shell, bringt aber keinerlei Treiber mit und installiert auch keine systemweiten Hooks oder so was. Deren Schuld kann ich zudem auch deshalb ausschließen, weil es nur auf 2 der 3 IPCs überhaupt installiert ist, aber mein Programm sich auf allen 3 gleich doof verhält.
Ansonsten läuft auf den Dingern nur noch ein BDE-Tool (Betriebsdatenerfassung, eher ein Teil des ERP mit ohne speziellen Dingen), ein COM-Port Mapper von MOXA und ein Sartorius OPC Server. All diese Komponenten waren jedoch in derselben Version bereits bei den Vorgängergeräten installiert, und sind es auch an dem anderen Standort, wo das Problem nicht existiert. (Leider weiss ich da nicht mehr welcher IPC es dort konkret ist.)

Helmi 7. Jan 2016 19:59

AW: Stackoverflow finden - wenn es denn einer ist
 
Ich muss bei so was immer an einen ehem. Kollegen denken, der eine Software für Sinumerik schrieb und mit den Siemens-Schikanen in Sachen Windows zu kämpfen hatte - von daher tipp ich bei so was schnell auf die Panels.

Hast du denn die Möglichkeit, mal einen normalen Rechner (also kein IPC) mit den gleichen Vorrausetzungen zu erzeugen und dort zu prüfen, ob das Problem auch dort auftaucht?

nahpets 7. Jan 2016 20:06

AW: Stackoverflow finden - wenn es denn einer ist
 
Zitat:

Zitat von Medium (Beitrag 1326334)
@Helmi: Ne, nicht diese Monster. Wenn ich der Optik trauen darf, dann müssten das SIMATIC IPC677D sein. Zumindest sehen die im Produktkatalog dem sehr ähnlich, wenn mich mein visuelles Erinnerungsvermögen nicht völlig verlassen hat.

@naphets: TApplicationEvents habe ich noch nie eingesetzt. (Kein Grund, hab's mir einfach nie genauer angesehen.) Aber riesen Dank für die Tipps bzgl. Jedi - die habe ich immerhin schon drauf! Das probiere ich auch mal. Wobei ich nach wie vor noch immer skeptisch bei den Error-Loggern bin, da das Programm ja scheinbar außerhalb der normalen Fehlerbehandlung aussteigt.

Bei meiner eigenen Implementierung für das Jedi-Exception-Handling (oder wie es auch immer heißen mag) bekomme ich eigentlich seitdem alle Fehler mit, auch die, bei denen ich vorher das Programm eigentlich nur noch erschießen konnte (das heißt leider nicht, dass Dein Problem damit "gefangen" werden muss, aber Versuch macht kluch).

Meine "Fehlerabfangroutine" sieht so aus:
Delphi-Quellcode:
{-----------------------------------------------------------------------------
  Procedure: AppEventsException
  Date:     04.10.2012
  Arguments: Sender: TObject; E: Exception
  Result:   None
  Purpose:  Ausgabe von Fehlermeldungen.
             Diese Routine wird beim Auftreten von Exceptions aufgerufen.
-----------------------------------------------------------------------------}
procedure TSBAutoRegistry.AppEventsException(Sender: TObject; E: Exception);
Var
          sExceptionClassMessage : String;
          sDebugMessage         : String;
          sMessage              : String;
          sAddr                 : String;
          sOwner                : String;
          dbgLocInfo            : TJclLocationInfo;
begin
  try
    // Ist Fehlerverursacher eine Komponente oder deren Nachfolger?
    if Sender is TComponent then begin
      // Hat sie einen Owner?
      if HasProperty(Sender, 'Owner') then begin
        // Dann diesen ermitteln
        sOwner := GetStrProp(Sender,'Owner');
        // und die Fehlermeldung zusammen bauen.
        sExceptionClassMessage := Format('%s, Fehlertyp: %s, Sender: %s [%s], Owner: %s',
                                        [E.Message,
                                         E.ClassName,
                                         TComponent(Sender).Name,
                                         Sender.ClassName,
                                         sOwner
                                        ]);
        // Sollen Debugfehlermeldungen erstellt werden?
        if fDebugMessages then begin
          sDebugMessage := Format('%s',[E.Message]) + #13 + #13
                         + Format('Fehlertyp: %s',[E.ClassName]) + #13
                         + Format('Sender: %s [%s]',[TComponent(Sender).Name,
                                                     Sender.ClassName]) + #13
                         + Format('Owner: %s',[sOwner]) + #13;
        end;
      end else begin
        // Es gibt keinen Owner
        // und die Fehlermeldung zusammen bauen.
        sExceptionClassMessage := Format('%s, Fehlertyp: %s, Sender: %s [%s]',
                                        [E.Message,
                                         E.ClassName,
                                         TComponent(Sender).Name,
                                         Sender.ClassName
                                        ]);
        // Sollen Debugfehlermeldungen erstellt werden?
        if fDebugMessages then begin
          sDebugMessage := Format('%s',[E.Message]) + #13 + #13
                         + Format('Fehlertyp: %s',[E.ClassName]) + #13
                         + Format('Sender: %s [%s]',[TComponent(Sender).Name,
                                                     Sender.ClassName]) + #13;
        end;
      end;
    end else begin
      // Der Fehlerverursacher ist keine Komponente oder einer ihrer Nachfolger.
      sExceptionClassMessage := Format('%s, Fehlertyp: %s, Sender: %s',
                                      [E.Message,
                                       E.ClassName,
                                       Sender.ClassName
                                      ]);
      // Sollen Debugfehlermeldungen erstellt werden?
      if fDebugMessages then begin
        sDebugMessage := Format('%s',[E.Message]) + #13 + #13
                       + Format('Fehlertyp: %s',[E.ClassName]) + #13
                       + Format('Sender: %s',[Sender.ClassName]) + #13;
      end;
    end;
  finally

  end;
  // Von der JCL genauere Fehlerinformationen ermitteln lassen
  dbgLocInfo := GetLocationInfo(ExceptAddr);
  // und diese in eine lesbare Zeichenfolge bringen lassen.
  sMessage  := GetLocationInfoStr(ExceptAddr, True, True, True, True);
  // Einen Teil davon möchten wir jedoch separat haben.
  sAddr     := Copy(sMessage,2,Pos(')',sMessage) - 2);
  // Und die Fehlermeldung in die LOG-Datei ausgeben.
  WriteAppLog(sExceptionClassMessage);
  WriteAppLog(sMessage);
  WriteAppLog(Format('Dateiname: %s',[ExtractFileName(dbgLocInfo.DebugInfo.FileName)]));
  WriteAppLog(Format('Fehleradresse: %s',[sAddr]));
  WriteAppLog(Format('Unit: %s',[dbgLocInfo.UnitName]));
  WriteAppLog(Format('Fehleradresse: %p',[dbgLocInfo.Address]));
  WriteAppLog(Format('Modulname: %s',[dbgLocInfo.SourceName]));
  WriteAppLog(Format('Prozedur: %s',[dbgLocInfo.ProcedureName]));
  WriteAppLog(Format('Prozeduroffset: %d',[dbgLocInfo.OffsetFromProcName]));
  WriteAppLog(Format('Zeilennummer: %d',[dbgLocInfo.LineNumber]));
  WriteAppLog(Format('Zeilenoffset: %d',[dbgLocInfo.OffsetFromLineNumber]));
  WriteAppLog(Format('Modul: %d [%x]',[dbgLocInfo.DebugInfo.Module, dbgLocInfo.DebugInfo.Module]));

  if fDebugMessages then begin
    // Dann hier eine entsprechende Zeichenfolge zusammenbauen.
    sDebugMessage := sDebugMessage + #13
                   + Format('Dateiname: %s',[ExtractFileName(dbgLocInfo.DebugInfo.FileName)]) + #13
                   + Format('Fehleradresse: %s',[sAddr]) + #13 + #13
                   + Format('Unit: %s',[dbgLocInfo.UnitName]) + #13
                   + Format('Fehleradresse: %p',[dbgLocInfo.Address]) + #13
                   + Format('Modulname: %s',[dbgLocInfo.SourceName]) + #13 + #13
                   + Format('Prozedur: %s',[dbgLocInfo.ProcedureName]) + #13
                   + Format('Prozeduroffset: %d',[dbgLocInfo.OffsetFromProcName]) + #13
                   + Format('Zeilennummer: %d',[dbgLocInfo.LineNumber]) + #13
                   + Format('Zeilenoffset: %d',[dbgLocInfo.OffsetFromLineNumber]) // + #13 + #13
//                 + Format('Modul: %d [%x]',[dbgLocInfo.DebugInfo.Module, dbgLocInfo.DebugInfo.Module])
//                 + Format('BinaryFile: %s',[dbgLocInfo.BinaryFileName]) + #13
                   ;
  end else begin
    sDebugMessage := e.Message;
  end;
  // Ist eine Ereignisroutine für die Fehlerausgabe... zugewiesen?
  if Assigned(fOnAppExceptionEvent) then begin
    fOnAppExceptionEvent(self,sDebugMessage);
  end else begin
    // Wenn keine Ereignisroutine für die Fehlerbehandlung zugewiesen ist,
    // geben wir hier selbst eine Fehlermeldung aus.
    MessageDlg(sDebugMessage, mtError, [mbOk], 0);
  end;
end;
Es ist die Ereignisroutine für TApplicationEvents.OnException.

Eventuell kannst Du mit Teilen davon ja was anfangen.

Medium 7. Jan 2016 20:20

AW: Stackoverflow finden - wenn es denn einer ist
 
Zitat:

Zitat von Helmi (Beitrag 1326339)
Ich muss bei so was immer an einen ehem. Kollegen denken, der eine Software für Sinumerik schrieb und mit den Siemens-Schikanen in Sachen Windows zu kämpfen hatte - von daher tipp ich bei so was schnell auf die Panels.

Ich gebe dir nur ZU gerne damit Recht, dass man i.A. in Siemens einen hervorragenden Generalsündenbock hat, bei dem man sogar überwiegend an der richtigen Adresse damit ist. Insbesondere die Qualität derer PC Software ist ...nicht gut. Fast egal was man in die Hand nimmt.

Zitat:

Hast du denn die Möglichkeit, mal einen normalen Rechner (also kein IPC) mit den gleichen Vorrausetzungen zu erzeugen und dort zu prüfen, ob das Problem auch dort auftaucht?
Leider nicht ohne relativ großen Aufwand, bzw. die OPC Software habe ich nicht. (Und weiss auch nicht, ob sie ohne angeschlossene Waagen überhaupt läuft. (Die sind via Netzwerk angebunden, nix spezielles.))
Ohne SPS Kommunikation und OPC Zeug habe ich keine Probleme hier. Leider ist es absolut möglich, und sogar sehr wahrscheinlich, dass ich auch mit diesen Dingen hier keine Fehler bekäme. Das würde zumindest der Beobachtung folgen, dass es an allen anderen IPCs läuft. (Insgesamt ist eine teils 1:1, teils fast identische Variante auf >15 IPCs an 3 Standorten seit >5 Jahren im Einsatz.)


@nahpets: Wow, danke dir. Das landet auf jeden Fall auf der Liste der zu testenden Dinge.

nahpets 7. Jan 2016 23:07

AW: Stackoverflow finden - wenn es denn einer ist
 
Wie sieht eigentlich Deine Timerroutine aus?

So in der Art?
Delphi-Quellcode:
procedure TForm1.SpecialTimer1Timer(Sender: TObject);
begin
  SpecialTimer1.Enabled := False;

... hier machen wir was...

  SpecialTimer1.Enabled := True;
end;
Wenn nein kann es passieren, dass das Timerereignis aufgerufen wird, wenn das vorherige noch nicht abgearbeitet ist, das kann zu einem StackOverflow führen.

Aus dem Grund habe ich mir angewöhnt im Timerereignis den Timer immer zuerst auszuschalten und am Ende wieder einzuschalten.

Medium 7. Jan 2016 23:21

AW: Stackoverflow finden - wenn es denn einer ist
 
Genau so mache ich das auch, da im Timer ein Request via Socket an die SPS geschickt wird, und man da ja nicht immer 100% auf den Connect vertrauen kann. (Kabel kaputt, Stecker locker, Pups quer, etc.) Verlängert zwar das effektive Intervall nachher ein wenig, aber das ist in dem Fall unwichtig.


Alle Zeitangaben in WEZ +1. Es ist jetzt 18:37 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