There
is precious little documented in the SDK concerning the protected file
system on Windows, and at the date of this posting there is nothing on the SfcGetFiles()
API.
Here, therefore, is my attempt at returning the listing of files returned
by this call. It seems to work, although the significance of some
UDT members are not documented and thus unused in this demo.
As this is a Unicode API, the results are pointers to byte strings and
thus require conversion per the GetPointerToByteStringW routine. |
Option Explicit
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Copyright ©1996-2011 VBnet/Randy Birch, All Rights Reserved.
' Some pages may also contain other copyrights by the author.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Distribution: You can freely use this code in your own
' applications, but you may not reproduce
' or publish this code on any web site,
' online service, or distribute as source
' on any media without express permission.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Private Const MAX_PATH As Long = 260
Private Const ERROR_SUCCESS As Long = 0
Private Type PROTECTED_FILES
Filename As Long
Filenumber As Long
End Type
Private Type PROTECTED_FILE_DATA
unknown As Long 'RpcHandle ???
pf As PROTECTED_FILES
End Type
Private Declare Sub CopyMemory Lib "kernel32" _
Alias "RtlMoveMemory" _
(pTo As Any, uFrom As Any, _
ByVal lSize As Long)
Private Declare Function lstrlenW Lib "kernel32" _
(ByVal lpString As Long) As Long
Private Declare Function SfcGetFiles Lib "sfcfiles.dll" _
(ptrFiles As Long, _
dwCount As Long) As Long
Private Declare Function ExpandEnvironmentStrings Lib "kernel32" _
Alias "ExpandEnvironmentStringsA" _
(ByVal lpSrc As String, _
ByVal lpDst As String, _
ByVal nSize As Long) As Long
Private Sub Form_Load()
Command1.Caption = "Get Protected Files"
Text1.Text = ""
Label1.Caption = "System Protected Files:"
End Sub
Private Sub Command1_Click()
Dim cnt As Long
Dim bufptr As Long
Dim dwCount As Long
Dim nStructSize As Long
Dim pfd As PROTECTED_FILE_DATA
'pass both bufptr and dwCount variables ByRef
If SfcGetFiles(bufptr, dwCount) = ERROR_SUCCESS Then
'nothing to do if either not valid
If (bufptr <> 0) And _
(dwCount > 0) Then
'the sizeof the PROTECTED_FILE_DATA UDT
nStructSize = LenB(pfd)
'this just speeds up filling the list
List1.Visible = False
'taking the memory address specified by bufptr
'and jumping every nStructSize bytes, retrieve
'each protected file into the pfd structure
For cnt = 0 To (dwCount - 1)
CopyMemory pfd, ByVal bufptr + (nStructSize * cnt), nStructSize
'the string returned is a wide byte string,
'so convert for display and add to list
List1.AddItem GetPointerToByteStringW(pfd.pf.Filename)
Next
List1.Visible = True
'reflect ListCount = dwCount.
'(w/ 1 added as ListCount is 0-based).
Label1.Caption = "System Protected Files: (" & List1.ListCount + 1 & ")"
End If 'bufptr
End If 'SfcGetFiles
End Sub
Private Sub List1_Click()
'expand the environment variables to
'valid system paths for selected item
With List1
If .ListIndex > -1 Then
Text1.Text = ExpandEnvironment(.List(.ListIndex))
End If
End With
End Sub
Private Function ExpandEnvironment(ByVal sEnvironPath As String) As String
'Parses an input string containing references
'to one or more environment variables and
'replaces them with their current values.
'
'Case is ignored. Each %VariableName% string is
'replaced with the variable's current value.
'The replacement rules are the same as those
'used by the command interpreter. If the name
'is not found, the %variableName% string is
'left intact and returned.
'
'NOTE: The environment variables that correspond
'to file system folders can be mapped to an
'equivalent CSIDL value and obtained with
'SHGetFolderLocation. CSIDLs are more reliable
'than variable names and should be used if at
'all possible.
Dim buff As String
Dim nSize As Long
buff = Space$(MAX_PATH)
nSize = Len(buff)
Call ExpandEnvironmentStrings(sEnvironPath, buff, nSize)
ExpandEnvironment = TrimNull(buff)
End Function
Private Function GetPointerToByteStringW(ByVal dwData As Long) As String
Dim tmp() As Byte
Dim tmplen As Long
If dwData <> 0 Then
tmplen = lstrlenW(dwData) * 2
If tmplen <> 0 Then
ReDim tmp(0 To (tmplen - 1)) As Byte
CopyMemory tmp(0), ByVal dwData, tmplen
GetPointerToByteStringW = tmp
End If
End If
End Function
Private Function TrimNull(startstr As String) As String
TrimNull = Left$(startstr, lstrlenW(StrPtr(startstr)))
End Function |