Search code examples
c#.netfileuniqueidentifier

Unique File Identifier


Possible Duplicate:
Unique file identifier in windows

I need to retrieve a unique identifier for certain files on the computer, and have only came across the Win32 GetFileInformationByHandle function. How can I accomplish this with the. NET framework?

Update: I need a persistent id that will not change if the file is moved, updated, renamed, etc.

Update2: How can the same be accomplished with folders?


Solution

  • Here's some code from Ashley Henderson I copied from this answer. It implies two approaches which both return the same unique identifier.

    public class WinAPI
        {
            [DllImport("ntdll.dll", SetLastError = true)]
            public static extern IntPtr NtQueryInformationFile(IntPtr fileHandle, ref IO_STATUS_BLOCK IoStatusBlock, IntPtr pInfoBlock, uint length, FILE_INFORMATION_CLASS fileInformation);
    
            public struct IO_STATUS_BLOCK
            {
                uint status;
                ulong information;
            }
            public struct _FILE_INTERNAL_INFORMATION {
              public ulong  IndexNumber;
            } 
    
            // Abbreviated, there are more values than shown
            public enum FILE_INFORMATION_CLASS
            {
                FileDirectoryInformation = 1,     // 1
                FileFullDirectoryInformation,     // 2
                FileBothDirectoryInformation,     // 3
                FileBasicInformation,         // 4
                FileStandardInformation,      // 5
                FileInternalInformation      // 6
            }
    
            [DllImport("kernel32.dll", SetLastError = true)]
            public static extern bool GetFileInformationByHandle(IntPtr hFile,out BY_HANDLE_FILE_INFORMATION lpFileInformation);
    
            public struct BY_HANDLE_FILE_INFORMATION
            {
                public uint FileAttributes;
                public FILETIME CreationTime;
                public FILETIME LastAccessTime;
                public FILETIME LastWriteTime;
                public uint VolumeSerialNumber;
                public uint FileSizeHigh;
                public uint FileSizeLow;
                public uint NumberOfLinks;
                public uint FileIndexHigh;
                public uint FileIndexLow;
            }
      }
    
      public class Test
      {
           public ulong ApproachA()
           {
                    WinAPI.IO_STATUS_BLOCK iostatus=new WinAPI.IO_STATUS_BLOCK();
    
                    WinAPI._FILE_INTERNAL_INFORMATION objectIDInfo = new WinAPI._FILE_INTERNAL_INFORMATION();
    
                    int structSize = Marshal.SizeOf(objectIDInfo);
    
                    FileInfo fi=new FileInfo(@"C:\Temp\testfile.txt");
                    FileStream fs=fi.Open(FileMode.Open,FileAccess.Read,FileShare.ReadWrite);
    
                    IntPtr res=WinAPI.NtQueryInformationFile(fs.Handle, ref iostatus, memPtr, (uint)structSize, WinAPI.FILE_INFORMATION_CLASS.FileInternalInformation);
    
                    objectIDInfo = (WinAPI._FILE_INTERNAL_INFORMATION)Marshal.PtrToStructure(memPtr, typeof(WinAPI._FILE_INTERNAL_INFORMATION));
    
                    fs.Close();
    
                    Marshal.FreeHGlobal(memPtr);   
    
                    return objectIDInfo.IndexNumber;
    
           }
    
           public ulong ApproachB()
           {
                   WinAPI.BY_HANDLE_FILE_INFORMATION objectFileInfo=new WinAPI.BY_HANDLE_FILE_INFORMATION();
    
                    FileInfo fi=new FileInfo(@"C:\Temp\testfile.txt");
                    FileStream fs=fi.Open(FileMode.Open,FileAccess.Read,FileShare.ReadWrite);
    
                    WinAPI.GetFileInformationByHandle(fs.Handle, out objectFileInfo);
    
                    fs.Close();
    
                    ulong fileIndex = ((ulong)objectFileInfo.FileIndexHigh << 32) + (ulong)objectFileInfo.FileIndexLow;
    
                    return fileIndex;   
           }
      }