To successfully enumerate the available flash cards, we will need to implement a couple of APIs using DllImport.
[DllImport("coredll.dll", SetLastError = false)]
public static extern bool FindClose(IntPtr hFindFile);
[DllImport("note_prj.dll", SetLastError = false)]
public static extern IntPtr FindFirstFlashCard(byte[] bFindFlashData);
[DllImport("note_prj.dll", SetLastError = false)]
public static extern bool FindNextFlashCard(IntPtr hFlashCard, byte[] bFindFlashData);
We also need to enum some of the FILE_ATTRIBUTE_xxx values available in Winbase.h.
public enum FILE_ATTRIBUTE
{
READONLY = 0x1
, HIDDEN = 0x2
, SYSTEM = 0x4
, DIRECTORY = 0x10
, ARCHIVE = 0x20
, INROM = 0x40
, NORMAL = 0x80
, TEMPORARY = 0x100
, SPARSE_FILE = 0x200
, REPARSE_POINT = 0x400
, COMPRESSED = 0x800
, ROMSTATICREF = 0x1000
, ROMMODULE = 0x2000
, ENCRYPTED = 0x4000
}
Next, we need to implement the WIN32_FIND_DATA structure. As you can see in our import of FindFirstFlashCard we don't actually pass an instance of the win32_find_data structure to the API, but instead we pass a byte buffer that are later converted to a win32_find_data structure. I've added a couple of properties to the structure to make working with file attributes a bit more .Net-ish. As you can see, the byte-to-structure-code is located in the constructur the same way as we did with the notification structures last week.
[StructLayout(LayoutKind.Sequential)]
public class WIN32_FIND_DATA
{
public uint FileAttributes;
private FILETIME ftCreationTime;
private FILETIME ftLastAccessTime;
private FILETIME ftLastWriteTime;
public DateTime dtCreationTime;
public DateTime dtLastAccessTime;
public DateTime dtLastWriteTime;
public uint nFileSizeHigh;
public uint nFileSizeLow;
public uint dwOID;
public string FileName;
public bool IsReadOnly;
public bool IsHidden;
public bool IsSystem;
public bool IsDirectory;
public bool IsArchive;
public bool IsInRom;
public bool IsNormal;
public bool IsTemporary;
public bool IsSparseFile;
public bool HasReparsePoint;
public bool IsCompressed;
public bool HasRomStaticRef;
public bool IsRomModule;
public bool IsEncrypted;
public WIN32_FIND_DATA()
{
}
public WIN32_FIND_DATA(byte[] Buf, uint Size)
{
int Index = 0;
int iEndOfString = 0;
System.Text.UnicodeEncoding enc = new UnicodeEncoding();
this.FileAttributes = BitConverter.ToUInt32(Buf, Index);
Index += 4;
this.ftCreationTime.dwLowDateTime = BitConverter.ToUInt32(Buf, Index);
Index += 4;
this.ftCreationTime.dwHighDateTime = BitConverter.ToUInt32(Buf, Index);
Index += 4;
this.ftLastAccessTime.dwLowDateTime = BitConverter.ToUInt32(Buf, Index);
Index += 4;
this.ftLastAccessTime.dwHighDateTime = BitConverter.ToUInt32(Buf, Index);
Index += 4;
this.ftLastWriteTime.dwLowDateTime = BitConverter.ToUInt32(Buf, Index);
Index += 4;
this.ftCreationTime.dwHighDateTime = BitConverter.ToUInt32(Buf, Index);
Index += 4;
this.nFileSizeHigh = BitConverter.ToUInt32(Buf, Index);
Index += 4;
this.nFileSizeLow = BitConverter.ToUInt32(Buf, Index);
Index += 4;
this.dwOID = BitConverter.ToUInt32(Buf, Index);
Index += 4;
iEndOfString = WinCE.findEndOfString(Buf, Index, (int)Size);
this.FileName = enc.GetString(Buf, Index, iEndOfString - Index - 2);
Index = iEndOfString;
this.IsReadOnly = Convert.ToBoolean(this.FileAttributes & (uint)FILE_ATTRIBUTE.READONLY);
this.IsHidden = Convert.ToBoolean(this.FileAttributes & (uint)FILE_ATTRIBUTE.HIDDEN);
this.IsSystem = Convert.ToBoolean(this.FileAttributes & (uint)FILE_ATTRIBUTE.SYSTEM);
this.IsDirectory = Convert.ToBoolean(this.FileAttributes & (uint)FILE_ATTRIBUTE.DIRECTORY);
this.IsArchive = Convert.ToBoolean(this.FileAttributes & (uint)FILE_ATTRIBUTE.ARCHIVE);
this.IsInRom = Convert.ToBoolean(this.FileAttributes & (uint)FILE_ATTRIBUTE.INROM);
this.IsNormal = Convert.ToBoolean(this.FileAttributes & (uint)FILE_ATTRIBUTE.NORMAL);
this.IsTemporary = Convert.ToBoolean(this.FileAttributes & (uint)FILE_ATTRIBUTE.TEMPORARY);
this.IsSparseFile = Convert.ToBoolean(this.FileAttributes & (uint)FILE_ATTRIBUTE.SPARSE_FILE);
this.HasReparsePoint = Convert.ToBoolean(this.FileAttributes & (uint)FILE_ATTRIBUTE.REPARSE_POINT);
this.IsCompressed = Convert.ToBoolean(this.FileAttributes & (uint)FILE_ATTRIBUTE.COMPRESSED);
this.HasRomStaticRef = Convert.ToBoolean(this.FileAttributes & (uint)FILE_ATTRIBUTE.ROMSTATICREF);
this.IsRomModule = Convert.ToBoolean(this.FileAttributes & (uint)FILE_ATTRIBUTE.ROMMODULE);
this.IsEncrypted = Convert.ToBoolean(this.FileAttributes & (uint)FILE_ATTRIBUTE.ENCRYPTED);
this.dtCreationTime = DateTime.FromFileTime(this.ftCreationTime.GetAsLong());
this.dtLastAccessTime = DateTime.FromFileTime(this.ftLastAccessTime.GetAsLong());
this.dtLastWriteTime = DateTime.FromFileTime(this.ftLastWriteTime.GetAsLong());
}
}
Now that's a lot of code!
The win32_find_data structure has a couple of instances of the FILETIME structure. This is a simple structure consisting of just two 32 bit unsigned integer values and a function that returns a 64 bit unsigned integer.
[StructLayout(LayoutKind.Sequential)]
public struct FILETIME
{
public uint dwLowDateTime;
public uint dwHighDateTime;
public long GetAsLong()
{
long lRet;
lRet = dwHighDateTime;
lRet = lRet << 32;
lRet = dwLowDateTime;
return lRet;
}
}
Returning the filetime structure as a 64 bit integer value makes it possible for us to directly convert it to a .Net DateTime structure using the static DateTime.GetFromFileTime(long lFileTime) function.
this.dtCreationTime = DateTime.FromFileTime(this.ftCreationTime.GetAsLong());
Next up is a simple function that enumerates all flash cards and outputs the path using System.Diagnostics.Trace.WriteLine(string sVal).
FileSystem.WIN32_FIND_DATA FindData;
Byte[] Buf = new byte[295]; // Struct is 40 bytes + MAX_PATH (255 bytes) = 295 bytes
IntPtr hFlashCard = WinCE.FileSystem.FileAppMgmt.FindFirstFlashCard(Buf);
if (hFlashCard != IntPtr.Zero)
{
FindData = new FileSystem.WIN32_FIND_DATA(Buf, 295);
System.Diagnostics.Trace.WriteLine("Filename:" + FindData.FileName);
Buf = new byte[295];
while (WinCE.FileSystem.FileAppMgmt.FindNextFlashCard(hFlashCard, Buf))
{
FindData = new FileSystem.WIN32_FIND_DATA(Buf, 295);
System.Diagnostics.Trace.WriteLine("Filename:" + FindData.FileName);
}
WinCE.FileSystem.FindClose(hFlashCard);
System.Diagnostics.Trace.WriteLine("Succeeded");
}
else
{
System.Diagnostics.Trace.WriteLine("Failed");
}
And that's about it.. Check back tomorrow when we look closer on a couple other file system related APIs.
Very nice. Can I use this code in my app?
SvaraRadera