2

I am using a library that recursively scans really fast the files and directories of a folder. The output is a List<WIN32_FIND_DATAW> . Click here to see the contents of the stuct.

I managed to convert FILETIME to DateTime with the following extension method:

public static DateTime convertToDateTime(this System.Runtime.InteropServices.ComTypes.FILETIME time)
{
    ulong high = (ulong)time.dwHighDateTime;
    int low = time.dwLowDateTime;
    uint uLow = (uint)low;
    high = high << 32;
    return DateTime.FromFileTime((long)(high | (ulong)uLow));
}

and I get the file size as:

  (UInt64)((nFileSizeHigh * (2 ^ 32)) + nFileSizeLow);

I find those methods online don't recall where.

Anyways the library contains a method that requires a list of WIN32_FIND_DATA. I want to call that method but I don't know how to create a WIN32_FIND_DATA object

Here is a random WIN32_FIND_DATA object created when I iterated through my C:\ Drive

enter image description here

How could I construct the same object? I don't know how to get the cAlternateName although I don't think I need that. I don't know how to go back and convert a DateTime to FILETIME. Lastly I don't know how to convert a file size into nFileSizeHigh and nFileSizeLow.


the library used this methods in order to constuct the WIN32_FIND_DATAW objects:

        [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
        public static extern IntPtr FindFirstFileW(string lpFileName, out WIN32_FIND_DATAW lpFindFileData);

        [DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
        public static extern bool FindNextFile(IntPtr hFindFile, out WIN32_FIND_DATAW lpFindFileData);

        [DllImport("kernel32.dll")]
        public static extern bool FindClose(IntPtr hFindFile); 

Maybe there exists a public static extern bool FindFile(IntPtr hFindFile, out WIN32_FIND_DATAW lpFindFileData); method. so that I can construct the WIN32_FIND_DATAW objects that I need.


Edit

In short I want to construct a WIN32_FIND_DATAW object by having the full path of a file

Tono Nam
  • 34,064
  • 78
  • 298
  • 470
  • Just curious why you're calling the API directly when you could be using the methods in the `System.IO.Directory` class like `EnumerateDirectories`, `EnumerateFiles`, or `GetDirectories` and `GetFiles`. – Jim Mischel Apr 19 '12 at 20:14
  • Cause if you want to iterate recursevly through a directory that contains a lot of files the kernel methos are much faster. – Tono Nam Apr 19 '12 at 21:23
  • You're certain of that? Please provide references. – Jim Mischel Apr 19 '12 at 21:27
  • 1
    http://stackoverflow.com/questions/724148/is-there-a-faster-way-to-scan-through-a-directory-recursively-in-net/724184#724184 – Tono Nam Apr 19 '12 at 22:25
  • Interesting. I guess it's because you end up having to get the file info again for every file/directory. But on the plus side, doesn't that answer your question about how to create a `WIN32_FIND_DATAW` structure? – Jim Mischel Apr 19 '12 at 22:38
  • Yeah but if i want to get the stuct of file x for example i would have to go to the parent use the find firs and next file methods until i got to x. Also if I want to get the struct of the root I would not be able to. – Tono Nam Apr 20 '12 at 00:09
  • If you just want to get information for a single file or directory, use `FileInfo info = new FileInfo(filename);`. That has all the information that's in a `WIN32_FIND_DATA`. If you really need a `WIN32_FIND_DATA`, you can create one from the `FileInfo` information. – Jim Mischel Apr 20 '12 at 00:31
  • 1
    Or, come to think of it, you can just call `FindFirst` with the full path name of the file that you want. That is `IntPtr findHandle = FindFirstFile(@"c:\blah\blah\foo.txt", ref data);`. That should give you the `WIN32_FIND_DATA` for that one file. – Jim Mischel Apr 20 '12 at 00:34
  • That works great when pointing it to a file! thanks a lot. I need it to work with directories as well... Thanks for the help that last comment was helpful – Tono Nam Apr 20 '12 at 17:25
  • If you use that method remember to use the FindClose(Some_IntPtr); method. `[DllImport("kernel32.dll")] public static extern bool FindClose(IntPtr hFindFile);` .... then use it as: `WIN32_FIND_DATAW data = new WIN32_FIND_DATAW(); var pointer = FindFirstFileW(@"A:\SomeFile.txt", out data); FindClose(pointer);` – Tono Nam Apr 20 '12 at 17:30
  • Jim that method also works with directories. Is just that I was trying to use it with the top root `C:\` directory. If I select the folder `C:\Program Files` for example it works!! I will use Romeo's approach if I happen to need it with a root. – Tono Nam Apr 20 '12 at 17:50

1 Answers1

1

Here is the declaration of necessary structures.

public struct FILETIME
{
     public UInt32 dwLowDateTime;
     public UInt32 dwHighDateTime;
}

public unsafe struct WIN32_FIND_DATAW
{
    public UInt32 dwFileAttributes;
    public FILETIME ftCreationTime;
    public FILETIME ftLastAccessTime;
    public FILETIME ftLastWriteTime;
    public UInt32 nFileSizeHigh;
    public UInt32 nFileSizeLow;
    public UInt32 dwReserved0;
    public UInt32 dwReserved1;
    public fixed Char cFileName[256];
    public fixed Char cAlternateFileName[14];
}

You can construct and initialize such object as usual structure in C#.

Update: The 64-bit integer stored in FILETIME structure represents the number of 100-nanosecond intervals since January 1, 1601 (UTC). In .NET DateTime.Ticks represents the number of 100-nanosecond intervals that have elapsed since 12:00:00 midnight, January 1, 0001. So, to convert DateTime to FILETIME you just need to subtract 1600 years from DateTime and write number of ticks as pair of unsigned 32-bit integers. Or you can just call DateTime.ToFileTimeUtc():

FILETIME fileTime = new FILETIME();
Int64 ticks = DateTime.Now.ToFileTimeUtc();
fileTime.dwLowDateTime = (UInt32)ticks;
fileTime.dwHighDateTime = (UInt32)(ticks >> 32);
vharavy
  • 4,881
  • 23
  • 30