unknown
8/2/2012 7:45:00 PM
With the help of "Junction" from sysinternals, I found some symbolic links
in my XP system under one of the folders in C:\Windows. Here is the sample
again, but this time it's tested:
Option Explicit
Private Const MAX_NAME_LENGTH = 1024
Private Const INVALID_HANDLE_VALUE = -1
Private Const CREATE_NEW = 1
Private Const CREATE_ALWAYS = 2
Private Const OPEN_EXISTING = 3
Private Const OPEN_ALWAYS = 4
Private Const TRUNCATE_EXISTING = 5
Private Const GENERIC_WRITE = &H40000000
Private Const GENERIC_READ = &H80000000
Private Const FILE_SHARE_READ = &H1
Private Const FILE_SHARE_WRITE = &H2
Private Const FILE_ATTRIBUTE_READONLY = &H1
Private Const FILE_ATTRIBUTE_HIDDEN = &H2
Private Const FILE_ATTRIBUTE_SYSTEM = &H4
Private Const FILE_ATTRIBUTE_DIRECTORY = &H10
Private Const FILE_ATTRIBUTE_ARCHIVE = &H20
Private Const FILE_ATTRIBUTE_NORMAL = &H80
Private Const FILE_ATTRIBUTE_TEMPORARY = &H100
Private Const FILE_ATTRIBUTE_SPARSE_FILE = &H200
Private Const FILE_ATTRIBUTE_REPARSE_POINT = &H400
Private Const FILE_ATTRIBUTE_COMPRESSED = &H800
Private Const FILE_ATTRIBUTE_OFFLINE = &H1000
Private Const FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = &H2000
Private Const FILE_ATTRIBUTE_ENCRYPTED = &H4000
Private Const FILE_FLAG_WRITE_THROUGH = &H80000000
Private Const FILE_FLAG_OVERLAPPED = &H40000000
Private Const FILE_FLAG_NO_BUFFERING = &H20000000
Private Const FILE_FLAG_RANDOM_ACCESS = &H10000000
Private Const FILE_FLAG_SEQUENTIAL_SCAN = &H8000000
Private Const FILE_FLAG_DELETE_ON_CLOSE = &H4000000
Private Const FILE_FLAG_BACKUP_SEMANTICS = &H2000000
Private Const FILE_FLAG_POSIX_SEMANTICS = &H1000000
Private Const FILE_FLAG_OPEN_REPARSE_POINT = &H200000
Private Declare Function DeviceIoControl Lib "kernel32" ( _
ByVal hDevice As Long, ByVal dwIoControlCode As Long, lpInBuffer As Any,
_
ByVal nInBufferSize As Long, lpOutBuffer As Any, _
ByVal nOutBufferSize As Long, lpBytesReturned As Long, _
ByVal lpOverlapped As Long) As Long
Private Declare Function CreateFileW Lib "kernel32" ( _
ByVal lpFileName As Long, ByVal dwDesiredAccess As Long, _
ByVal dwShareMode As Long, ByVal lpSecurityAttributes As Long, _
ByVal dwCreationDisposition As Long, ByVal dwFlagsAndAttributes As Long,
_
ByVal hTemplateFile As Long) As Long
Private Declare Function CloseHandle Lib "kernel32" ( _
ByVal hObject As Long) As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" ( _
Destination As Any, Source As Any, ByVal Length As Long)
Private Declare Sub OutputDebugString Lib "kernel32" Alias _
"OutputDebugStringA" (ByVal lpOutputString As String)
Private Const FSCTL_GET_REPARSE_POINT As Long = &H900A8
Private Const IO_REPARSE_TAG_CSV = &H80000009
Private Const IO_REPARSE_TAG_DEDUP = &H80000013
Private Const IO_REPARSE_TAG_DFS = &H8000000A
Private Const IO_REPARSE_TAG_DFSR = &H80000012
Private Const IO_REPARSE_TAG_HSM = &HC0000004
Private Const IO_REPARSE_TAG_HSM2 = &H80000006
Private Const IO_REPARSE_TAG_MOUNT_POINT = &HA0000003
Private Const IO_REPARSE_TAG_NFS = &H80000014
Private Const IO_REPARSE_TAG_SIS = &H80000007
Private Const IO_REPARSE_TAG_SYMLINK = &HA000000C
Private Const IO_REPARSE_TAG_WIM = &H80000008
Private Type REPARSE_DATA_BUFFER
ReparseTag As Long
ReparseDataLength As Integer
Reserved As Integer
SubstituteNameOffset As Integer
SubstituteNameLength As Integer
PrintNameOffset As Integer
PrintNameLength As Integer
End Type
Private Type REPARSE_DATA_BUFFER_SYMPOLIC_LINK
ReparseTag As Long
ReparseDataLength As Integer
Reserved As Integer
SubstituteNameOffset As Integer
SubstituteNameLength As Integer
PrintNameOffset As Integer
PrintNameLength As Integer
Flags As Long
End Type
Private Sub Form_Load()
DebugPrint App.Title & " started on " & Now
DebugPrint GetReparsePoint( _
"c:\windows\assembly\GAC_32\System.EnterpriseServices\2.0.0.0__b03f5f7f11d50a3a")
End Sub
Private Function GetReparsePoint(ByRef sFolderName As String) As String
Dim hFile As Long
Dim ret As Long
Dim lpOutBuffer() As Byte
Dim lpOutBufferSize As Long
Dim lpBytesReturned As Long
Dim ReparseDataBuffer1 As REPARSE_DATA_BUFFER
Dim sSubstituteName As String
Dim sPrintName As String
hFile = CreateFileW(ByVal StrPtr(sFolderName), GENERIC_READ, _
FILE_SHARE_READ Or FILE_SHARE_WRITE, ByVal 0&, OPEN_EXISTING, _
FILE_FLAG_BACKUP_SEMANTICS Or FILE_FLAG_OPEN_REPARSE_POINT, ByVal
0&)
If hFile = INVALID_HANDLE_VALUE Then
DebugPrint "CreateFileW failed, LastDllError = " & _
Err.LastDllError
Exit Function
End If
' Call DeviceIoControl with small buffer to get the length
ret = DeviceIoControl(hFile, FSCTL_GET_REPARSE_POINT, ByVal 0&, 0, _
ReparseDataBuffer1, Len(ReparseDataBuffer1), lpBytesReturned, _
ByVal 0&)
If ret = 0 Then
DebugPrint "DeviceIoControl call 1 failed, lpBytesReturned = " & _
lpBytesReturned & ", LastDllError = " & Err.LastDllError
' Calculate the buffer size
lpOutBufferSize = Len( _
ReparseDataBuffer1) + ReparseDataBuffer1.SubstituteNameLength +
_
ReparseDataBuffer1.PrintNameLength + MAX_NAME_LENGTH * 2
If ReparseDataBuffer1.ReparseTag = IO_REPARSE_TAG_SYMLINK Then
lpOutBufferSize = lpOutBufferSize + 4 ' 4 = size of Flags member
End If
On Error Resume Next
ReDim lpOutBuffer(0 To lpOutBufferSize - 1)
If Err.Number <> 0 Then
DebugPrint "ReDim failed, Error " & Err.Number & ": " & _
Err.Description
GoTo Cleanup
End If
On Error GoTo 0
DebugPrint "lpOutBufferSize = " & lpOutBufferSize
' Call DeviceIoControl again with a large buffer
ret = DeviceIoControl(hFile, FSCTL_GET_REPARSE_POINT, ByVal 0&, 0, _
lpOutBuffer(0), lpOutBufferSize, lpBytesReturned, ByVal 0&)
If ret = 0 Then
DebugPrint "DeviceIoControl call 2 failed, LastDllError = " & _
Err.LastDllError
GoTo Cleanup
Else
' DeviceIoControl succeeded
CopyMemory ReparseDataBuffer1, lpOutBuffer(0), _
Len(ReparseDataBuffer1)
sSubstituteName = String( _
ReparseDataBuffer1.SubstituteNameLength, 0)
sPrintName = String(ReparseDataBuffer1.PrintNameLength, 0)
If ReparseDataBuffer1.ReparseTag = IO_REPARSE_TAG_SYMLINK Then
CopyMemory ByVal StrPtr(sSubstituteName), _
lpOutBuffer(Len( _
ReparseDataBuffer1) + 4 + _
ReparseDataBuffer1.SubstituteNameOffset), _
ReparseDataBuffer1.SubstituteNameLength
CopyMemory ByVal StrPtr(sPrintName), _
lpOutBuffer(Len( _
ReparseDataBuffer1) + 4 + _
ReparseDataBuffer1.PrintNameOffset), _
ReparseDataBuffer1.PrintNameLength
Else
CopyMemory ByVal StrPtr(sSubstituteName), _
lpOutBuffer(Len( _
ReparseDataBuffer1) + _
ReparseDataBuffer1.SubstituteNameOffset), _
ReparseDataBuffer1.SubstituteNameLength
CopyMemory ByVal StrPtr(sPrintName), _
lpOutBuffer(Len( _
ReparseDataBuffer1) + ReparseDataBuffer1.PrintNameOffset
_
), ReparseDataBuffer1.PrintNameLength
End If
DebugPrint "DeviceIoControl succeeded."
DebugPrint "sSubstituteName = '" & sSubstituteName & "'"
DebugPrint "sPrintName = '" & sPrintName & "'"
GetReparsePoint = sSubstituteName
End If
End If
Cleanup:
CloseHandle hFile
End Function
Private Sub DebugPrint(ByRef s As String)
Debug.Print s
OutputDebugString s
End Sub