Click here to Skip to main content
15,889,877 members
Articles / Programming Languages / C#
Article

My Explorer In C#

Rate me:
Please Sign up or sign in to vote.
4.84/5 (65 votes)
26 Aug 20023 min read 500.7K   29.5K   264   42
An article on creating a simple Window Explorer using C# with out Interop.

Sample Image - My_Explorer.gif

Introduction

This article shows how to get system drives information using System.Managementnamespace and use Sysetm.IO namespace to get directories and files information to populate TreeView and ListView controls.

Getting Started

First we need to gather information on all the drives my computer have access to, and display the name and type of drive in the TreeView control. We can query the System.Management namespace to access drive information using the ManagementObjectSearcher class. It accepts a SQL like query as a parameter and returns a ManagementOjbectCollection class containing the drive information we requested. We now have all the drives information at our disposal (such as drive name, type, volume, description, etc...).

C#
//This procedure populate the TreeView with the Drive list 
private void PopulateDriveList() 
{ 
    TreeNode nodeTreeNode; 
    int imageIndex = 0; 
    int selectIndex = 0; 
    
    const int Removable = 2; 
    const int LocalDisk = 3; 
    const int Network = 4; 
    const int CD = 5; 
    //const int RAMDrive = 6; 
    
    this.Cursor = Cursors.WaitCursor; 
    
    //clear TreeView 
    tvFolders.Nodes.Clear(); 
    nodeTreeNode = new TreeNode("My Computer",0,0); 
    tvFolders.Nodes.Add(nodeTreeNode); 
    
    //set node collection 
    TreeNodeCollection nodeCollection = nodeTreeNode.Nodes; 
    
    //Get Drive list 
    ManagementObjectCollection queryCollection = getDrives(); 
    foreach ( ManagementObject mo in queryCollection) 
    { 
        switch (int.Parse( mo["DriveType"].ToString())) 
        { 
            case Removable: //removable drives 
                imageIndex = 5; 
                selectIndex = 5; 
                break; 
            case LocalDisk: //Local drives 
                imageIndex = 6; 
                selectIndex = 6; 
                break; 
            case CD: //CD rom drives 
                imageIndex = 7; 
                selectIndex = 7; 
                break; 
            case Network: //Network drives 
                imageIndex = 8; 
                selectIndex = 8; 
                break; 
            default: //defalut to folder 
                imageIndex = 2; 
                selectIndex = 3; 
                break; 
        } 
        
        //create new drive node
        nodeTreeNode = new TreeNode(mo["Name"].ToString() 
            + "\\" ,imageIndex,selectIndex); 
        
        //add new node 
        nodeCollection.Add(nodeTreeNode); 
    } 
    
    //Init files ListView 
    InitListView();
    
    this.Cursor = Cursors.Default; 
} 
protected ManagementObjectCollection getDrives()
{ 
    //get drive collection 
    ManagementObjectSearcher query = new 
        ManagementObjectSearcher("SELECT * From Win32_LogicalDisk "); 
    ManagementObjectCollection queryCollection = query.Get(); 
    return queryCollection; 
} 

Directories and Files

When we click on a drive or a directory in the TreeView, we need to check if the drive or directory exists, before proceeding any further. Now we can get the directories for the current selection in the TreeView by using the Directory class from the System.IO namespace. Calling the Directory.GetDirectories method with the current node path as the parameter, will return an array of directories. We can loop through the directories array to populate sub-nodes under the current selected node. To get the currently selected node's files, we need to call the Directory.GetFiles method with the current node path as the parameter. This will return an array of files for the selected drive or directory. Now we can populate the ListView with the file array by looping through each array element and call FileInfo class to get the file size, creation date, and modified date.

C#
protected void PopulateDirectory(TreeNode nodeCurrent, 
    TreeNodeCollection nodeCurrentCollection) 
{ 
    TreeNode nodeDir; 
    int imageIndex = 2; 
    int selectIndex = 3;
    
    if (nodeCurrent.SelectedImageIndex != 0) 
    {    //populate treeview with folders 
        try 
        { 
            if(Directory.Exists(getFullPath(nodeCurrent.FullPath)) 
                == false) 
            { 
                MessageBox.Show("Directory or path " + 
                    nodeCurrent.ToString() + " does not exist."); 
            } 
            else 
            {    //populate files 
                PopulateFiles(nodeCurrent);
                
                string[] stringDirectories = 
                    Directory.GetDirectories(getFullPath
                        (nodeCurrent.FullPath)); 
                
                string stringFullPath = ""; 
                string stringPathName = ""; 
                
                foreach (string stringDir in stringDirectories) 
                { 
                    stringFullPath = stringDir; 
                    stringPathName = GetPathName(stringFullPath); 
                    
                    //create node for directories 
                    nodeDir = new TreeNode(stringPathName.ToString(),
                        imageIndex,selectIndex); 
            
                    nodeCurrentCollection.Add(nodeDir); 
                } 
            } 
        } 
        catch (IOException e) 
        { 
            MessageBox.Show("Error: 
                Drive not ready or directory does not exist."); 
        } 
        catch (UnauthorizedAccessException e) 
        { 
            MessageBox.Show("Error: 
                Drive or directory access denided."); 
        } 
        catch (Exception e) 
        { 
            MessageBox.Show("Error: " + e); 
        } 
    } 
} 

protected string GetPathName(string stringPath) 
{ 
    //Get Name of folder 
    string[] stringSplit = stringPath.Split('\\'); 
    
    int _maxIndex = stringSplit.Length; 
    
    return stringSplit[_maxIndex-1]; 
} 

protected void PopulateFiles(TreeNode nodeCurrent)
{
    //Populate listview with files
    string[] lvData =  new string[4];
    
    //clear list
    InitListView();

    if (nodeCurrent.SelectedImageIndex != 0) 
    {
        //check path
        if(Directory.Exists((string) 
            getFullPath(nodeCurrent.FullPath)) == false)
        {
            MessageBox.Show("Directory or path " + 
                nodeCurrent.ToString() + " does not exist.");
        }
        else
        {
            try
            {
                string[] stringFiles = Directory.GetFiles
                    (getFullPath(nodeCurrent.FullPath));
                string stringFileName = "";
                DateTime dtCreateDate, dtModifyDate;
                Int64 lFileSize = 0;

                //loop throught all files
                foreach (string stringFile in stringFiles)
                {
                    stringFileName = stringFile;
                    FileInfo objFileSize = new 
                        FileInfo(stringFileName);
                    lFileSize = objFileSize.Length;
                    //GetCreationTime(stringFileName);
                    dtCreateDate = objFileSize.CreationTime; 
                    //GetLastWriteTime(stringFileName);
                    dtModifyDate = objFileSize.LastWriteTime; 

                    //create listview data
                    lvData[0] = GetPathName(stringFileName);
                    lvData[1] = formatSize(lFileSize);
                            
                    //check if file is in local current 
                    //day light saving time
                    if (TimeZone.CurrentTimeZone.
                        IsDaylightSavingTime(dtCreateDate) == false)
                    {
                        //not in day light saving time adjust time
                        lvData[2] = formatDate(dtCreateDate.AddHours(1));
                    }
                    else
                    {
                        //is in day light saving time adjust time
                        lvData[2] = formatDate(dtCreateDate);
                    }

                    //check if file is in local current day 
                    //light saving time
                    if (TimeZone.CurrentTimeZone.
                        IsDaylightSavingTime(dtModifyDate) == false)
                    {
                        //not in day light saving time adjust time
                        lvData[3] = formatDate(dtModifyDate.AddHours(1));
                    }
                    else{
                        //not in day light saving time adjust time
                        lvData[3] = formatDate(dtModifyDate);
                    }

                    //Create actual list item
                    ListViewItem lvItem = new ListViewItem(lvData,0);
                    lvFiles.Items.Add(lvItem);
                }
            }
            catch (IOException e)
            {
                MessageBox.Show("Error: 
                   Drive not ready or directory does not exist.");
            }
            catch (UnauthorizedAccessException e)
            {
                MessageBox.Show("Error: 
                   Drive or directory access denided.");
            }
            catch (Exception e)
            {
                MessageBox.Show("Error: " + e);
            }
        }
    }
}

protected string getFullPath(string stringPath) 
{ 
    //Get Full path string 
    stringParse = ""; 
    
    //remove My Computer from path. 
    stringParse = stringPath.Replace("My Computer\\", ""); 
    
    return stringParse; 
} 

protected string formatDate(DateTime dtDate) 
{ 
    //Get date and time in short format 
    string stringDate = ""; 
    stringDate = dtDate.ToShortDateString().ToString() 
        + " " + dtDate.ToShortTimeString().ToString();
    
    return stringDate; 
} 

protected string formatSize(Int64 lSize) 
{
    //Format number to KB 
    string stringSize = ""; 
    NumberFormatInfo myNfi = new NumberFormatInfo();
    Int64 lKBSize = 0; 
    
    if (lSize < 1024 ) 
    { 
        if (lSize == 0) 
        { 
            //zero byte 
            stringSize = "0"; 
        } 
        else 
        { 
            //less than 1K but not zero byte 
            stringSize = "1"; 
        } 
    } 
    else 
    { 
        //convert to KB 
        lKBSize = lSize / 1024; 
        
        //format number with default format 
        stringSize = lKBSize.ToString("n",myNfi); 
        
        //remove decimal 
        stringSize = stringSize.Replace(".00", ""); 
    } 
    
    return stringSize + " KB"; 
}

Formating Numbers

Instead of writing string parsing functions to format the file size with comma in the thousand and millionth position, I use the NumberFormatInfo class in System.Globalization namespace to format the number, when I convert the number to the string format.

C#
protected string formatSize(Int64 lSize) 
{ 
    //Format number to KB 
    string stringSize = ""; 
    NumberFormatInfo myNfi = new NumberFormatInfo(); 
    Int64 lKBSize = 0; 
    
    if (lSize < 1024 ) 
    { 
        :
        :
    } 
    else 
    { 
        //convert to KB 
        lKBSize = lSize / 1024; 
        
        //format number with default format 
        stringSize = lKBSize.ToString("n",myNfi); 
        
        //remove decimal 
        stringSize = stringSize.Replace(".00", ""); 
    } 
    
    return stringSize + " KB"; 
} 

Day Light Saving Time

At first glance, it looks like

C#
FileInfo objFileSize = new FileInfo(stringFileName)

will give you all the correct information about the file to display on the screen. But it turns out that the file date time may not be correct due to Day Light Saving Time settings on your machine and how the file was saved. The files that does not have the Day Light Saving Time set to true will have the create, modify, and access time off by one hour. We need to check for this condition using the function TimeZone.CurrentTimeZone.IsDaylightSavingTime(dtCreateDate). This function returns a Boolean, true if the file Day Light Saving Time was set and returns a false if it was not set. Then we can adjust the time for those files that does not have the Day Light Saving Time setting set, by adding one hour to the file time.

C#
protected void PopulateFiles(TreeNode nodeCurrent)
{
    //Populate listview with files
    string[] lvData =  new string[4];
    
    //clear list
    InitListView();

    if (nodeCurrent.SelectedImageIndex != 0) 
    {
        //check path
        if(Directory.Exists((string) 
            getFullPath(nodeCurrent.FullPath)) == false)
        {
            MessageBox.Show("Directory or path " + 
                nodeCurrent.ToString() + " does not exist.");
        }
        else
        {
            try
            {
                string[] stringFiles = Directory.
                    GetFiles(getFullPath(nodeCurrent.FullPath));
                string stringFileName = "";
                DateTime dtCreateDate, dtModifyDate;
                Int64 lFileSize = 0;

                //loop throught all files
                foreach (string stringFile in stringFiles)
                {
                    stringFileName = stringFile;
                    FileInfo objFileSize = new FileInfo(stringFileName);
                    lFileSize = objFileSize.Length;
                    //GetCreationTime(stringFileName);
                    dtCreateDate = objFileSize.CreationTime; 
                    //GetLastWriteTime(stringFileName);
                    dtModifyDate = objFileSize.LastWriteTime; 

                    //create listview data
                    lvData[0] = GetPathName(stringFileName);
                    lvData[1] = formatSize(lFileSize);
                            
                    //check if file is in local current 
                    //day light saving time
                    if (TimeZone.CurrentTimeZone.
                        IsDaylightSavingTime(dtCreateDate) == false)
                    {
                        //not in day light saving time adjust time
                        lvData[2] = formatDate(dtCreateDate.AddHours(1));
                    }
                    else
                    {
                        //is in day light saving time adjust time
                        lvData[2] = formatDate(dtCreateDate);
                    }

                    //check if file is in local current
                    //day light saving time
                    if (TimeZone.CurrentTimeZone.
                        IsDaylightSavingTime(dtModifyDate) == false)
                    {
                        //not in day light saving time adjust time
                        lvData[3] = formatDate(dtModifyDate.AddHours(1));
                    }
                    else                                        {
                        //not in day light saving time adjust time
                        lvData[3] = formatDate(dtModifyDate);
                    }

                    //Create actual list item
                    ListViewItem lvItem = new ListViewItem(lvData,0);
                    lvFiles.Items.Add(lvItem);
                }
            }
            catch (IOException e)
            {
                MessageBox.Show("Error: 
                    Drive not ready or directory does not exist.");
            }
            catch (UnauthorizedAccessException e)
            {
                MessageBox.Show("Error: 
                    Drive or directory access denied.");
            }
            catch (Exception e)
            {
                MessageBox.Show("Error: " + e);
            }
        }
    }
}

Conclusion

We have used the System.Management namespace to get information on all the available drives in the system and used the Directory and FileInfo classes in the System.IO namespace to get information about directories and files. There are many other features available in the Directory and File classes we did not touch upon, like the ones for creating directory, deleting directory, creating file, copy file, move file, etc. Also with System.Management namespace, you could get access to management information about the system, devices, and application in the Windows Management Instrumentation (WMI) infrastructure. We can query for information such as how much space is left on the drive, what is the current CPU utilization and much more, using the classes in the System.Management namespace. You could find out more about these namespaces at http://msdn.microsoft.com.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Software Developer (Senior)
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
Generalimportant question Pin
lovemeok_5529-Sep-06 21:44
lovemeok_5529-Sep-06 21:44 
GeneralNeed more info about ManagementObjectSearcher Pin
bebangs20-Jul-06 17:51
bebangs20-Jul-06 17:51 
GeneralNo System.Management namespace Pin
Pacer Dawn19-Jan-06 11:59
Pacer Dawn19-Jan-06 11:59 
GeneralRe: No System.Management namespace Pin
Eric Seipp9-Jun-06 4:05
Eric Seipp9-Jun-06 4:05 
GeneralFile icons Pin
Judah Gabriel Himango16-Jan-06 9:16
sponsorJudah Gabriel Himango16-Jan-06 9:16 
GeneralRe: File icons Pin
Death_Child27-Jan-06 5:37
Death_Child27-Jan-06 5:37 
GeneralRe: File icons Pin
Judah Gabriel Himango27-Jan-06 6:36
sponsorJudah Gabriel Himango27-Jan-06 6:36 
GeneralRe: File icons [modified] Pin
Patrick Etc.3-Dec-06 14:21
Patrick Etc.3-Dec-06 14:21 
It's even simpler than this actually. The Windows Shell API has a flag that says "Treat this item as though it were a real file, even though it doesn't exist". What the shell will do then is take the file's extension and use that as the basis for determining what the icon should be.

(because remember, all icons are registered with the system - that's part of why Windows uses a file-extension based exe system in the first place [and ones that aren't only apply to applications, and that's why it sometimes takes a long time for the icon to appear for large files.. it has to be opened and windows has to find the icon for the exe, if it has one]).

So it's pretty easy to do. Here's the code I use in one of my VB.NET applications (sorry, for those of you who prefer C#; I use both languages pretty much equally, this code happens to be in VB but should be easy to translate):

Public Enum IconSize
    Small
    Large
End Enum

    <StructLayout(LayoutKind.Sequential)> _
    Public Structure SHFILEINFO
        Public hIcon As IntPtr
        Public iIcon As IntPtr
        Public dwAttributes As UInteger
        <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=260)> Public szDisplayName As String
        <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=80)> Public szTypeName As String
    End Structure

    Public Class Win32
        Public Const FILE_ATTRIBUTE_NORMAL As UInteger = &H80
        Public Const FILE_ATTRIBUTE_DIRECTORY As UInteger = &H10

        Public Const SHGFI_ICON As UInteger = &H100                ' get icon 
        Public Const SHGFI_LARGEICON As UInteger = &H0             ' get large icon 
        Public Const SHGFI_SMALLICON As UInteger = &H1             ' get small icon 

        Public Const SHGFI_USEFILEATTRIBUTES As UInteger = &H10    ' use passed dwFileAttribute 
        Public Const SHGFI_TYPENAME As UInteger = &H400            ' get type name 

        <DllImport("shell32.dll", EntryPoint:="SHGetFileInfo", CallingConvention:=CallingConvention.StdCall)> _
        Public Shared Function SHGetFileInfo(ByVal pszPath As String, _
                                             ByVal dwFileAttributes As UInteger, _
                                             ByRef psfi As SHFILEINFO, _
                                             ByVal cbSizeFileInfo As UInteger, _
                                             ByVal uFlags As UInteger) As IntPtr
        End Function

        <DllImport("User32.dll")> _
        Public Shared Function DestroyIcon(ByVal hIcon As IntPtr) As Integer
        End Function
    End Class

    Public Shared Function GetFileIcon(ByVal fileName As String, ByVal argSize As IconSize, _
                                       ByVal isDir As Boolean) As Icon
        Try
            Dim hImgSmall As IntPtr
            Dim shInfo As New SHFILEINFO
            Dim dwAttribs As UInteger = 0
            Dim uFlags As UInteger = Win32.SHGFI_ICON

            If argSize = IconSize.Small Then
                uFlags = uFlags Or Win32.SHGFI_SMALLICON
            Else
                uFlags = uFlags Or Win32.SHGFI_LARGEICON
            End If

            If Not Directory.Exists(fileName) AndAlso Not File.Exists(fileName) Then
                If isDir Then
                    dwAttribs = dwAttribs Or Win32.FILE_ATTRIBUTE_DIRECTORY
                Else
                    dwAttribs = dwAttribs Or Win32.FILE_ATTRIBUTE_NORMAL
                End If

                uFlags = uFlags Or Win32.SHGFI_USEFILEATTRIBUTES
            End If

            hImgSmall = Win32.SHGetFileInfo(fileName, dwAttribs, shInfo, Convert.ToUInt32(Marshal.SizeOf(shInfo)), uFlags)

            Return DirectCast(Icon.FromHandle(shInfo.hIcon).Clone(), Icon)
            Win32.DestroyIcon(shInfo.hIcon)

        Catch ex As Exception
            Return Nothing
        End Try
    End Function


The DestroyIcon call is very important; otherwise you get GDI+ exceptions after awhile if your program stays open long because of memory leaks.

Enjoy.
GeneralManagement libarary isn't working for me Pin
BC3Tech10-Nov-05 10:05
BC3Tech10-Nov-05 10:05 
Generalgetting drive list Pin
Robert Billing14-Aug-05 0:43
Robert Billing14-Aug-05 0:43 
GeneralRe: getting drive list Pin
Ashok Dhamija31-Dec-05 5:15
Ashok Dhamija31-Dec-05 5:15 
GeneralRe: getting drive list Pin
Faldegast20-Jun-06 3:34
Faldegast20-Jun-06 3:34 
GeneralNetworkable Pin
Heath Stewart19-Jun-03 3:28
protectorHeath Stewart19-Jun-03 3:28 
GeneralRe: Networkable Pin
isglass2-Nov-04 23:08
isglass2-Nov-04 23:08 
GeneralRe: Networkable Pin
Heath Stewart3-Nov-04 4:05
protectorHeath Stewart3-Nov-04 4:05 
GeneralCrystal clear example Pin
David Furshpan10-Oct-02 12:58
David Furshpan10-Oct-02 12:58 
GeneralVery nice example. Pin
Gevik Babakhani30-Aug-02 0:48
Gevik Babakhani30-Aug-02 0:48 
GeneralGood job Pin
Mazdak27-Aug-02 5:22
Mazdak27-Aug-02 5:22 
GeneralRe: Good job Pin
ThatsAlok17-Oct-07 20:49
ThatsAlok17-Oct-07 20:49 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.