PureBasic

Руководство - Доступ к памяти

Некоторые инструкции PureBasic, например, из библиотеки Cipher и многие вызовы API для операционной системы, требуют указателя на буфер памяти в качестве аргумента, а не непосредственно на данные. PureBasic предоставляет ряд инструкций для управления буферами памяти, для решения данных ситуаций.

В этом примере используется буфер для чтения файла с диска в память. Затем, с помощью ListIconGadget() содержимое буфера преобразуется в шестнадцатеричный текстовый вид, что работает как простое средство просмотра hex.

ExplorerListGadget() используется для отображения содержимого исходного каталога пользователя изначально и для выбора файла. Предусмотрены две кнопки: одна для отображения файла, другая для очистки экрана.

Гаджет ListIcon разделен на девять столбцов, первый показывает базовое смещение каждой строки в списке, следующий показывает восемь значений байта, смещенных от базового значения, а девятый показывает строковый эквивалент этих восьми значений.

Используются два указателя - первый (* Buffer) содержит адрес памяти полного файла. Второй (* Byte), в процедуре "FileDisplay", демонстрирует использование арифметики указателей и команды Peek для получения отдельных значений из буфера.

Наконец, процедура "FileClose" демонстрирует использование инструкции FillMemory() для перезаписи содержимого буфера и FreeMemory(), для освобождения памяти занятой под буфер.

;- Директивы компилятора
EnableExplicit

;- Константы
; Window (окна)
Enumeration
    #WindowHex
EndEnumeration

; Гаджеты
Enumeration
    #GadgetFiles
    #GadgetOpen
    #GadgetClose
    #GadgetHex
EndEnumeration

;- Переменные
Define.l Event, EventWindow, EventGadget, EventType, EventMenu
Define.l Length
Define.s File
Define *Buffer

;- Декларация
Declare WindowCreate()
Declare WindowResize()
Declare FileClose()
Declare FileDisplay()
Declare FileRead()

;- Реализация
Procedure WindowCreate()
    ; Создать окно.

    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)

        ; Установка минимального размера окна.
        WindowBounds(#WindowHex, 175, 175, #PB_Ignore, #PB_Ignore)

        ; Создать список проводника из корневого каталога вошедшего в систему пользователя.
        ExplorerListGadget(#GadgetFiles, 5, 5, 490, 175, GetHomeDirectory())

        ; Кнопки.
        ButtonGadget(#GadgetOpen, 5, 185, 80, 25, "Open")
        ButtonGadget(#GadgetClose, 100, 185, 80, 25, "Close")

        ; Гаджет значка списка.
        ListIconGadget(#GadgetHex, 5, 215, 490, 180, "Offset", 80, #PB_ListIcon_AlwaysShowSelection - #PB_ListIcon_GridLines - #PB_ListIcon_FullRowSelect)

        ; Заголовки столбцов.
        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()
    ; Изменить размеры Гаджетов, в связи с новым размером окна.

    Protected.l X, Y, W, H

    ; Список проводника.
    W = WindowWidth(#WindowHex) - 10
    H = (WindowHeight(#WindowHex) - 35) / 2
    ResizeGadget(#GadgetFiles, #PB_Ignore, #PB_Ignore, W, H)

    ; Кнопки
    Y = GadgetHeight(#GadgetFiles) + 10
    ResizeGadget(#GadgetOpen, #PB_Ignore, Y, #PB_Ignore, #PB_Ignore)
    ResizeGadget(#GadgetClose, #PB_Ignore, Y, #PB_Ignore, #PB_Ignore)

    ; Список в виде иконок
    Y = (WindowHeight(#WindowHex) / 2) + 23
    W = WindowWidth(#WindowHex) - 10
    H = WindowHeight(#WindowHex) - (Y + 5)
    ResizeGadget(#GadgetHex, #PB_Ignore, Y, W, H)

EndProcedure

Procedure FileClose()
    ; Очистить список и освободить буфер памяти.

    Shared Length, *Buffer

    ClearGadgetItems(#GadgetHex)
    FillMemory(*Buffer, Length)
    FreeMemory(*Buffer)

EndProcedure

Procedure FileDisplay()
    ; Показать буфер файла в представлении списка.

    Shared Length, *Buffer

    Protected *Byte
    Protected Peek
    Protected.l Rows, Cols, Offset
    Protected.s OffsetString, Row, String

    ; Очистить текущее содержание.
    ClearGadgetItems(#GadgetHex)

    ; Цикл для строк.
    For Rows = 0 To Length - 1 Step 8

        ; Очистить текстовое значение для каждой строки.
        String = ""

        ; Преобразовать значение смещения в строку фиксированной длины.
        Row = RSet(Hex(Rows, #PB_Long), 6, "0") + Chr(10)

        ; Цикл для столбцов.
        For Cols = 0 To 7

            ; Вычислить смещение для текущего столбца.
            Offset = Rows + Cols

            ; Сравнить смещение с длиной файла.
            If Offset < Length
                ; Смещение является меньше, чем длина файла.

                ; Получить байт из буфера.
                *Byte = *Buffer + Offset
                Peek = PeekB(*Byte)

                ; Преобразовать байт в текст.
                Row + RSet(Hex(Peek, #PB_Byte), 2, "0") + Chr(10)

                ; Добавить символ к текстовой версии.
                Select Peek

                    Case 0 To 31, 127
                        ; Непечатные символы.
                        String + Chr(129)

                    Default
                        ; Печатные символы.
                        String + Chr(Peek)

                EndSelect

            Else
                ; Смещение больше, чем длина файла.

                ; Добавить пустой столбец.
                Row + Chr(10)

            EndIf

        Next Cols

        ; Добавьте текстовую версию в конце шестнадцатеричных столбцов.
        Row + String

        ; Добавьте завершенную строку к представлению списка.
        AddGadgetItem(#GadgetHex, -1, Row)

    Next Rows

EndProcedure

Procedure FileRead()
    ; Считать файл в буфер памяти.

    Shared Length, File, *Buffer

    Protected.b ReadByte
    Protected.l FileNumber, ReadLong, Size

    ; Остановка, если файл пуст.
    If File = ""
        ProcedureReturn
    EndIf

    ; Остановка, если размер файла недопустим.
    Size = FileSize(File)
    If Size < 1
        ProcedureReturn
    EndIf

    ; Открыть файл.
    FileNumber = OpenFile(#PB_Any, File)
    Length = Lof(FileNumber)

    If File And Length

        ; Выделить буфер памяти для содержания файла.
        *Buffer = AllocateMemory(Length)

        ; Считать файл в буфер.
        Length = ReadData(FileNumber, *Buffer, Length)

    EndIf

    ; Закрыть файл.
    CloseFile(FileNumber)

EndProcedure

;- Главный код
WindowCreate()

;- Цикл событий
Repeat

    ; Получить параметры события.
    Event = WaitWindowEvent()
    EventGadget = EventGadget()
    EventType = EventType()
    EventWindow = EventWindow()

    ; События дескриптора.
    Select Event

        Case #PB_Event_Gadget
            If EventGadget = #GadgetFiles
                ; Ничего не делать.

            ElseIf EventGadget = #GadgetOpen
                File = GetGadgetText(#GadgetFiles) + GetGadgetItemText(#GadgetFiles, GetGadgetState(#GadgetFiles))
                If FileSize(File) > 0
                    FileRead()
                    FileDisplay()
                EndIf

            ElseIf EventGadget = #GadgetClose
                FileClose()

            ElseIf EventGadget = #GadgetHex
                ; Ничего не делать.

            EndIf

        Case #PB_Event_CloseWindow
            If EventWindow = #WindowHex
                CloseWindow(#WindowHex)
                Break
            EndIf

        Case #PB_Event_SizeWindow
            WindowResize()

    EndSelect

ForEver

Навигация Руководства

< Чтение и запись файлов - Обзор - Динамическая нумерация с помощью #PB_Any > ���Ү�5