Announcement

Collapse

Forum Guidelines

This forum is for finished source code that is working properly. If you have questions about this or any other source code, please post it in one of the Discussion Forums, not here.
See more
See less

FileMap2.inc, WIN32API File Mapping

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • PBWin/PBCC FileMap2.inc, WIN32API File Mapping

    comments
    This replaces an earlier version I posted as a Class.

    File Mapping allows you to access a file as a block of memory.
    Instead of read/write to a file; you read/write to a block of memory.
    This gives you file access at memory access speed.
    Any changes made to the memory, reflect through to the file.

    Windows takes care of the file.
    This process bypasses a lot of overhead incurred using standard file operations.
    Windows handles everything on a very low level.

    You can use Dim At to write to an array in the file.

    Code:
    ' PB 5/9
    'FileMap2.inc
        '
        '       WIN32API File Mapping Module
        '       !!! fastest file access !!!
        '
        '   whole file mapped into memory using API File Mapping/Fiew functions
        '   file = read/write locked
        '
        '   - file access = memory access speed
        '   - read/write to system memory, instead of the file
        '   - modifications reflect through to file
        '
        '       Win32 Programmer's Reference:
        '
        '        "File mapping is the association of a file's contents with a portion of the virtual address space of
        '        a process."
        '        "Processes read from and write to the file view using pointers, just as they would with dynamically
        '        allocated memory."
        '
        '   mapped memory start = FMap_MemStart()
        '   mapped memory size = FMap_MemSize() - same size as file
        '
        '   use FMap_Resize() to change file size while open
        '       you need to reestablish any pointer addresses after FMap_Resize()
        '
        '   ReDim a() AT FMap_MemStart(): work directly with file-based array - see sample
        '
        'note: replaces previous version I did as a class
        '   'had problem couldn't find
        '   'implemented with PB file functions so that everything is ONE based
        '   '   instead of a mix of one/zero based file, arrays, ...etc
        '
        'public domain, use at your own risk
        '
    '
    #If Not %Def(%WINAPI)
        #Include Once "WIN32API.INC"
    #EndIf
    '
    $FMap_Err_BadFileName = "File Mapping: bad file name"
    $FMap_Err_FileExist = "File Mapping: file exist"
    $FMap_Err_FileNotFound = "File Mapping: file not found"
    $FMap_Err_ZeroFileSize = "File Mapping: zero file size"
    $FMap_Err_FileCreationFailed = "File Mapping: file creation failed"
    $FMap_Err_FileOpenFailed = "File Mapping: file open failed"
    $FMap_Err_FileNotOpen = "File Mapping: file not open"
    $FMap_Err_FileMappingFailed = "File Mapping: file mapping failed"
    $FMap_Err_FileMappingNotOpen = "File Mapping: file mapping not open"
    $FMap_Err_FileViewFailed = "File Mapping: file view failed"
    $FMap_Err_FileViewNotOpen = "File Mapping: file view not open"
    '
    %FMap_FileAttr_OpenStatus = 0
    %FMap_FileAttr_WinHandle = 2
    '
    Macro FMap_ExitFalse(test, procedure, msg)
        If test Then
        Else
            #Debug Print FuncName$ +": "+ msg
            t.isErr = %TRUE
            t.errMsg = msg
            Exit procedure
        End If
    End Macro
    Macro FMapExitTrue(test, procedure, msg)
        If test Then
            #Debug Print FuncName$ +": "+ msg
            t.isErr = %TRUE
            t.errMsg = msg
            Exit procedure
        End If
    End Macro
    Macro FMap_GoFalse(test, MARKER, msg)
        If test Then
        Else
            #Debug Print FuncName$ +": "+ msg
            t.isErr = %TRUE
            t.errMsg = msg
            GoTo MARKER
        End If
    End Macro
    Macro FMap_GoTrue(test, MARKER, msg)
        If test Then
            #Debug Print FuncName$ +": "+ msg
            t.isErr = %TRUE
            t.errMsg = msg
            GoTo MARKER
        End If
    End Macro
    '
    Macro FMap_hWinFile = FileAttr(t.hFile, %FMap_FileAttr_WinHandle)  'window's file handle
    '
    '
    '
    Type FMapT
        isErr As Long
        errMsg As Asciiz * 256
        hFile As Long
        hWinFile As Long
        hMap As Long
        hView As Long
    End Type
    '
    '
    '
    Function FMap_Create(t As FMapT, ByVal file As String, ByVal fileSize As Long) As Long
        'create new file - fileSize length
        'open file for use
        '   Note: can't create empty file
        'True/False success
        t.isErr = 0
        t.hFile = 0
        t.hWinFile = 0
        t.hMap = 0
        t.hView = 0
        FMapExitTrue(IsFile(file), Function, $FMap_Err_FileExist)
        FMapExitTrue(file = "", Function, $FMap_Err_BadFileName)
        FMapExitTrue(fileSize < 1, Function, $FMap_Err_ZeroFileSize)
        Try
            t.hFile = FreeFile
            Open file For Binary As t.hFile
            Seek t.hFile, fileSize + 1
            SetEof t.hFile
            t.hWinFile = FMap_hWinFile
            FMap_GoFalse(FMap_OpenMap(t), CLOSE_STUFF, t.errMsg)
            FMap_GoFalse(FMap_OpenView(t), CLOSE_STUFF, t.errMsg)
            '
            Function = %TRUE
            Exit Function
            '
            CLOSE_STUFF:
            If t.hView Then FMap_CloseView t
            If t.hMap Then FMap_CloseView t
            If FileAttr(t.hFile, %FMap_FileAttr_OpenStatus) Then Close t.hFile
            t.hFile = 0
            t.hWinFile = 0
            t.hMap = 0
            t.hView = 0
        Catch
            If FileAttr(t.hFile, %FMap_FileAttr_OpenStatus) Then Close t.hFile
            t.isErr = %TRUE
            t.errMsg = $FMap_Err_FileCreationFailed
            t.hFile = 0
            t.hWinFile = 0
        End Try
    End Function
    '
    Function FMap_Open(t As FMapT, ByVal file As String) As Long
        'open existing file - True/False success - can't be empty file
        Local pz As Asciiz Ptr
        '
        t.isErr = 0
        t.hFile = 0
        t.hMap = 0
        t.hView = 0
        FMap_ExitFalse(IsFile(file), Function, $FMap_Err_FileNotFound)
        Try
            t.hFile = FreeFile
            Open file For Binary As t.hFile
            If Lof(t.hFile) < 1 Then
                Close t.hFile
                t.hFile = 0
                t.isErr = %TRUE
                t.errMsg = $FMap_Err_ZeroFileSize
            Else
                t.hWinFile = FMap_hWinFile
                FMap_GoFalse(FMap_OpenMap(t), CLOSE_STUFF, t.errMsg)
                FMap_GoFalse(FMap_OpenView(t), CLOSE_STUFF, t.errMsg)
                '
                Function = %TRUE
                Exit Function
                '
                CLOSE_STUFF:
                If t.hView Then FMap_CloseView t
                If t.hMap Then FMap_CloseView t
                If FileAttr(t.hFile, %FMap_FileAttr_OpenStatus) Then Close t.hFile
                t.hFile = 0
                t.hWinFile = 0
                t.hMap = 0
                t.hView = 0
            End If
        Catch
            If FileAttr(t.hFile, %FMap_FileAttr_OpenStatus) Then Close t.hFile
            t.isErr = %TRUE
            t.errMsg = $FMap_Err_FileOpenFailed
            t.hFile = 0
            t.hWinFile = 0
        End Try
    End Function
    '
    Sub FMap_Close(t As FMapT)
        'close file
        t.isErr = 0
        FMap_ExitFalse(t.hFile, Sub, $FMap_Err_FileNotOpen)
        FMap_CloseView t
        FMap_CloseMap t
        Close t.hFile
        t.hFile = 0
        t.hMap = 0
        t.hView = 0
    End Sub
    '
    Function FMap_MemStart(t As FMapT) As Long
        'return memory address to beginning of File View
        '   you can read/alter memory from MemStart() to MemEnd()
        '   whatever changes are made to memory will reflect through to file
        FMap_ExitFalse(t.hFile, Function, $FMap_Err_FileNotOpen)
        FMap_ExitFalse(t.hMap, Function, $FMap_Err_FileMappingNotOpen)
        FMap_ExitFalse(t.hView, Function, $FMap_Err_FileViewNotOpen)
        Function = t.hView
    End Function
    '
    Function FMap_MemSize(t As FMapT) As Long
        'get size of File View
        '   you can read/alter memory at MemStart() for MemCount() -1 bytes
        FMap_ExitFalse(t.hFile, Function, $FMap_Err_FileNotOpen)
        FMap_ExitFalse(t.hMap, Function, $FMap_Err_FileMappingNotOpen)
        FMap_ExitFalse(t.hView, Function, $FMap_Err_FileViewNotOpen)
        Function = Lof(t.hFile)
    End Function
    '
    Sub FMap_Resize(t As FMapT, ByVal newFileSize As Long)
        'change size of file
        '   newFileSize can't be zero
        t.isErr = 0
        FMap_ExitFalse(t.hFile, Sub, $FMap_Err_FileNotOpen)
        FMapExitTrue(newFileSize < 1, Sub, $FMap_Err_ZeroFileSize)
        FMap_CloseView t : If t.isErr Then Exit Sub
        FMap_CloseMap t  : If t.isErr Then Exit Sub
        Seek t.hFile, newFileSize + 1
        SetEof t.hFile
        FMap_ExitFalse(FMap_OpenMap(t), Sub, t.errMsg)
        FMap_ExitFalse(FMap_OpenView(t), Sub, t.errMsg)
    End Sub
    '
    Function FMap_LOF(t As FMapT) As Long
        'get length of file
        t.isErr = 0
        FMap_ExitFalse(t.hFile, Function, $FMap_Err_FileNotOpen)
        Function = Lof(t.hFile)
    End Function
    '
    Function FMap_IsErr(t As FMapT) As Long
        'True/False if last operation caused an error
        Function = t.isErr
    End Function
    '
    Function FMap_ErrMsg(t As FMapT) As String
        'get error message
        If t.isErr Then Function = t.errMsg
    End Function
    '
    '   --------------------------------------
    '                internal use
    '   --------------------------------------
    '
    Function FMap_OpenMap(t As FMapT) As Long
        t.isErr = 0
        t.hView = 0
        FMap_ExitFalse(t.hWinFile, Function, $FMap_Err_FileNotOpen)
        t.hMap = CreateFileMapping(t.hWinFile, ByVal 0, %PAGE_READWRITE, 0, 0, ByVal 0)
        FMap_ExitFalse(t.hMap, Function, $FMap_Err_FileMappingFailed)
        Function = %TRUE
    End Function
    '
    Sub FMap_CloseMap(t As FMapT)
        t.isErr = 0
        t.hView = 0
        FMap_ExitFalse(t.hWinFile, Sub, $FMap_Err_FileNotOpen)
        FMap_ExitFalse(t.hMap, Sub, $FMap_Err_FileMappingNotOpen)
        CloseHandle(t.hMap)
        t.hMap = 0
    End Sub
    '
    Function FMap_OpenView(t As FMapT) As Long
        t.isErr = 0
        t.hView = 0
        FMap_ExitFalse(t.hWinFile, Function, $FMap_Err_FileNotOpen)
        FMap_ExitFalse(t.hMap, Function, $FMap_Err_FileMappingNotOpen)
        t.hView = MapViewOfFile(t.hMap, %FILE_MAP_ALL_ACCESS, 0, 0, 0)
        FMap_ExitFalse(t.hView, Function, $FMap_Err_FileViewFailed)
        Function = %TRUE
    End Function
    '
    Sub FMap_CloseView(t As FMapT)
        t.isErr = 0
        FMap_ExitFalse(t.hWinFile, Sub, $FMap_Err_FileNotOpen)
        FMap_ExitFalse(t.hView, Sub, $FMap_Err_FileViewNotOpen)
        UnmapViewOfFile(t.hView)
        t.hView = 0
    End Sub
    '
    Last edited by Stanley Durham; 16 Aug 2009, 09:26 AM.
    stanthemanstan~gmail
    Dead Theory Walking
    Range Trie Tree
    HLib ~ Free Data Container Lib ~ Arrays, Lists, Stacks, Queues, Deques, Trees, Hashes

  • #2
    test, sample app
    Code:
    #PBForms CREATED V1.51
    'pbwin 9
    $TestSource = "FileMapTest.bas"
    $TestTitle = "File Mapping Test"
    #Compile Exe "FileMapTest.exe"
    #Dim All
    #Optimize Speed
    #Include "..\FileMap2.inc"
    #PBForms BEGIN INCLUDES
    #If Not %Def(%WINAPI)
        #Include Once "WIN32API.INC"
    #EndIf
    #Include Once "PBForms.INC"
    #PBForms END INCLUDES
    #PBForms BEGIN CONSTANTS
    %Dlg1    =  101
    %BtnTest = 1002
    %Lbx1    = 1001
    #PBForms END CONSTANTS
    Declare CallBack Function ShowDlg1Proc()
    Declare Function ShowDlg1(ByVal hParent As Dword) As Long
    #PBForms DECLARATIONS
    Global lbx As LBxI
    Global tmr As TimerI
    Function PBMain()
        ShowDlg1 %HWND_Desktop
    End Function
    Sub BtnTest(ByVal hDlg As Long)
        Local i, j, hFile, hMem, arrCount1, arrCount2 As Long
        Local pb As Byte Ptr
        Local file As String : file = "FielMap.dat"
        Local t As FMapT
        Local s As String
        Local arr() As Long
        '
        lbx.Clear(2)
        '
        If IsFile(file) Then Kill file
        '
        FMap_Create(t, file, 26)
        If FMap_IsErr(t) Then
            ? FMap_ErrMsg(t) : Exit Sub
        End If
        '
        lbx.Add("map is open")
        lbx.Add("")
        lbx.Add("make changes to mapped memory using a BYTE pointer")
        '
        pb = FMap_MemStart(t)
        If FMap_IsErr(t) Then
            ? FMap_ErrMsg(t) : Exit Sub
        End If
        j = 96
        For i = 0 To 25
            Incr j
            @pb[i] = j
        Next i
        '
        lbx.Add("")
        lbx.Add("close file mapping")
        FMap_Close t
        '
        lbx.Add("")
        lbx.Add("open file using PB function, read map contents")
        hFile = FreeFile
        Open file For Binary As hFile Base = 0
        Get$ hFile, 26, s
        lbx.Add("map = '"+s+"'")
        Close hFile
        '
        lbx.Add("")
        lbx.Add("reopen file using File Mapping")
        lbx.Add("test Resize()")
        lbx.Add("   File Mapping is fixed size - can't resize")
        lbx.Add("       Resize() closes map mapping")
        lbx.Add("       changes size")
        lbx.Add("       turns back on to new size")
        FMap_Open(t, file)
        If FMap_IsErr(t) Then
            ? FMap_ErrMsg(t) : Exit Sub
        End If
        FMap_Resize t, 52
        lbx.Add("")
        lbx.Add("fill new area using BYTE pointer")
        pb = FMap_MemStart(t) + 26
        j = 96
        For i = 0 To 25
            Incr j
            @pb[i] = j
        Next i
        '
        lbx.Add("")
        lbx.Add("close file mapping")
        FMap_Close t
        '
        lbx.Add("")
        lbx.Add("open file using PB function, read map contents")
        hFile = FreeFile
        Open file For Binary As hFile Base = 0
        Get$ hFile, 54, s
        lbx.Add("map = '"+s+"'")
        Close hFile
        '
        lbx.Add("")
        lbx.Add("reopen file using File Mapping")
        lbx.Add("change all characters to UCase(), using Peek$()")
        FMap_Open(t, file)
        hMem = FMap_MemStart(t)
        s = Peek$(hMem, 54)
        s = UCase$(s)
        Poke$ hMem, s
        '
        lbx.Add("")
        lbx.Add("close file mapping")
        FMap_Close t
        '
        lbx.Add("")
        lbx.Add("open file using PB function, read map contents")
        hFile = FreeFile
        Open file For Binary As hFile Base = 0
        Get$ hFile, 54, s
        lbx.Add("map = '"+s+"'")
        Close hFile
        '
        arrCount1 = 10000
        lbx.Add("")
        lbx.Add("reopen file using File Mapping")
        lbx.Add("How about an array() using ReDim() AT?")
        FMap_Open(t, file)
        lbx.Add("resize map for 10,000 element Long array")
        lbx.Add("fill array")
        FMap_Resize t, arrCount1 * 4
        hMem = FMap_MemStart(t)
        ReDim arr(1 To arrCount1) At hMem
        tmr.Start()
        For i = 1 To arrCount1
            arr(i) = i
        Next i
        lbx.Add(tmr.Get())
        '
        lbx.Add("")
        lbx.Add("close and reopen map mapping")
        FMap_Close t
        FMap_Open(t, file)
        lbx.Add("")
        lbx.Add("get all elements - make sure array actually in map")
        hMem = FMap_MemStart(t)
        ReDim arr(1 To arrCount1) At hMem
        tmr.Start()
        For i = 1 To arrCount1
            If arr(i) <> i Then
                ? "missing at: " + Format$(i)
                Exit For
            End If
        Next i
        lbx.Add(tmr.Get())
        '
        arrCount2 = 20000
        lbx.Add("")
        lbx.Add("we can't change the size of the array using ReDim()")
        lbx.Add("   just Resize() the map")
        lbx.Add("   change array() to 20,000 elements")
        FMap_Resize t, arrCount2 * 4
        lbx.Add("   Note: we have to reestablish the beginning of the array after Resize()")
        hMem = FMap_MemStart(t)
        ReDim arr(1 To arrCount2) At hMem
        lbx.Add("fill new elements in array")
        For i = 10001 To arrCount2
            arr(i) = i
        Next i
        '
        lbx.Add("")
        lbx.Add("close and reopen map mapping")
        lbx.Add("make sure all 20,000 elements in array")
        FMap_Close t
        FMap_Open(t, file)
        hMem = FMap_MemStart(t)
        ReDim arr(1 To arrCount2) At hMem
        tmr.Start()
        For i = 1 To arrCount2
            If arr(i) <> i Then
                ? "missing at: " + Format$(i)
                Exit For
            End If
        Next i
        lbx.Add(tmr.Get())
        '
        FMap_Close t
        '
        lbx.Add("")
        lbx.Add("done...")
    End Sub
    CallBack Function ShowDlg1Proc()
        Select Case As Long CbMsg
            Case %WM_InitDialog
                 lbx = Class "LBxC"
                 lbx.INI(Cb.Hndl, %Lbx1)
                 lbx.SetHorizontal(1000)
                 tmr = Class "TimerC"
            Case %WM_NCActivate
                Static hWndSaveFocus As Dword
                If IsFalse CbWParam Then
                    hWndSaveFocus = GetFocus()
                ElseIf hWndSaveFocus Then
                    SetFocus(hWndSaveFocus)
                    hWndSaveFocus = 0
                End If
            Case %WM_Command
                Select Case As Long CbCtl
                    Case %BtnTest
                        If CbCtlMsg = %BN_Clicked Or CbCtlMsg = 1 Then
                            BtnTest(Cb.Hndl)
                        End If
                End Select
        End Select
    End Function
    Function ShowDlg1(ByVal hParent As Dword) As Long
        Local lRslt  As Long
    #PBForms BEGIN DIALOG %Dlg1->->
        Local hDlg   As Dword
        Local hFont1 As Dword
        Dialog New hParent, $TestTitle, 67, 61, 341, 241, %WS_Popup _
            Or %WS_Border Or %WS_DlgFrame Or %WS_Caption Or %WS_SysMenu Or _
            %WS_MinimizeBox Or %WS_ClipSiblings Or %WS_Visible Or %DS_ModalFrame _
            Or %DS_3DLook Or %DS_NoFailCreate Or %DS_SetFont, _
            %WS_Ex_ControlParent Or %WS_Ex_Left Or %WS_Ex_LtrReading Or _
            %WS_Ex_RightScrollbar, To hDlg
        Control Add ListBox, hDlg, %Lbx1, , 5, 5, 330, 210, %WS_Child Or _
            %WS_Visible Or %WS_HScroll Or %WS_VScroll Or %LBS_Notify Or _
            %LBS_NoIntegralHeight, %WS_Ex_ClientEdge Or %WS_Ex_Left Or _
            %WS_Ex_LtrReading Or %WS_Ex_RightScrollbar
        Control Add Button,  hDlg, %BtnTest, "Test", 275, 220, 60, 15
        hFont1 = PBFormsMakeFont("Courier New", 9, 400, %FALSE, %FALSE, %FALSE, _
            %ANSI_CHARSET)
        Control Send hDlg, %Lbx1, %WM_SETFONT, hFont1, 0
    #PBForms END DIALOG
        Dialog Show Modal hDlg, Call ShowDlg1Proc To lRslt
    #PBForms BEGIN CLEANUP %Dlg1
        DeleteObject hFont1
    #PBForms END CLEANUP
        Function = lRslt
    End Function
    Class LBxC
        Instance meHDlg As Long
        Instance meID As Long
        Interface LBxI
            Inherit IUnknown
            Method INI(ByVal hDlg As Long, ByVal Id As Long)
                meHDlg = hDlg
                meID = Id
            End Method
            Method SetHorizontal(ByVal Count As Long)
                Local hCntrl&
                Control Handle meHDlg, meID To hCntrl&
                SendMessage hCntrl&, %LB_SETHORIZONTALEXTENT, Count, 0
            End Method
            Method Clear(Opt doEventsCount As Long)
                ListBox Reset meHDlg, meID
                If VarPtr(doEventsCount) Then me.DoEventsCount(doEventsCount)
            End Method
            Method Add(ByVal s As String, Opt doEventsCount As Long) As String
                ListBox Add meHDlg, meID, s
                If VarPtr(doEventsCount) Then me.DoEventsCount(doEventsCount)
            End Method
        End Interface
        Class Method DoEventsCount(ByVal Count As Long)
            Local i As Long
            For i = 1 To Count
                Dialog DoEvents
            Next i
        End Method
    End Class
    Class TimerC
        Instance meTime As Double
        Interface TimerI
            Inherit IUnknown
            Method Start()
                meTime = Timer
            End Method
            Method Get() As String
                Method = "    Time: " + Format$(Timer - meTime, "###.###############")
            End Method
        End Interface
    End Class
    stanthemanstan~gmail
    Dead Theory Walking
    Range Trie Tree
    HLib ~ Free Data Container Lib ~ Arrays, Lists, Stacks, Queues, Deques, Trees, Hashes

    Comment

    Working...
    X