Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Chriss Miller on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Tracking files that have moved in VB6 2

Status
Not open for further replies.

Ed2020

Programmer
Nov 12, 2001
1,899
GB
Hi,

I have some code that generates a file listing for a specified directory or drive. My intention is to run this once a week for a number of weeks and maintain a list of a particular file type.

I need to be able to track additions and deletions however some of the files get moved during the course of a week and, as I am unable to guarantee a unique file name, it is difficult to differentiate between files that have a new location and genuinely new files.

What I need is a unique file reference that does not change over the lifetime of a file. I believe that within the MFT of an NTFS drive there is a unique file ID, but I can't find any way of retrieving this in VB6.

If anyone could offer any suggestions it would be much appreciated!

TIA,

Ed Metcalfe.

Please do not feed the trolls.....
 
Wel, you are kind of right. There is a FileID (which can chaneg) and, depending on configuration, and ObjectID that is unique to a volume (i.e. in theory, as long as you don't change drives the ObjectID stays the same)

But it is a pain trying to read the MFT and pick up that ObjectID using VB, and even more of a pain to write yourself a search tool that finds the renamed or moved file ... Except of course that Windows clearly does it - so maybe there is a way of leveraging Windows itself to do the work for you. And there is ...

Here's some example code that I put together that illustrates the idea:
Code:
[blue]Option Explicit

Private Enum ResolutionConstants
    rcNoDialog = 1 ' do not display a dialog if the link cannot be resolved; high-order word then defines the timeout
    rcUpdate = 4 ' if link has changed update its path and list of identifiers
    rcNoUpdate = 8 ' Do not update link info
    rcNoHeuristics = 16 ' Do not use folder search heuristics
    rcNoDLT = 32 ' Do not use distributed link tracking (this is the bit that uses MFTs $ObjectID to locate the file)
    rcDisableDLT = 64 ' further reduces the ability to locate the file
    rcMSI = 128 ' Invoke the Microsoft Windows Installer to install the file if it cannot be found ...
End Enum

' Requires references to:
' Microsoft shell controls and automation - to perform the magic
' Windows Script Host Object Model - to create the initial shortcut
' Microsoft Scripting Runtime - for FileSystemObject
Private Sub Example_Click()
    With New FileSystemObject
        .CreateTextFile "c:\test.txt", True
    End With
    
    CreateMyLink
    MoveFile
    MsgBox FindNewLocation
End Sub

Private Sub CreateMyLink()
    Dim wsh As WshShell
    Dim mylink As WshShortcut
    
    Dim testlink As ShellLinkObject
    
    Set wsh = New WshShell
    Set mylink = wsh.CreateShortcut("c:\test.lnk")
    
    mylink.TargetPath = "c:\test.txt"
    'Set testlink = mylink
    mylink.Save
End Sub

Private Sub MoveFile()
    With New FileSystemObject
        .MoveFile "c:\test.txt", "c:\temp\wombat.txt" 'Let's moving AND renaming for this example. Can we find later ...
    End With
End Sub

Private Function FindNewLocation() As String
    Dim mylink As ShellLinkObject
    Dim myShell As Shell32.Shell
    
    Set myShell = New Shell32.Shell
    Set mylink = myShell.NameSpace("c:\").Items.Item("test.lnk").GetLink
    ' This is the magic bit ...
    mylink.Resolve rcNoHeuristics ' don't do the slower folder search (should never have to with this example)
    FindNewLocation = mylink.Path
End Function[/blue]
 
Hi strongm,

Thanks for your reply, and the code. That will be very useful.

I've made some progress on reading the file and volume IDs since I posted my question. I was in the middle of testing this when I noticed your response:

Code:
Private Const OPEN_EXISTING = 3
Private Type FILETIME
    dwLowDateTime As Long
    dwHighDateTime As Long
End Type
Public Type BY_HANDLE_FILE_INFORMATION
    dwFileAttributes As Long
    ftCreationTime As FILETIME
    ftLastAccessTime As FILETIME
    ftLastWriteTime As FILETIME
    dwVolumeSerialNumber As Long
    nFileSizeHigh As Long
    nFileSizeLow As Long
    nNumberOfLinks As Long
    nFileIndexHigh As Long
    nFileIndexLow As Long
End Type
Private Declare Function GetFileInformationByHandle Lib "kernel32" (ByVal hFile As Long, lpFileInformation As BY_HANDLE_FILE_INFORMATION) As Long
Private Declare Function CreateFile Lib "kernel32" Alias "CreateFileA" (ByVal lpFileName As String, ByVal dwDesiredAccess As Long, ByVal dwShareMode As Long, lpSecurityAttributes As Any, 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

Public Sub GetFileIDsX(ByVal strFilePath As String)
    Dim hFile As Long
    Dim FileInfo As BY_HANDLE_FILE_INFORMATION

    hFile = CreateFile(strFilePath, 0, 0, ByVal 0&, OPEN_EXISTING, 0, ByVal 0&)
    GetFileInformationByHandle hFile, FileInfo
    CloseHandle hFile
    
    Debug.Print FileInfo.dwVolumeSerialNumber & FileInfo.nFileIndexHigh & FileInfo.nFileIndexLow
End Sub

Is the combination of FileInfo.nFileIndexHigh & FileInfo.nFileIndexLow what you were refering to when you said the File ID can change? Under what circumstances can these values change for a given file?

Many thanks,

Ed.

Please do not feed the trolls.....
 
No, FileIndex is unique for the lifetime of the file on a specific volume.
 
Hi Ed,

Something to note:

If the file is copied to the new location, rather than moved, and the original is then deleted, you won't be able to track it this way.

However, if you buld up a list of 'lost' and 'found' files for which the IDs differ, then compare their sizes, a binary comparison on those 'lost' and 'found' files with the same sizes would allow you to match any that were 'moved' this way too. You can extend this to cross-volume movements also. Whether it's worth the effort, only you can decide.

Cheers

[MS MVP - Word]
 
Thanks strongm. Much appreciated.

Ed Metcalfe.

Please do not feed the trolls.....
 
(note that the FileID in the MFT that I mentioned is really just the index position in a B-tree that NTFS maintains for each directory; this B-tree may get sorted, so the FileID can change. Probably shouldn't really be called a FileID, I'm referring to poor documentation; the FileIndex that you obtain via GetFileInformationByHandle is, as far as I can tell, what I describe as MFT's ObjectID)
 
Thanks macropod. I had thought of the copy/paste/delete issue however I hadn't got as far as finding a solution.

One problem is that some of the files in question are Business Objects report files, which may be saved containing data. If they have been refreshed between file listings the binary & file size comparisons won't work (although they will for certain other files I am looking at, so it will still be useful). I may well be able to compare the SQL properties of each file to identify moved files as well.

Have a star for your input. :)

Ed Metcalfe.

Please do not feed the trolls.....
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top