Results 1 to 1 of 1

Thread: [VB6] List and view Alternate Data Streams using GetFileInformationByHandleEx

  1. #1

    Thread Starter
    PowerPoster
    Join Date
    Jul 2010
    Location
    NYC
    Posts
    7,667

    [VB6] List and view Alternate Data Streams using GetFileInformationByHandleEx


    So I was playing around with this last night and thought it would make a good demo, since while it seems like a single API would be straightforward it turns out this is fairly complex.

    Alternate Data Streams are a hidden part of regular files that you can't normally see. They can be any length, but only the first one is reported in Windows size counts, so a 1KB file could actually be hiding 1GB in an alternate stream. The most common use of alternate streams is web browsers marking files downloaded from the internet, which is how Windows knows to ask you to confirm if you really want to run something you downloaded-- this is shown in the picture above, and getting/setting that was the subject of [VB6] Code Snippet: Get/set/del file zone identifier (Run file from internet? source). There's already code samples about these streams, notably Karl Peterson's, but I still wanted to post this since it's highly simplified and uses a different API- haven't seen any others that do it with GetFileInformationByHandleEx.


    Code:
    Option Explicit
    
    
    Public Type FileStream
        StrmName As String
        StrmSize As Currency
        StrmAllocSize As Currency
    End Type
    
    Public Declare Function GetFileInformationByHandleEx Lib "kernel32" (ByVal hFile As Long, ByVal FileInformationClass As FILE_INFO_BY_HANDLE_CLASS, ByVal lpFileInformation As Long, ByVal dwBufferSize As Long) As Long
    Public Declare Function CreateFileW Lib "kernel32" (ByVal lpFileName As Long, ByVal dwDesiredAccess As Long, ByVal dwShareMode As Long, ByVal lpSecurityAttributes As Any, ByVal dwCreationDisposition As Long, ByVal dwFlagsAndAttributes As Long, ByVal hTemplateFile As Long) As Long
    Public Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
    Public Const GENERIC_READ    As Long = &H80000000
    Public Const FILE_SHARE_READ = &H1&
    Public Const OPEN_EXISTING = 3&
    Public Const FILE_FLAG_BACKUP_SEMANTICS = &H2000000
    Public Type LARGE_INTEGER
        lowpart As Long
        highpart As Long
    End Type
    Public Type FILE_STREAM_INFO
       NextEntryOffset As Long
       StreamNameLength As Long
       StreamSize As LARGE_INTEGER
       StreamAllocationSize As LARGE_INTEGER
       StreamName(0) As Integer
    End Type
    Public Enum FILE_INFO_BY_HANDLE_CLASS
        FileBasicInfo = 0
        FileStandardInfo = 1
        FileNameInfo = 2
        FileRenameInfo = 3
        FileDispositionInfo = 4
        FileAllocationInfo = 5
        FileEndOfFileInfo = 6
        FileStreamInfo = 7
        FileCompressionInfo = 8
        FileAttributeTagInfo = 9
        FileIdBothDirectoryInfo = 10 ' 0xA
        FileIdBothDirectoryRestartInfo = 11 ' 0xB
        FileIoPriorityHintInfo = 12 ' 0xC
        FileRemoteProtocolInfo = 13 ' 0xD
        FileFullDirectoryInfo = 14 ' 0xE
        FileFullDirectoryRestartInfo = 15 ' 0xF
        FileStorageInfo = 16 ' 0x10
        FileAlignmentInfo = 17 ' 0x11
        FileIdInfo = 18 ' 0x12
        FileIdExtdDirectoryInfo = 19 ' 0x13
        FileIdExtdDirectoryRestartInfo = 20 ' 0x14
        MaximumFileInfoByHandlesClass = 2
    End Enum
    Public Declare Sub ZeroMemory Lib "NTDLL.DLL" Alias "RtlZeroMemory" (dest As Any, ByVal numBytes As Long)
    Public Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
    Public Const INVALID_HANDLE_VALUE = -1&
    Public Function LargeIntToCurrency(li As LARGE_INTEGER) As Currency
        CopyMemory LargeIntToCurrency, li, LenB(li)
        LargeIntToCurrency = LargeIntToCurrency * 10000
    End Function
    Public Function GetFileStreams(sFile As String, tStreams() As FileStream) As Long
    ReDim tStreams(0)
    
    Dim hFile As Long
    hFile = CreateFileW(StrPtr(sFile), GENERIC_READ, FILE_SHARE_READ, ByVal 0&, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0)
    If hFile <> INVALID_HANDLE_VALUE Then
        Dim tFSI As FILE_STREAM_INFO
        Dim byBuf() As Byte
        Dim byName() As Byte
        Dim nErr2 As Long
        Dim dwNameOffset As Long
        Dim dwDirOffset As Long
        Dim nEntryNum As Long
        
        ReDim byBuf((LenB(tFSI) + CLng(260 * 2 - 3)) * CLng(&H10000))
        ReDim byName(0)
        
        If GetFileInformationByHandleEx(hFile, FileStreamInfo, VarPtr(byBuf(0)), UBound(byBuf) + 1) Then
    '    nErr2 = GetLastError()
    '    Debug.Print "lasterr=0x" & Hex$(nErr2)
        dwDirOffset = 0
        Do While 1
            ReDim Preserve tStreams(nEntryNum)
            ZeroMemory tFSI, LenB(tFSI)
            CopyMemory tFSI, ByVal VarPtr(byBuf(dwDirOffset)), LenB(tFSI)
            Erase byName
            
            dwNameOffset = dwDirOffset + &H18
            dwNameOffset = VarPtr(byBuf(dwNameOffset))
            ReDim byName(tFSI.StreamNameLength - 1)
            CopyMemory byName(0), ByVal dwNameOffset, tFSI.StreamNameLength
    
            tStreams(nEntryNum).StrmSize = LargeIntToCurrency(tFSI.StreamSize)
            tStreams(nEntryNum).StrmAllocSize = LargeIntToCurrency(tFSI.StreamAllocationSize)
            tStreams(nEntryNum).StrmName = CStr(byName)
            nEntryNum = nEntryNum + 1
            
            If tFSI.NextEntryOffset = 0 Then Exit Do
            dwDirOffset = dwDirOffset + tFSI.NextEntryOffset
        Loop
        GetFileStreams = nEntryNum
        End If
    clhn:
        CloseHandle hFile
    End If
    End Function
    Once you know the stream name, you can address it with normal file functions to open, save, and delete it. The sample project uses VB's Open:
    Code:
    Private Sub List1_Click()
    If List1.ListIndex <> -1 Then
        Text2.Text = LoadFile(Text1.Text & tStrm(List1.ListIndex).StrmName)
    End If
    End Sub
    
    
    Public Function LoadFile(ByVal FileName As String) As String
       Dim hFile As Long
       On Error GoTo Hell
       hFile = FreeFile
       Open FileName For Binary As #hFile
          LoadFile = Space$(LOF(hFile))
          Get #hFile, , LoadFile
       Close #hFile
       Exit Function
    Hell:
        Debug.Print "LoadFile::" & Err.Description
    End Function
    Attached Files Attached Files

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width