Das Notes Forum
Domino 9 und frühere Versionen => ND8: Entwicklung => Thema gestartet von: Lloyd am 04.04.12 - 18:20:50
-
Hi,
ich bekomme in einer meiner Funktionen einen Fehler [Out of Stack Space]. Aus dem Forum habe ich schon rausbekommen dass es sich hierbei scheinbar um eine Rekursion handeln muss. Ich habe jetzt schon alle möglichen Dinge im Script verändert, ich komme aber nicht dahinter wo es klemmt. Kann jemand aus dem Script erkennen wo mein Problem liegen könnte? Ich vermute dass es an der Klasse "ArraySets" liegt, die ich insgesamt 3 mal unter anderem Variablen-Namen verwende (Dim ApplList As New ArraySets, ApplList2 As New ArraySets, ApplList3 As New ArraySets). Sorry für das lange Script, aber ich denke man braucht alle Infos um dem Fehler auf die Spur zu kommen.
Sub Click(Source As Button)
Dim ws As New NotesUIWorkspace
Dim uidoc As NotesUIdocument
Dim s As New NotesSession
Dim db As NotesDatabase
Dim importpfad As String
Dim zeile As String
Dim tz As String
Dim cpname As String
Dim software As String
Dim version As String
Dim installationsdatum As String
Dim cpnamenum As Integer
Dim softwarenum As Integer
Dim versionnum As Integer
Dim instdatumnum As Integer
Dim count As Long
Dim item As NotesItem, item2 As NotesItem
Dim keys( 1 To 2 ) As String
Dim connectold As Variant, connectold2 As Variant
Dim hwentry As Integer, swentry As String
Dim keywert As String
Dim item3 As NotesItem
Dim hwview As NotesView
Dim hwdoc As NotesDocument
Dim view As NotesView
Dim swdoc As NotesDocument
Dim ndoc As Notesdocument
Set db = s.CurrentDatabase
Set uidoc = ws.CurrentDocument
Dim ApplList As New ArraySets, ApplList3 As New ArraySets
Dim ApplList2 As New ArraySets
Call ApplList3.Init
Set hwview = db.GetView("($cpname)")
importpfad = uidoc.FieldGetText("import_pfad")
tz = uidoc.FieldGetText("import_tz")
If uidoc.FieldGetText("import_sw_cpname") <> "" Then
cpnamenum = uidoc.FieldGetText("import_sw_cpname")
End If
If uidoc.FieldGetText("import_sw_name") <> "" Then
softwarenum = uidoc.FieldGetText("import_sw_name")
End If
If uidoc.FieldGetText("import_sw_version") <> "" Then
versionnum = uidoc.FieldGetText("import_sw_version")
End If
If uidoc.FieldGetText("import_sw_instdatum") <> "" Then
instdatumnum = uidoc.FieldGetText("import_sw_instdatum")
End If
count = 0
Filenum = Freefile
Open importpfad For Input As Filenum
Do While Not Eof( Filenum)
count = count + 1
Print "Lese Zeile " & Cstr(count) & " Bitte warten ..."
Line Input #FileNum, zeile
If cpnamenum <> 0 Then
cpname = Strtoken(zeile, tz, cpnamenum)
Set hwdoc = hwview.GetDocumentByKey(cpname)
If hwdoc Is Nothing Then
Gosub Weiter ' Wenn kein Hardwaredokument existiert dann zum nächsten Datensatz in der Importdatei
End If
End If
If softwarenum <> 0 Then
software = Strtoken(zeile, tz, softwarenum)
keys( 1 ) = software
End If
If versionnum <> 0 Then
version = Strtoken ( zeile, tz, versionnum )
keys( 2 ) = version
End If
If instdatumnum <> 0 Then
installationsdatum = Strtoken ( zeile, tz , instdatumnum )
End If
' Prüfen ob für diese Software ein Massenänderungsdokument existiert und wenn ja dann Namen umbenennen
%REM
swname = Massenänderung_SWName_einzeln(software)
If (Cstr(swname) <> "") Then
software = Cstr(swname)
keys( 1 ) = Cstr(swname)
End If
%ENDREM
' ### START Prüfen ob Software Stammdokument schon existiert ###
Set view = db.GetView("$software")
If (keys(2) <> "") And (keys(2) <> " ") Then
Set swdoc = view.GetDocumentByKey(keys)
Else
Set swdoc = view.GetDocumentByKey(software)
End If
If Not swdoc Is Nothing Then '(1)
BestehendeSofware:
' Print "Lizenzblatt existiert"
' Wenn Lizenzblatt existiert dann nur verknüpfen mit Hardware
Call ApplList.Init
connectold = swdoc.GetItemValue("sw_connections")
If (connectold(0) = "") Then
ApplList.AddElement ( hwdoc.UniversalID)
Else
Forall c In connectold
ApplList.AddElement ( c)
End Forall
End If
hwentry = ApplList.Search(Cstr(hwdoc.UniversalID))
If (hwentry <> 0) Then
' Wenn der CPName schon existiert dann nicht verknüpfen
' Print "Der PCName wurde im Softwareblatt bereits verknüpft"
Call ApplList2.Init
connectold2 = hwdoc.GetItemValue("sw_connections")
If (connectold2(0) = "") Then
ApplList2.AddElement ( swdoc.UniversalID)
Else
Forall d In connectold2
ApplList2.AddElement ( d)
End Forall
End If
swentry = ApplList2.Search(Cstr(hwdoc.UniversalID))
If (swentry = 0) Then
' Print "Die Software wurde noch nicht im Hardwaredokument verknüpft"
Set item3 = hwdoc.GetFirstItem( "sw_connections" )
Call item3.AppendToTextList( swdoc.UniversalID)
Call hwdoc.Save(True,False)
Else
' Print "Die Software wurde bereits im Hardwaredokument verknüpft"
End If
Else
' Wenn der CPNAME nicht existiert dann verknüpfen
' Print "Der PCName wurde im Softwareblatt noch nicht verknüpft"
' Verknüpfe PC im Softwaredokument
Set item = swdoc.GetFirstItem( "sw_connections" )
Call item.AppendToTextList( hwdoc.UniversalID)
Call swdoc.Save(True,False)
Call ApplList2.Init
connectold2 = hwdoc.GetItemValue("sw_connections")
If (connectold2(0) = "") Then
ApplList2.AddElement ( swdoc.UniversalID)
Else
Forall d In connectold2
ApplList2.AddElement ( d)
End Forall
End If
swentry = ApplList2.Search(Cstr(hwdoc.UniversalID))
If (swentry = 0) Then
' Print "Die Software wurde noch nicht im Hardwaredokument verknüpft"
Set item3 = hwdoc.GetFirstItem( "sw_connections" )
Call item3.AppendToTextList( swdoc.UniversalID)
Call hwdoc.Save(True,False)
Else
' Print "Die Software wurde bereits im Hardwaredokument verknüpft"
End If
End If
Else '(1)
' Wenn Lizenzblatt nicht existiert dann erst neues Lizenzblatt anlegen und dann mit Hardware verknüpfen
swentry = ApplList3.Search_Extended(software)
If (swentry = "") Then '(2)
NeueSoftware:
' Print "Es existiert noch kein Lizenzblatt zu dieser Software"
Set ndoc = db.CreateDocument
ndoc.Form = "lizenzblatt"
ndoc.lizenz_swname = software
ndoc.lizenz_swversion = version
ndoc.lizenz_typ = "Unbestimmt"
ndoc.sw_connections = hwdoc.UniversalID ' Verknüpfe PC im Softwaredokument
Call ndoc.ComputeWithForm(True,False)
Call ndoc.Save(True,False)
ApplList3.AddElement ( software & "##" & ndoc.UniversalID )
Call ApplList2.Init
connectold2 = hwdoc.GetItemValue("sw_connections")
If (connectold2(0) = "") Then
ApplList2.AddElement ( ndoc.UniversalID)
Else
Forall d In connectold2
ApplList2.AddElement ( d)
End Forall
End If
swentry = ApplList2.Search(Cstr(hwdoc.UniversalID))
If (swentry = 0) Then
' Print "Die Software wurde noch nicht im Hardwaredokument verknüpft"
Set item3 = hwdoc.GetFirstItem( "sw_connections" )
Call item3.AppendToTextList( ndoc.UniversalID)
Call hwdoc.Save(True,False)
Else
' Print "Die Software wurde bereits im Hardwaredokument verknüpft"
End If
Else '(2)
Set swdoc = db.GetDocumentByUNID(swentry)
If Not swdoc Is Nothing Then
Gosub BestehendeSofware
Else
Gosub NeueSoftware
End If
End If '(2)
End If '(1)
' ### ENDE Prüfen ob Software Stammdokument schon existiert ###
Weiter:
Loop
Close #FileNum
End Sub
'==========================================================================================
' START C L A S S "ArraySets"
'==========================================================================================
Class ArraySets
Public Value() As String
Public TotalElements As Long
Sub Init
TotalElements = 0
Redim Value(1 To 1) As String
End Sub
Sub AddElement(NewValue As String)
TotalElements = TotalElements + 1
Redim Preserve Value(1 To TotalElements) As String
Value(TotalElements) = NewValue
End Sub
Function Search(SearchFor As String) As Integer
Dim CurrentLabelEntry As Integer
CurrentLabelEntry = 0
Forall c In Value
If Ucase(c) = Ucase(SearchFor) Then
CurrentLabelEntry = CurrentLabelEntry + 1
End If
End Forall
Search = CurrentLabelEntry
End Function
Function Search_Extended(SearchForString As String) As String
Dim CurrentLabelEntry As String
CurrentLabelEntry = ""
Forall c In Value
If Strleft(Ucase(c),"##") = Ucase(SearchForString) Then
CurrentLabelEntry = Strright(c,"##")
End If
End Forall
Search_Extended = CurrentLabelEntry
End Function
End Class
'==========================================================================================
' ENDE C L A S S "ArraySets"
'==========================================================================================
-
Wo ist Dein ErrorHandling, das Dir sagt, in welcher Zeile es knallt?
Ohne dieses Minimum guten Codings bist Du hilflos - und wir eher nicht gewillt, unter diesen Umständen Deinen Code "blind" durchzuflöhen.
Bernhard
-
Hallo Bernhard,
du hast natürlich recht. Ich hatte den Code auf das Minimum zusammengeschrumpft, bevor ich den hier eingestellt habe. Anbei der Screenshot meiner Fehlerbehandlung, die vorher mal drin war:
Der Fehler tritt dabei in Zeile 177 auf, was die folgende CodeZeile ist:
swentry = ApplList3.Search_Extended(software)
-
Die Fehlermeldung [Out of Stack Space] sagt eigentlich ziemlich genau was passiert.
If cpnamenum <> 0 Then
cpname = Strtoken(zeile, tz, cpnamenum)
Set hwdoc = hwview.GetDocumentByKey(cpname)
If hwdoc Is Nothing Then
==> Gosub Weiter ' Wenn kein Hardwaredokument existiert dann zum nächsten Datensatz in der Importdatei
End If
End If
.........
Weiter:
Loop
Close #FileNum
End Sub
Du willst hier ans Ende der Schleife springen aber anstatt GOTO verwendest du GOSUB mit dem das Unterprogramm "Weiter" aufgerufen wird.
Bei jedem GOSUB merkt sich Lotusscript auf dem Stack die Adresse nach dem GOSUB um beim Ende des Unterprogrammes bei Ausführung der RETURN Anweisung zu wissen wohin es zurückspringen muss. Nun gibt es bei dir aber kein RETURN und so wird die Liste der Rücksprungadressen auf dem Stack immer größer bis es dann mal knallt weil kein Speicher mehr frei ist.
Soweit ich weiss ist die Stackgrösse auf 32K limtiert, versuchweise reicht das etwa für 2000 Aufrufe oder weniger, je nachdem was sonst noch auf dem Stack ist.
Ersetze alle GOSUB durch ein GOTO und dieser Fehler dürfte dann nicht mehr auftreten.
Noch besser wäre wenn du die Programmlogik änderst und erst gar kein GOTO verwendest,
momentan ist das ziemlich unübersichtlich und in einem halben Jahr blickst du selber nicht mehr durch.
Gruss
Peter
-
Hallo Peter,
du hast ja sowas von Recht. VIELEN VIELEN DANK. Da wäre ich nie drauf gekommen!
Und ja du hast nochmal recht: Das sieht sehr unübersichtlich aus. Das liegt aber daran dass ich sämtliche Funktionen zusammengefasst habe, damit es im Forum etwas "übersichtlicher/nachvollziehbarer" wird. Nachdem du mir jetzt den Fehler aufgezeigt hast, baue ich das wieder um.
Nochmal herzlichen Dank, vor allem für die ausführliche Erläutern der Fehlerursache. Damit habe ich auch verstanden warum das passiert.
Ach ja, du hast auch ein Drittes mal recht. Der Fehler trat in der Tat nach etwas mehr als dem 2000 Aufruf auf.
-
http://www.cleancoders.com/
Du hast die hier wohl angebrachten ca 10 privaten Funktionen per Hand ge-inlined, um das zu posten ??? Mir ist das völlig egal, aber da reservier ich mir ein paar hmm Zweifel. Aber wie gesagt, total egal. Kauft ein paar Folgen von obigen Film.