Einsteiger-Kapitel - Speicher-Zugriff
Einige PureBasic-Anweisungen, zum Beispiel die aus der Cipher Bibliothek, und viele Betriebssystem-API-Aufrufe benötigen einen Zeiger (Pointer) auf einen Speicherpuffer als ein Argument, anstatt die Daten direkt selbst. PureBasic bietet eine Reihe von Anweisungen zum Manipulieren des Speicherpuffers, um dies zu erleichtern. ;- Compiler-Direktiven
EnableExplicit
;- Konstanten
; Fenster
Enumeration
#WindowHex
EndEnumeration
; Gadgets
Enumeration
#GadgetFiles
#GadgetOpen
#GadgetClose
#GadgetHex
EndEnumeration
;- Variablen
Define.l Event, EventWindow, EventGadget, EventType, EventMenu
Define.l Length
Define.s File
Define *Buffer
;- Deklarationen
Declare WindowCreate()
Declare WindowResize()
Declare FileClose()
Declare FileDisplay()
Declare FileRead()
;- Implementierung
Procedure WindowCreate()
; Erstellen des Fensters.
Protected.l Col
Protected.s Label
If OpenWindow(#WindowHex, 50, 50, 500, 400, "Hex View", #PB_Window_SystemMenu | #PB_Window_SizeGadget | #PB_Window_MinimizeGadget | #PB_Window_TitleBar)
; Festlegen des Mindest-Fenstergröße.
WindowBounds(#WindowHex, 175, 175, #PB_Ignore, #PB_Ignore)
; Erstellen der Explorer Liste und Einstellen auf das Benutzer-Verzeichnis.
ExplorerListGadget(#GadgetFiles, 5, 5, 490, 175, GetHomeDirectory())
; Schalter.
ButtonGadget(#GadgetOpen, 5, 185, 80, 25, "Open")
ButtonGadget(#GadgetClose, 100, 185, 80, 25, "Close")
; ListIcon Gadget.
ListIconGadget(#GadgetHex, 5, 215, 490, 180, "Offset", 80, #PB_ListIcon_AlwaysShowSelection | #PB_ListIcon_GridLines | #PB_ListIcon_FullRowSelect)
; Spalten-Überschriften.
For Col = 0 To 7
Label = RSet(Hex(Col, #PB_Byte), 2, "0")
AddGadgetColumn(#GadgetHex, Col + 1, Label, 38)
Next Col
AddGadgetColumn(#GadgetHex, 9, "Text", 80)
EndIf
EndProcedure
Procedure WindowResize()
; Verändern der Gadgetgröße auf die neue Fenstergröße.
Protected.l X, Y, W, H
; Explorer Liste
W = WindowWidth(#WindowHex) - 10
H = (WindowHeight(#WindowHex) - 35) / 2
ResizeGadget(#GadgetFiles, #PB_Ignore, #PB_Ignore, W, H)
; Schalter
Y = GadgetHeight(#GadgetFiles) + 10
ResizeGadget(#GadgetOpen, #PB_Ignore, Y, #PB_Ignore, #PB_Ignore)
ResizeGadget(#GadgetClose, #PB_Ignore, Y, #PB_Ignore, #PB_Ignore)
; ListIcon Anzeige
Y = (WindowHeight(#WindowHex) / 2) + 23
W = WindowWidth(#WindowHex) - 10
H = WindowHeight(#WindowHex) - (Y + 5)
ResizeGadget(#GadgetHex, #PB_Ignore, Y, W, H)
EndProcedure
Procedure FileClose()
; Löscht die Listen-Anzeige und gibt den Speicherpuffer frei.
Shared Length, *Buffer
ClearGadgetItems(#GadgetHex)
FillMemory(*Buffer, Length)
FreeMemory(*Buffer)
EndProcedure
Procedure FileDisplay()
; Anzeigen des Datei-Puffers in der Listen-Anzeige.
Shared Length, *Buffer
Protected *Byte
Protected Peek
Protected.l Rows, Cols, Offset
Protected.s OffsetString, Row, String
; Löschen der aktuellen Inhalte.
ClearGadgetItems(#GadgetHex)
; Die Zeilen durchlaufen.
For Rows = 0 To Length - 1 Step 8
; Löschen des Text-Wertes jeder Zeile.
String = ""
; Konvertieren des Offset-Wertes in einen String fester Länge.
Row = RSet(Hex(Rows, #PB_Long), 6, "0") + Chr(10)
; Die Spalten durchlaufen.
For Cols = 0 To 7
; Offset für die aktuelle Spalte berechnen.
Offset = Rows + Cols
; Den Offset mit der Datei-Größe vergleichen.
If Offset < Length
; Der Offset ist kleiner als die Länge der Datei.
; Das Byte vom Puffer ermitteln.
*Byte = *Buffer + Offset
Peek = PeekB(*Byte)
; Das Byte in Text konvertieren.
Row + RSet(Hex(Peek, #PB_Byte), 2, "0") + Chr(10)
; Das Zeichen zur Text-Version hinzufügen.
Select Peek
Case 0 To 31, 127
; Nicht druckbare/darstellbare Zeichen.
String + Chr(129)
Default
; Darstellbare Zeichen.
String + Chr(Peek)
EndSelect
Else
; Der Offset ist größer als die Länge der Datei.
; Eine leere Spalte hinzufügen.
Row + Chr(10)
EndIf
Next Cols
; Die Text-Version am Ende der Hex-Spalten hinzufügen.
Row + String
; Hinzufügen der komplettierten Zeile zur Listen-Anzeige.
AddGadgetItem(#GadgetHex, -1, Row)
Next Rows
EndProcedure
Procedure FileRead()
; Lesen der Datei in den Speicherpuffer.
Shared Length, File, *Buffer
Protected.b ReadByte
Protected.l FileNumber, ReadLong, Size
; Stoppen wenn die Datei leer ist.
If File = ""
ProcedureReturn
EndIf
; Stoppen wenn die Dateigröße ungültig ist.
Size = FileSize(File)
If Size < 1
ProcedureReturn
EndIf
; Öffnen der Datei.
FileNumber = OpenFile(#PB_Any, File)
Length = Lof(FileNumber)
If File And Length
; Einen Speicherpuffer reservieren, um darin die Datei aufzunehmen.
*Buffer = AllocateMemory(Length)
; Lesen der Datei in den Puffer.
Length = ReadData(FileNumber, *Buffer, Length)
EndIf
; Schließen der Datei.
CloseFile(FileNumber)
EndProcedure
;- Hauptteil
WindowCreate()
;- Ereignis-Schleife
Repeat
; Ermitteln der Ereignis-Parameter.
Event = WaitWindowEvent()
EventGadget = EventGadget()
EventType = EventType()
EventWindow = EventWindow()
; Verarbeiten der Ereignisse.
Select Event
Case #PB_Event_Gadget
If EventGadget = #GadgetFiles
; Tue nichts.
ElseIf EventGadget = #GadgetOpen
File = GetGadgetText(#GadgetFiles) + GetGadgetItemText(#GadgetFiles, GetGadgetState(#GadgetFiles))
If FileSize(File) > 0
FileRead()
FileDisplay()
EndIf
ElseIf EventGadget = #GadgetClose
FileClose()
ElseIf EventGadget = #GadgetHex
; Tue nichts.
EndIf
Case #PB_Event_CloseWindow
If EventWindow = #WindowHex
CloseWindow(#WindowHex)
Break
EndIf
Case #PB_Event_SizeWindow
WindowResize()
EndSelect
ForEver
Einsteiger-Kapitel Navigation
< Vorheriges: Lesen und Schreiben von Dateien | Überblick | Nächstes: Dynamische Nummerierung mittels #PB_Any >