using System;
using System.IO;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace News2News.XProjects.ListOfDrives
{
public enum DriveEventType
{
Disconnected = 0,
Connected = 1
}
public partial class ListOfDrivesControl : UserControl
{
const uint SHGFI_SYSICONINDEX = 0x000004000;
const uint SHGFI_LARGEICON = 0;
const uint SHGFI_SMALLICON = 0x000000001;
const uint SHGFI_ICON = 0x000000100;
const uint SHGFI_TYPENAME = 0x000000400;
const uint SHGFI_USEFILEATTRIBUTES = 0x000000400;
const int LVIF_IMAGE = 0x0002;
const int LVSIL_NORMAL = 0;
const int LVSIL_SMALL = 0x0001;
const int LVM_FIRST = 0x1000;
const int LVM_GETIMAGELIST = (LVM_FIRST + 2);
const int LVM_SETIMAGELIST = (LVM_FIRST + 3);
const int LVM_SETITEM = (LVM_FIRST + 6);
const int LVS_SHAREIMAGELISTS = 0x0040;
const int GWL_STYLE = -16;
const int FILE_ATTRIBUTE_NORMAL = 0x00000080;
const int DBT_DEVICEARRIVAL = 0x8000;
const int DBT_DEVICEREMOVECOMPLETE = 0x8004;
const int DBT_DEVTYP_VOLUME = 0x0002;
public delegate void DriveEventHandler(object sender,
DriveEventArgs e);
public delegate void ListPopulatedHandler(object sender,
EventArgs e);
public delegate void ListPopulatingHandler(object sender,
EventArgs e);
static class NativeMethods
{
[StructLayout(LayoutKind.Sequential,
CharSet = CharSet.Auto)]
internal struct SHFILEINFO
{
internal IntPtr hIcon;
internal int iIcon;
internal uint dwAttributes;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
internal string szDisplayName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
internal string szTypeName;
};
[StructLayout(LayoutKind.Sequential)]
internal struct LVITEM
{
internal int mask;
internal int iItem;
internal int iSubItem;
internal int state;
internal int stateMask;
internal IntPtr pszText;
internal int cchTextMax;
internal int iImage;
internal IntPtr lParam;
internal int iIndent;
internal int iGroupId;
internal int cColumns;
internal IntPtr puColumns;
}
[DllImport("user32.dll")]
internal static extern int GetWindowLong(
IntPtr hWnd, int nIndex);
[DllImport("user32.dll")]
internal static extern int SetWindowLong(
IntPtr hWnd, int nIndex, int dwNewLong);
[DllImport("user32.dll", EntryPoint = "SendMessage",
CharSet = CharSet.Auto)]
internal static extern IntPtr SendMessage(
IntPtr hWnd, UInt32 Msg,
IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", EntryPoint = "SendMessage",
CharSet = CharSet.Auto)]
internal static extern IntPtr
SendMessage_SetItemIcon(
IntPtr hWnd, UInt32 Msg,
IntPtr wParam, ref LVITEM lParam);
[DllImport("user32.dll")]
internal static extern bool
DestroyIcon(IntPtr hIcon);
[DllImport("shell32.dll", EntryPoint = "SHGetFileInfoW",
CharSet = CharSet.Unicode)]
internal static extern IntPtr SHGetFileInfo(
string pszPath, uint dwFileAttributes,
ref SHFILEINFO psfi, uint cbFileInfo,
uint uFlags);
}
class DriveListItem : ListViewItem
{
NativeMethods.SHFILEINFO shFileInfo;
int IconMode = 0; //0=small, 1=large
public DriveListItem(DriveInfo d, int iconMode)
{
IconMode = iconMode;
GetFileTypeInfo(d.RootDirectory.Name,
FILE_ATTRIBUTE_NORMAL);
string volumeLabel = "(" + d.RootDirectory.Name + ")";
string volumeDescription = shFileInfo.szTypeName;
string volumeSize = "";
if (d.IsReady)
{
volumeLabel = d.VolumeLabel + " " + volumeLabel;
if (d.TotalSize > 0)
{
volumeSize =
((float)d.TotalFreeSpace /
0x40000000).ToString("F2") +
" GB free of " +
((float)d.TotalSize /
0x40000000).ToString("F2") +
" GB";
}
}
this.Text = volumeLabel;
this.SubItems.Add(
new ListViewSubItem(null, volumeDescription));
this.SubItems.Add(
new ListViewSubItem(null, volumeSize));
}
private void GetFileTypeInfo(string path,
uint attributes)
{
uint flags = (SHGFI_SYSICONINDEX | SHGFI_ICON |
SHGFI_TYPENAME | SHGFI_USEFILEATTRIBUTES);
flags |= (IconMode == 0 ?
SHGFI_SMALLICON : SHGFI_LARGEICON);
shFileInfo = new NativeMethods.SHFILEINFO();
NativeMethods.SHGetFileInfo(path, (uint)attributes,
ref shFileInfo,
(uint)Marshal.SizeOf(shFileInfo),
flags);
if (shFileInfo.hIcon != IntPtr.Zero)
{
NativeMethods.DestroyIcon(shFileInfo.hIcon);
}
}
internal void SetItemIcon(IntPtr listViewHwnd,
int listItemIndex)
{
NativeMethods.LVITEM lvitem =
new NativeMethods.LVITEM();
lvitem.mask = LVIF_IMAGE;
lvitem.iItem = listItemIndex;
lvitem.iImage = shFileInfo.iIcon;
NativeMethods.SendMessage_SetItemIcon(listViewHwnd,
LVM_SETITEM, IntPtr.Zero, ref lvitem);
}
}
[StructLayout(LayoutKind.Sequential)]
internal struct DEV_BROADCAST_VOLUME
{
internal uint dbcv_size;
internal uint dbcv_devicetype;
internal uint dbcv_reserved;
internal uint dbcv_unitmask;
internal ushort dbcv_flags;
}
int iconMode = 1;
public event DriveEventHandler DriveEvent;
public event ListPopulatedHandler ListPopulated;
public event ListPopulatingHandler ListPopulating;
delegate void AddListItemDelegate(DriveListItem item);
AddListItemDelegate AddListItem;
public int IconMode
{
get { return iconMode; }
set
{
if (iconMode != value)
{
iconMode = value;
PopulateList();
}
}
}
public ListOfDrivesControl()
{
InitializeComponent();
AddListItem = new AddListItemDelegate(AddListItemMethod);
SwitchToSystemList();
PopulateList();
}
void PopulateList()
{
if (ListPopulating != null) ListPopulating(this, null);
listView1.Items.Clear();
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork +=
new DoWorkEventHandler(PopulateListOnBackground);
worker.RunWorkerCompleted +=
new RunWorkerCompletedEventHandler(OnListPopulated);
worker.RunWorkerAsync();
}
void OnListPopulated(object sender,
RunWorkerCompletedEventArgs e)
{
if (ListPopulated != null) ListPopulated(this, null);
}
void AddListItemMethod(DriveListItem item)
{
listView1.Items.Add(item);
item.SetItemIcon(listView1.Handle, item.Index);
}
void PopulateListOnBackground(object sender, DoWorkEventArgs e)
{
foreach (DriveInfo d in DriveInfo.GetDrives())
{
DriveListItem item = new DriveListItem(d, IconMode);
this.Invoke(AddListItem, new object[] { item });
}
}
private void SwitchToSystemList()
{
if (NativeMethods.SendMessage(listView1.Handle,
LVM_GETIMAGELIST, new IntPtr(LVSIL_SMALL),
IntPtr.Zero) != IntPtr.Zero)
{
//the list is already switched
return;
}
int wStyle = (LVS_SHAREIMAGELISTS |
NativeMethods.GetWindowLong(listView1.Handle,
GWL_STYLE));
NativeMethods.SetWindowLong(
listView1.Handle, GWL_STYLE, wStyle);
NativeMethods.SHFILEINFO info =
new NativeMethods.SHFILEINFO();
uint flags = (SHGFI_SYSICONINDEX | SHGFI_ICON |
SHGFI_TYPENAME | SHGFI_USEFILEATTRIBUTES);
flags |= (IconMode == 0 ? SHGFI_SMALLICON : SHGFI_LARGEICON);
//obtaining handle to a system list
IntPtr hSysimageList = NativeMethods.SHGetFileInfo("",
FILE_ATTRIBUTE_NORMAL, ref info,
(uint)Marshal.SizeOf(info), flags);
//assigning the system list
//to the ListView control
NativeMethods.SendMessage(listView1.Handle,
LVM_SETIMAGELIST, new IntPtr(LVSIL_SMALL),
hSysimageList);
}
public void OnDeviceEvent(ref Message m)
{
if ((m.WParam == (IntPtr)DBT_DEVICEARRIVAL)
|| (m.WParam == (IntPtr)DBT_DEVICEREMOVECOMPLETE))
{
DEV_BROADCAST_VOLUME volume = (DEV_BROADCAST_VOLUME)
Marshal.PtrToStructure(m.LParam,
typeof(DEV_BROADCAST_VOLUME));
if (volume.dbcv_devicetype == DBT_DEVTYP_VOLUME)
{
PopulateList();
if (DriveEvent == null) return;
for (int i = 0; i < 26; i++)
{
if ((volume.dbcv_unitmask & (1 << i)) != 0)
{
DriveEventType eventType =
m.WParam == (IntPtr)DBT_DEVICEARRIVAL
? DriveEventType.Connected
: DriveEventType.Disconnected;
string root = (char)(i + 65) + ":\\";
DriveEvent(this,
new DriveEventArgs(root, eventType));
break;
}
}
}
}
}
}
public class DriveEventArgs : EventArgs
{
public string RootDirectoryName = "";
public DriveEventType EventType;
public DriveEventArgs(string root, DriveEventType eventType)
{
RootDirectoryName = root;
EventType = eventType;
}
}
}
|