Stapel (engl.: Stack): Ein festgelegter Speicherbereich, der von Visual Basic verwendet wird, um lokale Variablen und Argumente zwischen Prozeduraufrufen zwischenzuspeichern (VB-Dokumentation). Bei jedem Aufruf einer Funktion wird Platz auf dem Stapel für die Parameter der Funkton und für die lokalen Variablen benötigt und beim Verlassen der Funktion automatisch wieder freigegeben. Mögliche Ursachen für einen Überlauf des Stapelspeichers: Bei rekursiven Funktionsaufrufen (d.h. eine Funktion ruft sich selbst auf oder ruft eine zweite Funktion die ihrerseits die erste wieder aufruft usw.) kann es zu einer langen Schlange im Stapel kommen. Der Fehler „Nicht genügend Stapelspeicher" zeigt an, dass der Stapelbereich voll ist. Falls in diesem Fall statt lokaler Variablen modulglobale Variable verwendet werden, "schont" das den Stapelspeicher. Allerdings greifen dann alle rekursiven Aufrufe auf die gleichen Variablen zu - ein Effekt, der häufig nicht gewünscht wird. Ein bekanntes Beispiel für rekursive Programmierung ist der Quicksort-Algorithmus. Ein andere Ursache für das Anwachsen des Stapelspeicher-Bedarfs sind sogenannte Ereignisketten: Wenn in einer Ereignisbehandlungs-Routine auf bestimmte Steuerelemente-Eigenschaften zugegriffen wird, werden automatisch andere Ereignisse ausgelöst, deren Behandlungsroutinen ihrerseits Ereignisse provozieren (Kaskadeneffekt). Man sollte deshalb vor der Abarbeitung von Code zur Ereignisbehandlung eine formular-globale boolsche Variable auf 'true' setzen und danach wieder auf 'false'. In allen 'sensiblen' Ereignisroutinen (z.B. 'Change'-Ereignisse) ist am Anfang diese Variable abzufragen: Ist sie auf 'true' gesetzt, wird nichts gemacht. Da VB-Programme standardmäßig mit einem genügend großen Stapel (1 Megabyte) ausgestattet werden, weisen Stapelprobleme meist auf Fehler in Rekursion oder Ereignisbehandlung hin. Die VB-Dokumentation enthält leider nur wenige Hinweise bezüglich der Verwendung des Stapels:
Manipulation der Größe des Stapelspeichers: Wenn die Stapelgröße eines Programms geändert werden soll, muss beim Linken die Option 'STACK' gesetzt werden.
Ab sofort werden alle Linkeraufrufe der VB-IDE von LINK.EXE abgefangen.
Vor dem Aufruf des Linkers wird dann eine VB-Input-Box angezeigt, in der die gewünschte Größe des Stapels festgelegt werden kann (in Kilobyte). Eingaben unter 250 werden auf 250 KB gesetzt, Eingaben über 5000 werden auf 5000 KB gesetzt. Bei Betätigung der Taste 'Abbrechen' und bei 'leerer' oder unplausibler Eingabe wird der Standardwert von 1 MB verwendet. Details zum Stapel:
Fazit: ' ==================================================================== ' Programm, das die IDE-Linkeraufrufe abfängt und ' die Optionen hinzufügt (falls gewünscht) ' Schritt-Folge: ' 1. Dieses Programm übersetzen ('Sub Main') ' 2. VB6-Linker 'Link.Exe' in VBLink.EXE umbenennen ' 3. Dieses Programm muss 'Link.EXE' genannt und ' in den VB6-Ordner kopiert werden ' ==================================================================== Option Explicit ' vereinfachte UDTs für die Prozess-Erzeugung Private Type PROCESS_INFO hProcess As Long x(1 To 12) As Byte End Type Private Type STARTUP_INFO Size As Long Reserved As String Desktop As String Title As String x(1 To 28) As Byte Flags As Long Show As Integer y(1 To 16) As Byte End Type ' API-Funktionen für die Prozess-Erzeugung Private Declare Function CreateProcess Lib "Kernel32" _ Alias "CreateProcessA" ( _ ByVal AppName As Long, _ ByVal CmdLine As String, _ ByVal ProcAttr As Long, _ ByVal ThreadAttr As Long, _ ByVal InheritedHandle As Long, _ ByVal CreationFlags As Long, _ ByVal Env As Long, _ ByVal CurDir As Long, _ Startup As STARTUP_INFO, _ Process As PROCESS_INFO) As Long Private Declare Function WaitForSingleObject Lib "Kernel32" ( _ ByVal Handle As Long, _ ByVal MilliSeconds As Long) As Long Private Declare Function CloseHandle Lib "Kernel32" ( _ ByVal Object As Long) As Long ' Rückgabe von WaitForSingleObject Private Const WAIT_TIMEOUT = 258& Private Const WAIT_FAILED = &HFFFFFFFF Private Const INFINITE = &HFFFFFFFF Const cTitel As String = "VB-Link (Systemcode)" Private Sub Main() ' VB-Linkeraufrufe anfangen und MAP/STACK setzen Dim rs As String, r As Long ' Dialog-Reaktion Dim CmdLine As String ' Kommandozeile Dim st As Long ' Größe des Stack Dim t1 As Long, t2 As Long ' Position Dateiname Dim exedat As String ' Name der zu erstellenden Datei Dim dat As String, d() As String ' Abfrage des IDE-Linkeraufrufs CmdLine = Command() ' Name der Ausgabedatei des Linkers ermitteln (für Dialog) t1 = InStr(CmdLine, "/OUT:") t2 = InStr(CmdLine, "/BASE:") If t2 > t1 + 10 And t1 > 0 Then exedat = Mid(CmdLine, t1 + 6, t2 - (t1 + 6) - 2) d() = Split(exedat, "\") dat = Trim(d(UBound(d))) End If ' Mapfile gewünscht? r = MsgBox("Erstellte Datei: " + vbCrLf + dat + _ vbCrLf + vbCrLf + "Map-File erstellen?", vbYesNo, cTitel) If r = vbYes Then CmdLine = CmdLine + " /MAP" ' Stacksize festlegen rs = InputBox("Erstellte Datei: " + vbCrLf + dat + vbCrLf + vbCrLf + _ "Stackgröße (KB): " + vbCrLf + _ "mindestens 250 KB", cTitel, " 1024 ") If StrPtr(rs) <> 0 And rs <> "" Then ' Stackgröße auslesen und in Bytes wandeln st = DLNG(rs) * 1024 CmdLine = CmdLine + " /STACK:" + CStr(st) End If ' VB6-Linker aufrufen: umbenannt als 'VBLink.EXE' ShellWait App.Path + "\VBLink.exe " + CmdLine End Sub Private Function DLNG(ByVal rs As String) As Long ' Auswertung des Rückgabe-Strings Dim d As Long On Error GoTo fehler d = CLng(rs) ' sinnvolle Stackgröße setzen (Kilobytes) If d < 250 Then d = 250 If d > 5000 Then d = 5000 DLNG = d Exit Function fehler: DLNG = 1000 ' Standardwert bei unplaus. Eingabe End Function Public Function ShellWait(ByVal Execute As String) As Boolean ' Funktion erstellt einen Prozess und wartet ' bis der Prozess sich meldet bzw. abgeschlossen ist Dim Prc As PROCESS_INFO ' Infos zum erstellten Prozess Dim Startup As STARTUP_INFO ' Prozess-Start-Infos Dim Ret As Long ' API-Rückgabe Const MilliSeconds As Long = INFINITE ' unbegrenzt warten ' Initialisierung Prozess-Start With Startup .Size = Len(Startup) .Flags = 1 End With ' Prozess generieren Ret = CreateProcess(0&, Execute, 0&, 0&, 1&, &H20&, 0&, 0&, Startup, Prc) If Ret = 0 Then MsgBox "Warnung: Linker lässt sich nicht starten", vbCritical, cTitel DoEvents Exit Function End If ' Kompilierung abwarten Ret = WaitForSingleObject(Prc.hProcess, MilliSeconds) If Ret = WAIT_FAILED Or Ret = WAIT_TIMEOUT Then MsgBox "Warnung: Linker reagiert nicht", vbCritical, cTitel DoEvents End If ' Prozess-Handle freigeben CloseHandle Prc.hProcess End Function ' ==================================================================== Dieser Tipp wurde bereits 21.057 mal aufgerufen. Voriger Tipp | Zufälliger Tipp | Nächster Tipp
Anzeige
Diesen und auch alle anderen Tipps & Tricks finden Sie auch auf unserer aktuellen vb@rchiv Vol.6 Ein absolutes Muss - Geballtes Wissen aus mehr als 8 Jahren vb@rchiv! - nahezu alle Tipps & Tricks und Workshops mit Beispielprojekten - Symbol-Galerie mit mehr als 3.200 Icons im modernen Look Weitere Infos - 4 Entwickler-Vollversionen (u.a. sevFTP für .NET), Online-Update-Funktion u.v.m. |
vb@rchiv CD Vol.6 Geballtes Wissen aus mehr als 8 Jahren vb@rchiv! Online-Update-Funktion Entwickler-Vollversionen u.v.m. Tipp des Monats März 2024 Dieter Otter UTF-8 Konvertierung von Dateien und Strings VB6 selbst verfügt über keine Funktionen zur UTF-8 Konvertierung von Daten. Mit Hilfe des ADODB.Stream-Objekts lassen sich diese fehlenden Funktionen aber schnell nachrüsten. Neu! sevPopUp 2.0 Dynamische Kontextmenüs! Erstellen Sie mit nur wenigen Zeilen Code Kontextmenüs dynamisch zur Laufzeit. Vordefinierte Styles (XP, Office, OfficeXP, Vista oder Windows 8) erleichtern die Anpassung an die eigenen Anwendung... |
||||||||||||||||
Microsoft, Windows und Visual Basic sind entweder eingetragene Marken oder Marken der Microsoft Corporation in den USA und/oder anderen Ländern. Weitere auf dieser Homepage aufgeführten Produkt- und Firmennamen können geschützte Marken ihrer jeweiligen Inhaber sein. |