Skip to content

Instantly share code, notes, and snippets.

@soeminnminn
Created May 9, 2017 15:57
Show Gist options
  • Save soeminnminn/aec9de809ed39c4f380926940da5d769 to your computer and use it in GitHub Desktop.
Save soeminnminn/aec9de809ed39c4f380926940da5d769 to your computer and use it in GitHub Desktop.
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices;
using System.Security.Permissions;
namespace S16.IO
{
#region FilesList Class
public class FilesList : IEnumerable<PathInfo>
{
#region API Methods
[DllImport("Kernel32.dll", CharSet = CharSet.Auto)]
private static extern SafeFileHandle FindFirstFile(String fileName, [In, Out] WIN32_FIND_DATA findFileData);
[DllImport("kernel32", CharSet = CharSet.Auto)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool FindNextFile(SafeFileHandle hFindFile, [In, Out] WIN32_FIND_DATA lpFindFileData);
[DllImport("kernel32", CharSet = CharSet.Auto)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool FindClose(IntPtr hFindFile);
#endregion
#region Variables
private string mBasePath = null;
private string mMask = null;
private bool mWithSubFolder = false;
#endregion
#region Constructor
public FilesList(string basePath, string mask, bool bWithSubFolder)
{
if (string.IsNullOrEmpty(basePath))
{
throw new ArgumentNullException("basePath");
}
this.mBasePath = basePath;
this.mMask = string.IsNullOrEmpty(mask) ? "*" : mask;
this.mWithSubFolder = bWithSubFolder;
}
#endregion
#region GetFliesList Methods
public static string[] GetFliesList(string path)
{
return GetFliesList(path, "*.*", false, false);
}
public static string[] GetFliesList(string path, string mask)
{
return GetFliesList(path, mask, false, false);
}
public static string[] GetFliesList(string path, string mask, bool bWithSubFolder)
{
return GetFliesList(path, mask, bWithSubFolder, false);
}
public static string[] GetFliesList(string path, string mask, bool bWithSubFolder, bool bWithFolderName)
{
string basePath = path.Trim();
List<string> list = new List<string>();
GetFilesList(path, mask, bWithSubFolder, bWithFolderName, ref list);
return list.ToArray();
}
#endregion
#region GetFliesList Internal Methods
internal static void GetFilesList(string basePath, string mask, bool bWithSubFolder, bool bWithFolderName, ref List<string> list)
{
// check security - ensure that caller has rights to read this directory
new FileIOPermission(FileIOPermissionAccess.PathDiscovery, Path.Combine(basePath, ".")).Demand();
// now that security is checked, go read the directory
WIN32_FIND_DATA findData = new WIN32_FIND_DATA();
SafeFileHandle handle = FindFirstFile(Path.Combine(basePath, mask), findData);
if (!handle.IsInvalid)
{
do
{
// don't match . or ..
if (findData.fileName.Equals(@".") || findData.fileName.Equals(@".."))
continue;
if ((findData.fileAttributes & (int)FileAttributes.Directory) != 0)
{
if (bWithSubFolder)
{
// it's a directory - recurse into it
GetFilesList(Path.Combine(basePath, findData.fileName), mask, bWithSubFolder, bWithFolderName, ref list);
}
}
else
{
string filePath = (bWithFolderName ? Path.Combine(basePath, findData.fileName) : findData.fileName);
list.Add(filePath);
}
} while (FindNextFile(handle, findData));
// close this find handle
handle.Close();
}
}
#endregion
#region Methods
public IEnumerator<PathInfo> GetEnumerator()
{
return new FilesListEnumerator(this.mBasePath, this.mMask, this.mWithSubFolder);
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
#endregion
#region Nested Types
#region FilesListEnumerator Class
public class FilesListEnumerator : IEnumerator<PathInfo>
{
#region Variables
private string mBasePath = null;
private string mMask = null;
private bool mWithSubFolder = false;
private string mCurrentPath = null;
private SafeFileHandle mHandle = null;
private PathInfo mCurrent = null;
private Queue<string> mQueue = null;
#endregion
#region Constructor
public FilesListEnumerator(string basePath, string mask, bool bWithSubFolder)
{
if (string.IsNullOrEmpty(basePath))
{
throw new ArgumentNullException("basePath");
}
this.mBasePath = basePath;
this.mMask = string.IsNullOrEmpty(mask) ? "*" : mask;
this.mWithSubFolder = bWithSubFolder;
this.mQueue = new Queue<string>();
this.mCurrentPath = this.mBasePath;
}
#endregion
#region Methods
public void Dispose()
{
if (this.mHandle != null)
{
this.mHandle.Close();
this.mHandle = null;
}
}
public bool MoveNext()
{
if (string.IsNullOrEmpty(this.mCurrentPath)) return false;
new FileIOPermission(FileIOPermissionAccess.PathDiscovery, Path.Combine(this.mCurrentPath, ".")).Demand();
bool result = false;
WIN32_FIND_DATA findData = new WIN32_FIND_DATA();
if (this.mHandle == null)
{
SafeFileHandle handle = FindFirstFile(Path.Combine(this.mCurrentPath, this.mMask), findData);
if ((handle != null) && (!handle.IsInvalid))
{
result = true;
while (findData.fileName.Equals(@".") || findData.fileName.Equals(@".."))
{
result = FindNextFile(handle, findData);
if (!result) break;
}
this.mHandle = handle;
}
}
else
{
result = FindNextFile(this.mHandle, findData);
}
if (result)
{
string filePath = Path.Combine(this.mCurrentPath, findData.fileName);
if ((findData.fileAttributes & (int)FileAttributes.Directory) != 0)
{
this.mQueue.Enqueue(filePath);
}
else
{
this.mCurrent = new PathInfo(filePath);
//System.Diagnostics.Trace.WriteLine(filePath);
}
}
else
{
if (this.mHandle != null)
{
this.mHandle.Close();
this.mHandle = null;
}
if (this.mQueue.Count > 0)
{
this.mCurrentPath = this.mQueue.Dequeue();
result = this.MoveNext();
}
}
return result;
}
public void Reset()
{
this.mQueue.Clear();
if (this.mHandle != null)
{
this.mHandle.Close();
this.mHandle = null;
}
this.mCurrent = null;
this.mCurrentPath = this.mBasePath;
}
#endregion
#region Properties
public PathInfo Current
{
get { return this.mCurrent; }
}
object System.Collections.IEnumerator.Current
{
get { return this.Current; }
}
#endregion
}
#endregion
#region WIN32_FIND_DATA Class
/// <summary>
/// Structure that maps to WIN32_FIND_DATA
/// </summary>
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto), BestFitMapping(false)]
internal sealed class WIN32_FIND_DATA
{
public int fileAttributes;
public uint creationTime_lowDateTime;
public uint creationTime_highDateTime;
public uint lastAccessTime_lowDateTime;
public uint lastAccessTime_highDateTime;
public uint lastWriteTime_lowDateTime;
public uint lastWriteTime_highDateTime;
public uint nFileSizeHigh;
public uint nFileSizeLow;
public int dwReserved0;
public int dwReserved1;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
public string fileName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
public string alternateFileName;
}
#endregion
#region SafeFileHandle Class
/// <summary>
/// SafeHandle class for holding find handles
/// </summary>
private sealed class SafeFileHandle : Microsoft.Win32.SafeHandles.SafeHandleMinusOneIsInvalid
{
/// <summary>
/// Constructor
/// </summary>
public SafeFileHandle()
: base(true)
{
}
/// <summary>
/// Release the find handle
/// </summary>
/// <returns>true if the handle was released</returns>
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
protected override bool ReleaseHandle()
{
return FindClose(handle);
}
}
#endregion
#endregion
}
#endregion
#region PathInfo Class
public class PathInfo
{
#region API Methods
[DllImport("shell32.dll", CharSet = CharSet.Auto)]
private static extern int SHGetFileInfo(string pszPath, uint dwFileAttributes, ref SHFILEINFO psfi, uint cbFileInfo, uint uFlags);
#endregion
#region Constant
private const uint SHGFI_DISPLAYNAME = 0x200;
private const uint SHGFI_ICON = 0x100;
private const uint SHGFI_LINKOVERLAY = 0x8000;
private const uint SHGFI_SELECTED = 0x10000;
private const uint SHGFI_SYSICONINDEX = 0x4000;
private const uint SHGFI_TYPENAME = 0x400;
#endregion
#region Variables
private string mFilePath = "";
private bool mLargeIcon = false;
private bool mLinkOverlay = false;
private bool mSelected = false;
private DateTime mCreationTime = DateTime.Now;
private DateTime mLastAccesTime = DateTime.Now;
private DateTime mLastWriteTime = DateTime.Now;
private long mLength = 0L;
private FileAttributes mAttributes = FileAttributes.Normal;
private string mFileName = null;
private string mAlternateFileName = null;
#endregion
#region Constructor
public PathInfo()
{
}
public PathInfo(string filePath)
: this()
{
this.mFilePath = filePath;
if (!string.IsNullOrEmpty(filePath))
{
FileInfo fileInfo = new FileInfo(filePath);
this.mFileName = fileInfo.Name;
this.mAttributes = fileInfo.Attributes;
this.mCreationTime = fileInfo.CreationTime;
this.mLastAccesTime = fileInfo.LastAccessTime;
this.mLastWriteTime = fileInfo.LastWriteTime;
this.mLength = fileInfo.Length;
}
}
internal PathInfo(string filePath, FilesList.WIN32_FIND_DATA findData)
{
this.mFilePath = filePath;
if (findData != null)
{
this.mAttributes = (FileAttributes)findData.fileAttributes;
this.mCreationTime = ConvertDateTime(findData.creationTime_highDateTime, findData.creationTime_lowDateTime);
this.mLastAccesTime = ConvertDateTime(findData.lastAccessTime_highDateTime, findData.lastAccessTime_lowDateTime);
this.mLastWriteTime = ConvertDateTime(findData.lastWriteTime_highDateTime, findData.lastWriteTime_lowDateTime);
this.mLength = CombineHighLowInts(findData.nFileSizeHigh, findData.nFileSizeLow);
this.mAlternateFileName = findData.alternateFileName;
}
}
#endregion
#region Methods
public override bool Equals(object obj)
{
if (!string.IsNullOrEmpty(this.mFilePath))
{
if (obj is string)
{
return ((string)obj).Equals(this.mFilePath);
}
else if (obj is PathInfo)
{
PathInfo other = (PathInfo)obj;
return this.mFilePath.Equals(other.mFilePath);
}
}
return base.Equals(obj);
}
public override int GetHashCode()
{
if (!string.IsNullOrEmpty(this.mFilePath))
return this.mFilePath.GetHashCode();
return base.GetHashCode();
}
public override string ToString()
{
if (!string.IsNullOrEmpty(this.mFilePath))
return this.mFilePath;
return base.ToString();
}
private static long CombineHighLowInts(uint high, uint low)
{
return (((long)high) << 0x20) | low;
}
private static DateTime ConvertDateTime(uint high, uint low)
{
long fileTime = CombineHighLowInts(high, low);
return DateTime.FromFileTimeUtc(fileTime).ToLocalTime();
}
#endregion
#region Properties
/// <summary>
/// Contains display name of FileName.
/// </summary>
public string DisplayName
{
get
{
if (!string.IsNullOrEmpty(this.mFilePath))
{
SHFILEINFO psfi = new SHFILEINFO();
if (SHGetFileInfo(this.mFilePath, 0, ref psfi, (uint)Marshal.SizeOf(psfi), (uint)SHGFI_DISPLAYNAME) > 0)
{
return psfi.szDisplayName;
}
}
return "";
}
}
public string FileName
{
get { return this.mFileName; }
}
public string AlternateFileName
{
get { return this.mAlternateFileName; }
}
/// <summary>
/// Defines file name or path, for which an icon extracts.
/// </summary>
public string FilePath
{
get
{
return this.mFilePath;
}
}
/// <summary>
/// Contains an icon associated with FileName.
/// </summary>
public System.Drawing.Icon Icon
{
get
{
if (!string.IsNullOrEmpty(this.mFilePath))
{
SHFILEINFO psfi = new SHFILEINFO();
uint uFlags = (uint)SHGFI_ICON;
uFlags = this.mLargeIcon ? uFlags : uFlags;
uFlags = this.mLinkOverlay ? (uFlags | (uint)SHGFI_LINKOVERLAY) : uFlags;
uFlags = this.mSelected ? (uFlags | (uint)SHGFI_SELECTED) : uFlags;
if (SHGetFileInfo(this.mFilePath, 0, ref psfi, (uint)Marshal.SizeOf(psfi), uFlags) > 0)
{
return System.Drawing.Icon.FromHandle(new IntPtr(psfi.hIcon));
}
}
return null;
}
}
/// <summary>
/// Get the icon with link overlay.
/// </summary>
public System.Drawing.Icon LinkOverlayIcon
{
get
{
if (!string.IsNullOrEmpty(this.mFilePath))
{
SHFILEINFO psfi = new SHFILEINFO();
uint uFlags = (uint)SHGFI_ICON | (uint)SHGFI_LINKOVERLAY;
if (SHGetFileInfo(this.mFilePath, 0, ref psfi, (uint)Marshal.SizeOf(psfi), uFlags) > 0)
{
return System.Drawing.Icon.FromHandle(new IntPtr(psfi.hIcon));
}
}
return null;
}
}
/// <summary>
/// Get the selected icon.
/// </summary>
public System.Drawing.Icon SelectedIcon
{
get
{
if (!string.IsNullOrEmpty(this.mFilePath))
{
SHFILEINFO psfi = new SHFILEINFO();
uint uFlags = (uint)SHGFI_ICON | (uint)SHGFI_SELECTED;
if (SHGetFileInfo(this.mFilePath, 0, ref psfi, (uint)Marshal.SizeOf(psfi), uFlags) > 0)
{
return System.Drawing.Icon.FromHandle(new IntPtr(psfi.hIcon));
}
}
return null;
}
}
/// <summary>
/// Contains system icon index of FileName.
/// </summary>
public int SystemIconIndex
{
get
{
if (!string.IsNullOrEmpty(this.mFilePath))
{
SHFILEINFO psfi = new SHFILEINFO();
if (SHGetFileInfo(this.mFilePath, 0, ref psfi, (uint)Marshal.SizeOf(psfi), (uint)SHGFI_SYSICONINDEX) > 0)
{
return psfi.iIcon;
}
}
return -1;
}
}
/// <summary>
/// Contains type name of FileName.
/// </summary>
public string TypeName
{
get
{
if (!string.IsNullOrEmpty(this.mFilePath))
{
SHFILEINFO psfi = new SHFILEINFO();
if (SHGetFileInfo(this.mFilePath, 0, ref psfi, (uint)Marshal.SizeOf(psfi), (uint)SHGFI_TYPENAME) > 0)
{
return psfi.szTypeName;
}
}
return "";
}
}
public FileAttributes Attributes
{
get { return this.mAttributes; }
}
public DateTime CreationTime
{
get { return this.mCreationTime; }
}
public DateTime LastAccesTime
{
get { return this.mLastAccesTime; }
}
public DateTime LastWriteTime
{
get { return this.mLastWriteTime; }
}
public long Length
{
get { return this.mLength; }
}
#endregion
#region SHFILEINFO Class
/// <summary>
/// Structure that maps to SHFILEINFO
/// </summary>
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
internal sealed class SHFILEINFO
{
public const int MAX_PATH = 260;
public int hIcon;
public int iIcon;
public uint dwAttributes;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
public string szDisplayName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
public string szTypeName;
}
#endregion
}
#endregion
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment